github.com/go-oss/image@v0.1.1-0.20230517025328-001b78555e78/jpeg/quality.go (about) 1 // Copyright 2020 Takenori Nakagawa. 2 // MIT License 3 4 package jpeg 5 6 import ( 7 "image" 8 "io" 9 _ "unsafe" // for go:linkname 10 ) 11 12 func isZero(arr [blockSize]int32) bool { 13 var zero [blockSize]int32 14 return arr == zero 15 } 16 17 // quality calculates Quality from DQT. 18 // ref: https://github.com/ImageMagick/ImageMagick/blob/7.0.7.7/coders/jpeg.c#L794-L927 19 // see LICENSE-imagemagick. 20 func (d *decoder) quality() int32 { 21 var quality, qvalue, sum int32 22 var i, j int 23 24 for i = range d.quant { 25 for j = 0; j < blockSize; j++ { 26 sum += d.quant[i][j] 27 } 28 } 29 30 if !isZero(d.quant[0]) && !isZero(d.quant[1]) { 31 hash := [101]int32{ 32 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645, 33 632, 623, 613, 607, 600, 594, 589, 585, 581, 571, 34 555, 542, 529, 514, 494, 474, 457, 439, 424, 410, 35 397, 386, 373, 364, 351, 341, 334, 324, 317, 309, 36 299, 294, 287, 279, 274, 267, 262, 257, 251, 247, 37 243, 237, 232, 227, 222, 217, 213, 207, 202, 198, 38 192, 188, 183, 177, 173, 168, 163, 157, 153, 148, 39 143, 139, 132, 128, 125, 119, 115, 108, 104, 99, 40 94, 90, 84, 79, 74, 70, 64, 59, 55, 49, 41 45, 40, 34, 30, 25, 20, 15, 11, 6, 4, 42 0, 43 } 44 sums := [101]int32{ 45 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104, 46 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946, 47 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998, 48 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702, 49 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208, 50 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458, 51 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788, 52 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128, 53 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509, 54 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846, 55 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201, 56 128, 0, 57 } 58 59 qvalue = d.quant[0][2] + d.quant[0][53] + d.quant[1][0] + d.quant[1][blockSize-1] 60 for i = 0; i < 100; i++ { 61 if (qvalue < hash[i]) && (sum < sums[i]) { 62 continue 63 } 64 if ((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50) { 65 quality = int32(i + 1) 66 } 67 break 68 } 69 } else if !isZero(d.quant[0]) { 70 hash := [101]int32{ 71 510, 505, 422, 380, 355, 338, 326, 318, 311, 305, 72 300, 297, 293, 291, 288, 286, 284, 283, 281, 280, 73 279, 278, 277, 273, 262, 251, 243, 233, 225, 218, 74 211, 205, 198, 193, 186, 181, 177, 172, 168, 164, 75 158, 156, 152, 148, 145, 142, 139, 136, 133, 131, 76 129, 126, 123, 120, 118, 115, 113, 110, 107, 105, 77 102, 100, 97, 94, 92, 89, 87, 83, 81, 79, 78 76, 74, 70, 68, 66, 63, 61, 57, 55, 52, 79 50, 48, 44, 42, 39, 37, 34, 31, 29, 26, 80 24, 21, 18, 16, 13, 11, 8, 6, 3, 2, 81 0, 82 } 83 sums := [101]int32{ 84 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859, 85 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679, 86 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823, 87 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086, 88 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092, 89 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396, 90 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727, 91 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068, 92 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398, 93 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736, 94 667, 592, 518, 441, 369, 292, 221, 151, 86, 95 64, 0, 96 } 97 98 qvalue = d.quant[0][2] + d.quant[0][53] 99 for i = 0; i < 100; i++ { 100 if (qvalue < hash[i]) && (sum < sums[i]) { 101 continue 102 } 103 if ((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50) { 104 quality = int32(i + 1) 105 } 106 break 107 } 108 } 109 110 return quality 111 } 112 113 // DecodeWithQuality reads a JPEG image from r and returns it as an image.Image and Quality. 114 func DecodeWithQuality(r io.Reader) (image.Image, int, error) { 115 var d decoder 116 img, err := d.decode(r, false) 117 if err != nil { 118 return img, 0, err 119 } 120 121 quality := d.quality() 122 return img, int(quality), err 123 } 124 125 func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) { 126 return decode(d, r, configOnly) 127 } 128 129 //go:linkname decode image/jpeg.(*decoder).decode 130 func decode(d *decoder, r io.Reader, configOnly bool) (image.Image, error)