Backed out 3 changesets (bug 1790375) for causing wd failures on fetch_error.py....
[gecko.git] / third_party / jpeg-xl / lib / jpegli / quant.cc
blob36f1df4cdd2fb0a38b421c22d7fdb578d1fba38d
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
2 //
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
6 #include "lib/jpegli/quant.h"
8 #include <algorithm>
9 #include <cmath>
10 #include <vector>
12 #include "lib/jpegli/adaptive_quantization.h"
13 #include "lib/jpegli/common.h"
14 #include "lib/jpegli/encode_internal.h"
15 #include "lib/jpegli/error.h"
16 #include "lib/jpegli/memory_manager.h"
17 #include "lib/jxl/base/byte_order.h"
18 #include "lib/jxl/base/status.h"
20 namespace jpegli {
22 namespace {
24 // Global scale is chosen in a way that butteraugli 3-norm matches libjpeg
25 // with the same quality setting. Fitted for quality 90 on jyrki31 corpus.
26 constexpr float kGlobalScaleXYB = 1.43951668f;
27 constexpr float kGlobalScaleYCbCr = 1.73966010f;
29 static constexpr float kBaseQuantMatrixXYB[] = {
30 // c = 0
31 7.5629935265f,
32 19.8247814178f,
33 22.5724945068f,
34 20.6706695557f,
35 22.6864585876f,
36 23.5696277618f,
37 25.8129081726f,
38 36.3307571411f,
39 19.8247814178f,
40 21.5503177643f,
41 19.9372234344f,
42 20.5424213409f,
43 21.8645496368f,
44 23.9041385651f,
45 28.2844066620f,
46 32.6609764099f,
47 22.5724945068f,
48 19.9372234344f,
49 21.9017257690f,
50 19.1223449707f,
51 21.7515811920f,
52 24.6724700928f,
53 25.4249649048f,
54 32.6653823853f,
55 20.6706695557f,
56 20.5424213409f,
57 19.1223449707f,
58 20.1610221863f,
59 25.3719692230f,
60 25.9668903351f,
61 30.9804954529f,
62 31.3406009674f,
63 22.6864585876f,
64 21.8645496368f,
65 21.7515811920f,
66 25.3719692230f,
67 26.2431850433f,
68 40.5992202759f,
69 43.2624626160f,
70 63.3010940552f,
71 23.5696277618f,
72 23.9041385651f,
73 24.6724700928f,
74 25.9668903351f,
75 40.5992202759f,
76 48.3026771545f,
77 34.0964355469f,
78 61.9852142334f,
79 25.8129081726f,
80 28.2844066620f,
81 25.4249649048f,
82 30.9804954529f,
83 43.2624626160f,
84 34.0964355469f,
85 34.4937438965f,
86 66.9702758789f,
87 36.3307571411f,
88 32.6609764099f,
89 32.6653823853f,
90 31.3406009674f,
91 63.3010940552f,
92 61.9852142334f,
93 66.9702758789f,
94 39.9652709961f,
95 // c = 1
96 1.6262000799f,
97 3.2199242115f,
98 3.4903779030f,
99 3.9148359299f,
100 4.8337211609f,
101 4.9108843803f,
102 5.3137121201f,
103 6.1676793098f,
104 3.2199242115f,
105 3.4547898769f,
106 3.6036829948f,
107 4.2652835846f,
108 4.8368387222f,
109 4.8226222992f,
110 5.6120514870f,
111 6.3431472778f,
112 3.4903779030f,
113 3.6036829948f,
114 3.9044559002f,
115 4.3374395370f,
116 4.8435096741f,
117 5.4057979584f,
118 5.6066360474f,
119 6.1075134277f,
120 3.9148359299f,
121 4.2652835846f,
122 4.3374395370f,
123 4.6064834595f,
124 5.1751475334f,
125 5.4013924599f,
126 6.0399808884f,
127 6.7825231552f,
128 4.8337211609f,
129 4.8368387222f,
130 4.8435096741f,
131 5.1751475334f,
132 5.3748049736f,
133 6.1410837173f,
134 7.6529307365f,
135 7.5235214233f,
136 4.9108843803f,
137 4.8226222992f,
138 5.4057979584f,
139 5.4013924599f,
140 6.1410837173f,
141 6.3431472778f,
142 7.1083049774f,
143 7.6008300781f,
144 5.3137121201f,
145 5.6120514870f,
146 5.6066360474f,
147 6.0399808884f,
148 7.6529307365f,
149 7.1083049774f,
150 7.0943155289f,
151 7.0478363037f,
152 6.1676793098f,
153 6.3431472778f,
154 6.1075134277f,
155 6.7825231552f,
156 7.5235214233f,
157 7.6008300781f,
158 7.0478363037f,
159 6.9186143875f,
160 // c = 2
161 3.3038473129f,
162 10.0689258575f,
163 12.2785224915f,
164 14.6041173935f,
165 16.2107315063f,
166 19.2314529419f,
167 28.0129547119f,
168 55.6682891846f,
169 10.0689258575f,
170 11.4085016251f,
171 11.3871345520f,
172 15.4934167862f,
173 16.5364933014f,
174 14.9153423309f,
175 26.3748722076f,
176 40.8614425659f,
177 12.2785224915f,
178 11.3871345520f,
179 17.0886878967f,
180 13.9500350952f,
181 16.0003223419f,
182 28.5660629272f,
183 26.2124195099f,
184 30.1260128021f,
185 14.6041173935f,
186 15.4934167862f,
187 13.9500350952f,
188 21.1235027313f,
189 26.1579780579f,
190 25.5579223633f,
191 40.6859359741f,
192 33.8056335449f,
193 16.2107315063f,
194 16.5364933014f,
195 16.0003223419f,
196 26.1579780579f,
197 26.8042831421f,
198 26.1587715149f,
199 35.7343978882f,
200 43.6857032776f,
201 19.2314529419f,
202 14.9153423309f,
203 28.5660629272f,
204 25.5579223633f,
205 26.1587715149f,
206 34.5418128967f,
207 41.3197937012f,
208 48.7867660522f,
209 28.0129547119f,
210 26.3748722076f,
211 26.2124195099f,
212 40.6859359741f,
213 35.7343978882f,
214 41.3197937012f,
215 47.6329460144f,
216 55.3498458862f,
217 55.6682891846f,
218 40.8614425659f,
219 30.1260128021f,
220 33.8056335449f,
221 43.6857032776f,
222 48.7867660522f,
223 55.3498458862f,
224 63.6065597534f,
227 static const float kBaseQuantMatrixYCbCr[] = {
228 // c = 0
229 1.2397409345866273f, //
230 1.7227115097630963f, //
231 2.9212167156636855f, //
232 2.812737435286529f, //
233 3.339819711906184f, //
234 3.463603762596166f, //
235 3.840915217993518f, //
236 3.86956f, //
237 1.7227115097630963f, //
238 2.0928894413636874f, //
239 2.8456760904429297f, //
240 2.704506820909662f, //
241 3.4407673520905337f, //
242 3.166232352090534f, //
243 4.025208741558432f, //
244 4.035324490952577f, //
245 2.9212167156636855f, //
246 2.8456760904429297f, //
247 2.9587403520905338f, //
248 3.3862948970669273f, //
249 3.619523781336757f, //
250 3.9046279999999998f, //
251 3.757835838431854f, //
252 4.237447515714274f, //
253 2.812737435286529f, //
254 2.704506820909662f, //
255 3.3862948970669273f, //
256 3.380058821812233f, //
257 4.1679867415584315f, //
258 4.805510627261856f, //
259 4.784259f, //
260 4.605934f, //
261 3.339819711906184f, //
262 3.4407673520905337f, //
263 3.619523781336757f, //
264 4.1679867415584315f, //
265 4.579851258441568f, //
266 4.923237f, //
267 5.574107f, //
268 5.48533336146308f, //
269 3.463603762596166f, //
270 3.166232352090534f, //
271 3.9046279999999998f, //
272 4.805510627261856f, //
273 4.923237f, //
274 5.43936f, //
275 5.093895741558431f, //
276 6.0872254423617225f, //
277 3.840915217993518f, //
278 4.025208741558432f, //
279 3.757835838431854f, //
280 4.784259f, //
281 5.574107f, //
282 5.093895741558431f, //
283 5.438461f, //
284 5.4037359493250845f, //
285 3.86956f, //
286 4.035324490952577f, //
287 4.237447515714274f, //
288 4.605934f, //
289 5.48533336146308f, //
290 6.0872254423617225f, //
291 5.4037359493250845f, //
292 4.37787101190424f,
293 // c = 1
294 2.8236197786377537f, //
295 6.495639358561486f, //
296 9.310489207538302f, //
297 10.64747864717083f, //
298 11.07419143098738f, //
299 17.146390223910462f, //
300 18.463982229408998f, //
301 29.087001644203088f, //
302 6.495639358561486f, //
303 8.890103846667353f, //
304 8.976895794294748f, //
305 13.666270550318826f, //
306 16.547071905624193f, //
307 16.63871382827686f, //
308 26.778396930893695f, //
309 21.33034294694781f, //
310 9.310489207538302f, //
311 8.976895794294748f, //
312 11.08737706005991f, //
313 18.20548239870446f, //
314 19.752481654011646f, //
315 23.985660533114896f, //
316 102.6457378402362f, //
317 24.450989f, //
318 10.64747864717083f, //
319 13.666270550318826f, //
320 18.20548239870446f, //
321 18.628012327860365f, //
322 16.042509519487183f, //
323 25.04918273242625f, //
324 25.017140189353015f, //
325 35.79788782635831f, //
326 11.07419143098738f, //
327 16.547071905624193f, //
328 19.752481654011646f, //
329 16.042509519487183f, //
330 19.373482748612577f, //
331 14.677529999999999f, //
332 19.94695960400931f, //
333 51.094112f, //
334 17.146390223910462f, //
335 16.63871382827686f, //
336 23.985660533114896f, //
337 25.04918273242625f, //
338 14.677529999999999f, //
339 31.320412426835304f, //
340 46.357234000000005f, //
341 67.48111451705412f, //
342 18.463982229408998f, //
343 26.778396930893695f, //
344 102.6457378402362f, //
345 25.017140189353015f, //
346 19.94695960400931f, //
347 46.357234000000005f, //
348 61.315764694388044f, //
349 88.34665293823721f, //
350 29.087001644203088f, //
351 21.33034294694781f, //
352 24.450989f, //
353 35.79788782635831f, //
354 51.094112f, //
355 67.48111451705412f, //
356 88.34665293823721f, //
357 112.16099098350989f,
358 // c = 2
359 2.9217254961255255f, //
360 4.497681013199305f, //
361 7.356344520940414f, //
362 6.583891506504051f, //
363 8.535608740100237f, //
364 8.799434353234647f, //
365 9.188341534163023f, //
366 9.482700481227672f, //
367 4.497681013199305f, //
368 6.309548851989123f, //
369 7.024608962670982f, //
370 7.156445324163424f, //
371 8.049059218663244f, //
372 7.0124290657218555f, //
373 6.711923184393611f, //
374 8.380307846134853f, //
375 7.356344520940414f, //
376 7.024608962670982f, //
377 6.892101177327445f, //
378 6.882819916277163f, //
379 8.782226090078568f, //
380 6.8774750000000004f, //
381 7.8858175969577955f, //
382 8.67909f, //
383 6.583891506504051f, //
384 7.156445324163424f, //
385 6.882819916277163f, //
386 7.003072944847055f, //
387 7.7223464701024875f, //
388 7.955425720217421f, //
389 7.4734110000000005f, //
390 8.362933242943903f, //
391 8.535608740100237f, //
392 8.049059218663244f, //
393 8.782226090078568f, //
394 7.7223464701024875f, //
395 6.778005927001542f, //
396 9.484922741558432f, //
397 9.043702663686046f, //
398 8.053178199770173f, //
399 8.799434353234647f, //
400 7.0124290657218555f, //
401 6.8774750000000004f, //
402 7.955425720217421f, //
403 9.484922741558432f, //
404 8.607606527385098f, //
405 9.922697394370815f, //
406 64.25135180237939f, //
407 9.188341534163023f, //
408 6.711923184393611f, //
409 7.8858175969577955f, //
410 7.4734110000000005f, //
411 9.043702663686046f, //
412 9.922697394370815f, //
413 63.184936549738225f, //
414 83.35294340273799f, //
415 9.482700481227672f, //
416 8.380307846134853f, //
417 8.67909f, //
418 8.362933242943903f, //
419 8.053178199770173f, //
420 64.25135180237939f, //
421 83.35294340273799f, //
422 114.89202448569779f, //
425 static const float k420GlobalScale = 1.22;
426 static const float k420Rescale[64] = {
427 0.4093, 0.3209, 0.3477, 0.3333, 0.3144, 0.2823, 0.3214, 0.3354, //
428 0.3209, 0.3111, 0.3489, 0.2801, 0.3059, 0.3119, 0.4135, 0.3445, //
429 0.3477, 0.3489, 0.3586, 0.3257, 0.2727, 0.3754, 0.3369, 0.3484, //
430 0.3333, 0.2801, 0.3257, 0.3020, 0.3515, 0.3410, 0.3971, 0.3839, //
431 0.3144, 0.3059, 0.2727, 0.3515, 0.3105, 0.3397, 0.2716, 0.3836, //
432 0.2823, 0.3119, 0.3754, 0.3410, 0.3397, 0.3212, 0.3203, 0.0726, //
433 0.3214, 0.4135, 0.3369, 0.3971, 0.2716, 0.3203, 0.0798, 0.0553, //
434 0.3354, 0.3445, 0.3484, 0.3839, 0.3836, 0.0726, 0.0553, 0.3368, //
437 static const float kBaseQuantMatrixStd[] = {
438 // c = 0
439 16.0f, 11.0f, 10.0f, 16.0f, 24.0f, 40.0f, 51.0f, 61.0f, //
440 12.0f, 12.0f, 14.0f, 19.0f, 26.0f, 58.0f, 60.0f, 55.0f, //
441 14.0f, 13.0f, 16.0f, 24.0f, 40.0f, 57.0f, 69.0f, 56.0f, //
442 14.0f, 17.0f, 22.0f, 29.0f, 51.0f, 87.0f, 80.0f, 62.0f, //
443 18.0f, 22.0f, 37.0f, 56.0f, 68.0f, 109.0f, 103.0f, 77.0f, //
444 24.0f, 35.0f, 55.0f, 64.0f, 81.0f, 104.0f, 113.0f, 92.0f, //
445 49.0f, 64.0f, 78.0f, 87.0f, 103.0f, 121.0f, 120.0f, 101.0f, //
446 72.0f, 92.0f, 95.0f, 98.0f, 112.0f, 100.0f, 103.0f, 99.0f, //
447 // c = 1
448 17.0f, 18.0f, 24.0f, 47.0f, 99.0f, 99.0f, 99.0f, 99.0f, //
449 18.0f, 21.0f, 26.0f, 66.0f, 99.0f, 99.0f, 99.0f, 99.0f, //
450 24.0f, 26.0f, 56.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, //
451 47.0f, 66.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, //
452 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, //
453 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, //
454 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, //
455 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, 99.0f, //
458 static const float kZeroBiasMulYCbCrLQ[] = {
459 // c = 0
460 0.0000f, 0.0568f, 0.3880f, 0.6190f, 0.6190f, 0.4490f, 0.4490f, 0.6187f, //
461 0.0568f, 0.5829f, 0.6189f, 0.6190f, 0.6190f, 0.7190f, 0.6190f, 0.6189f, //
462 0.3880f, 0.6189f, 0.6190f, 0.6190f, 0.6190f, 0.6190f, 0.6187f, 0.6100f, //
463 0.6190f, 0.6190f, 0.6190f, 0.6190f, 0.5890f, 0.3839f, 0.7160f, 0.6190f, //
464 0.6190f, 0.6190f, 0.6190f, 0.5890f, 0.6190f, 0.3880f, 0.5860f, 0.4790f, //
465 0.4490f, 0.7190f, 0.6190f, 0.3839f, 0.3880f, 0.6190f, 0.6190f, 0.6190f, //
466 0.4490f, 0.6190f, 0.6187f, 0.7160f, 0.5860f, 0.6190f, 0.6204f, 0.6190f, //
467 0.6187f, 0.6189f, 0.6100f, 0.6190f, 0.4790f, 0.6190f, 0.6190f, 0.3480f, //
468 // c = 1
469 0.0000f, 1.1640f, 0.9373f, 1.1319f, 0.8016f, 0.9136f, 1.1530f, 0.9430f, //
470 1.1640f, 0.9188f, 0.9160f, 1.1980f, 1.1830f, 0.9758f, 0.9430f, 0.9430f, //
471 0.9373f, 0.9160f, 0.8430f, 1.1720f, 0.7083f, 0.9430f, 0.9430f, 0.9430f, //
472 1.1319f, 1.1980f, 1.1720f, 1.1490f, 0.8547f, 0.9430f, 0.9430f, 0.9430f, //
473 0.8016f, 1.1830f, 0.7083f, 0.8547f, 0.9430f, 0.9430f, 0.9430f, 0.9430f, //
474 0.9136f, 0.9758f, 0.9430f, 0.9430f, 0.9430f, 0.9430f, 0.9430f, 0.9430f, //
475 1.1530f, 0.9430f, 0.9430f, 0.9430f, 0.9430f, 0.9430f, 0.9430f, 0.9480f, //
476 0.9430f, 0.9430f, 0.9430f, 0.9430f, 0.9430f, 0.9430f, 0.9480f, 0.9430f, //
477 // c = 2
478 0.0000f, 1.3190f, 0.4308f, 0.4460f, 0.0661f, 0.0660f, 0.2660f, 0.2960f, //
479 1.3190f, 0.3280f, 0.3093f, 0.0750f, 0.0505f, 0.1594f, 0.3060f, 0.2113f, //
480 0.4308f, 0.3093f, 0.3060f, 0.1182f, 0.0500f, 0.3060f, 0.3915f, 0.2426f, //
481 0.4460f, 0.0750f, 0.1182f, 0.0512f, 0.0500f, 0.2130f, 0.3930f, 0.1590f, //
482 0.0661f, 0.0505f, 0.0500f, 0.0500f, 0.3055f, 0.3360f, 0.5148f, 0.5403f, //
483 0.0660f, 0.1594f, 0.3060f, 0.2130f, 0.3360f, 0.5060f, 0.5874f, 0.3060f, //
484 0.2660f, 0.3060f, 0.3915f, 0.3930f, 0.5148f, 0.5874f, 0.3060f, 0.3060f, //
485 0.2960f, 0.2113f, 0.2426f, 0.1590f, 0.5403f, 0.3060f, 0.3060f, 0.3060f, //
488 static const float kZeroBiasMulYCbCrHQ[] = {
489 // c = 0
490 0.0000f, 0.0044f, 0.2521f, 0.6547f, 0.8161f, 0.6130f, 0.8841f, 0.8155f, //
491 0.0044f, 0.6831f, 0.6553f, 0.6295f, 0.7848f, 0.7843f, 0.8474f, 0.7836f, //
492 0.2521f, 0.6553f, 0.7834f, 0.7829f, 0.8161f, 0.8072f, 0.7743f, 0.9242f, //
493 0.6547f, 0.6295f, 0.7829f, 0.8654f, 0.7829f, 0.6986f, 0.7818f, 0.7726f, //
494 0.8161f, 0.7848f, 0.8161f, 0.7829f, 0.7471f, 0.7827f, 0.7843f, 0.7653f, //
495 0.6130f, 0.7843f, 0.8072f, 0.6986f, 0.7827f, 0.7848f, 0.9508f, 0.7653f, //
496 0.8841f, 0.8474f, 0.7743f, 0.7818f, 0.7843f, 0.9508f, 0.7839f, 0.8437f, //
497 0.8155f, 0.7836f, 0.9242f, 0.7726f, 0.7653f, 0.7653f, 0.8437f, 0.7819f, //
498 // c = 1
499 0.0000f, 1.0816f, 1.0556f, 1.2876f, 1.1554f, 1.1567f, 1.8851f, 0.5488f, //
500 1.0816f, 1.1537f, 1.1850f, 1.0712f, 1.1671f, 2.0719f, 1.0544f, 1.4764f, //
501 1.0556f, 1.1850f, 1.2870f, 1.1981f, 1.8181f, 1.2618f, 1.0564f, 1.1191f, //
502 1.2876f, 1.0712f, 1.1981f, 1.4753f, 2.0609f, 1.0564f, 1.2645f, 1.0564f, //
503 1.1554f, 1.1671f, 1.8181f, 2.0609f, 0.7324f, 1.1163f, 0.8464f, 1.0564f, //
504 1.1567f, 2.0719f, 1.2618f, 1.0564f, 1.1163f, 1.0040f, 1.0564f, 1.0564f, //
505 1.8851f, 1.0544f, 1.0564f, 1.2645f, 0.8464f, 1.0564f, 1.0564f, 1.0564f, //
506 0.5488f, 1.4764f, 1.1191f, 1.0564f, 1.0564f, 1.0564f, 1.0564f, 1.0564f, //
507 // c = 2
508 0.0000f, 0.5392f, 0.6659f, 0.8968f, 0.6829f, 0.6328f, 0.5802f, 0.4836f, //
509 0.5392f, 0.6746f, 0.6760f, 0.6102f, 0.6015f, 0.6958f, 0.7327f, 0.4897f, //
510 0.6659f, 0.6760f, 0.6957f, 0.6543f, 0.4396f, 0.6330f, 0.7081f, 0.2583f, //
511 0.8968f, 0.6102f, 0.6543f, 0.5913f, 0.6457f, 0.5828f, 0.5139f, 0.3565f, //
512 0.6829f, 0.6015f, 0.4396f, 0.6457f, 0.5633f, 0.4263f, 0.6371f, 0.5949f, //
513 0.6328f, 0.6958f, 0.6330f, 0.5828f, 0.4263f, 0.2847f, 0.2909f, 0.6629f, //
514 0.5802f, 0.7327f, 0.7081f, 0.5139f, 0.6371f, 0.2909f, 0.6644f, 0.6644f, //
515 0.4836f, 0.4897f, 0.2583f, 0.3565f, 0.5949f, 0.6629f, 0.6644f, 0.6644f, //
518 static const float kZeroBiasOffsetYCbCrDC[] = {0.0f, 0.0f, 0.0f};
520 static const float kZeroBiasOffsetYCbCrAC[] = {
521 0.59082f,
522 0.58146f,
523 0.57988f,
526 constexpr uint8_t kTransferFunctionPQ = 16;
527 constexpr uint8_t kTransferFunctionHLG = 18;
529 float DistanceToLinearQuality(float distance) {
530 if (distance <= 0.1f) {
531 return 1.0f;
532 } else if (distance <= 4.6f) {
533 return (200.0f / 9.0f) * (distance - 0.1f);
534 } else if (distance <= 6.4f) {
535 return 5000.0f / (100.0f - (distance - 0.1f) / 0.09f);
536 } else if (distance < 25.0f) {
537 return 530000.0f /
538 (3450.0f -
539 300.0f * std::sqrt((848.0f * distance - 5330.0f) / 120.0f));
540 } else {
541 return 5000.0f;
545 constexpr float kExponent[DCTSIZE2] = {
546 1.00f, 0.51f, 0.67f, 0.74f, 1.00f, 1.00f, 1.00f, 1.00f, //
547 0.51f, 0.66f, 0.69f, 0.87f, 1.00f, 1.00f, 1.00f, 1.00f, //
548 0.67f, 0.69f, 0.84f, 0.83f, 0.96f, 1.00f, 1.00f, 1.00f, //
549 0.74f, 0.87f, 0.83f, 1.00f, 1.00f, 0.91f, 0.91f, 1.00f, //
550 1.00f, 1.00f, 0.96f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, //
551 1.00f, 1.00f, 1.00f, 0.91f, 1.00f, 1.00f, 1.00f, 1.00f, //
552 1.00f, 1.00f, 1.00f, 0.91f, 1.00f, 1.00f, 1.00f, 1.00f, //
553 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, //
555 constexpr float kDist0 = 1.5f; // distance where non-linearity kicks in.
557 float DistanceToScale(float distance, int k) {
558 if (distance < kDist0) {
559 return distance;
561 const float exp = kExponent[k];
562 const float mul = std::pow(kDist0, 1.0 - exp);
563 return std::max<float>(0.5f * distance, mul * std::pow(distance, exp));
566 float ScaleToDistance(float scale, int k) {
567 if (scale < kDist0) {
568 return scale;
570 const float exp = 1.0 / kExponent[k];
571 const float mul = std::pow(kDist0, 1.0 - exp);
572 return std::min<float>(2.0f * scale, mul * std::pow(scale, exp));
575 float QuantValsToDistance(j_compress_ptr cinfo) {
576 jpeg_comp_master* m = cinfo->master;
577 float global_scale = kGlobalScaleYCbCr;
578 if (m->cicp_transfer_function == kTransferFunctionPQ) {
579 global_scale *= .4f;
580 } else if (m->cicp_transfer_function == kTransferFunctionHLG) {
581 global_scale *= .5f;
583 int quant_max = m->force_baseline ? 255 : 32767U;
584 static const float kDistMax = 10000.0f;
585 float dist_min = 0.0f;
586 float dist_max = kDistMax;
587 for (int c = 0; c < cinfo->num_components; ++c) {
588 int quant_idx = cinfo->comp_info[c].quant_tbl_no;
589 uint16_t* quantval = cinfo->quant_tbl_ptrs[quant_idx]->quantval;
590 const float* base_qm = &kBaseQuantMatrixYCbCr[quant_idx * DCTSIZE2];
591 for (int k = 0; k < DCTSIZE2; ++k) {
592 float dmin = 0.0;
593 float dmax = kDistMax;
594 float invq = 1.0f / base_qm[k] / global_scale;
595 int qval = quantval[k];
596 if (qval > 1) {
597 float scale_min = (qval - 0.5f) * invq;
598 dmin = ScaleToDistance(scale_min, k);
600 if (qval < quant_max) {
601 float scale_max = (qval + 0.5f) * invq;
602 dmax = ScaleToDistance(scale_max, k);
604 if (dmin <= dist_max) {
605 dist_min = std::max(dmin, dist_min);
607 if (dmax >= dist_min) {
608 dist_max = std::min(dist_max, dmax);
612 float distance;
613 if (dist_min == 0) {
614 distance = dist_max;
615 } else if (dist_max == kDistMax) {
616 distance = dist_min;
617 } else {
618 distance = 0.5f * (dist_min + dist_max);
620 return distance;
623 bool IsYUV420(j_compress_ptr cinfo) {
624 return (cinfo->jpeg_color_space == JCS_YCbCr &&
625 cinfo->comp_info[0].h_samp_factor == 2 &&
626 cinfo->comp_info[0].v_samp_factor == 2 &&
627 cinfo->comp_info[1].h_samp_factor == 1 &&
628 cinfo->comp_info[1].v_samp_factor == 1 &&
629 cinfo->comp_info[2].h_samp_factor == 1 &&
630 cinfo->comp_info[2].v_samp_factor == 1);
633 } // namespace
635 void SetQuantMatrices(j_compress_ptr cinfo, float distances[NUM_QUANT_TBLS],
636 bool add_two_chroma_tables) {
637 jpeg_comp_master* m = cinfo->master;
638 const bool xyb = m->xyb_mode && cinfo->jpeg_color_space == JCS_RGB;
639 const bool is_yuv420 = IsYUV420(cinfo);
641 float global_scale;
642 bool non_linear_scaling = true;
643 const float* base_quant_matrix[NUM_QUANT_TBLS];
644 int num_base_tables;
646 if (xyb) {
647 global_scale = kGlobalScaleXYB;
648 num_base_tables = 3;
649 base_quant_matrix[0] = kBaseQuantMatrixXYB;
650 base_quant_matrix[1] = kBaseQuantMatrixXYB + DCTSIZE2;
651 base_quant_matrix[2] = kBaseQuantMatrixXYB + 2 * DCTSIZE2;
652 } else if (cinfo->jpeg_color_space == JCS_YCbCr && !m->use_std_tables) {
653 global_scale = kGlobalScaleYCbCr;
654 if (m->cicp_transfer_function == kTransferFunctionPQ) {
655 global_scale *= .4f;
656 } else if (m->cicp_transfer_function == kTransferFunctionHLG) {
657 global_scale *= .5f;
659 if (is_yuv420) {
660 global_scale *= k420GlobalScale;
662 if (add_two_chroma_tables) {
663 cinfo->comp_info[2].quant_tbl_no = 2;
664 num_base_tables = 3;
665 base_quant_matrix[0] = kBaseQuantMatrixYCbCr;
666 base_quant_matrix[1] = kBaseQuantMatrixYCbCr + DCTSIZE2;
667 base_quant_matrix[2] = kBaseQuantMatrixYCbCr + 2 * DCTSIZE2;
668 } else {
669 num_base_tables = 2;
670 base_quant_matrix[0] = kBaseQuantMatrixYCbCr;
671 // Use the Cr table for both Cb and Cr.
672 base_quant_matrix[1] = kBaseQuantMatrixYCbCr + 2 * DCTSIZE2;
674 } else {
675 global_scale = 0.01f;
676 non_linear_scaling = false;
677 num_base_tables = 2;
678 base_quant_matrix[0] = kBaseQuantMatrixStd;
679 base_quant_matrix[1] = kBaseQuantMatrixStd + DCTSIZE2;
682 int quant_max = m->force_baseline ? 255 : 32767U;
683 for (int quant_idx = 0; quant_idx < num_base_tables; ++quant_idx) {
684 const float* base_qm = base_quant_matrix[quant_idx];
685 JQUANT_TBL** qtable = &cinfo->quant_tbl_ptrs[quant_idx];
686 if (*qtable == nullptr) {
687 *qtable = jpegli_alloc_quant_table(reinterpret_cast<j_common_ptr>(cinfo));
689 for (int k = 0; k < DCTSIZE2; ++k) {
690 float scale = global_scale;
691 if (non_linear_scaling) {
692 scale *= DistanceToScale(distances[quant_idx], k);
693 if (is_yuv420 && quant_idx > 0) {
694 scale *= k420Rescale[k];
696 } else {
697 scale *= DistanceToLinearQuality(distances[quant_idx]);
699 int qval = std::round(scale * base_qm[k]);
700 (*qtable)->quantval[k] = std::max(1, std::min(qval, quant_max));
702 (*qtable)->sent_table = FALSE;
706 void InitQuantizer(j_compress_ptr cinfo, QuantPass pass) {
707 jpeg_comp_master* m = cinfo->master;
708 // Compute quantization multupliers from the quant table values.
709 for (int c = 0; c < cinfo->num_components; ++c) {
710 int quant_idx = cinfo->comp_info[c].quant_tbl_no;
711 JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[quant_idx];
712 if (!quant_table) {
713 JPEGLI_ERROR("Missing quantization table %d for component %d", quant_idx,
716 for (size_t k = 0; k < DCTSIZE2; k++) {
717 int val = quant_table->quantval[k];
718 if (val == 0) {
719 JPEGLI_ERROR("Invalid quantval 0.");
721 switch (pass) {
722 case QuantPass::NO_SEARCH:
723 m->quant_mul[c][k] = 8.0f / val;
724 break;
725 case QuantPass::SEARCH_FIRST_PASS:
726 m->quant_mul[c][k] = 128.0f;
727 break;
728 case QuantPass::SEARCH_SECOND_PASS:
729 m->quant_mul[c][kJPEGZigZagOrder[k]] = 1.0f / (16 * val);
730 break;
734 if (m->use_adaptive_quantization) {
735 for (int c = 0; c < cinfo->num_components; ++c) {
736 for (int k = 0; k < DCTSIZE2; ++k) {
737 m->zero_bias_mul[c][k] = k == 0 ? 0.0f : 0.5f;
738 m->zero_bias_offset[c][k] = k == 0 ? 0.0f : 0.5f;
741 if (cinfo->jpeg_color_space == JCS_YCbCr) {
742 float distance = QuantValsToDistance(cinfo);
743 static const float kDistHQ = 1.0f;
744 static const float kDistLQ = 3.0f;
745 float mix0 = (distance - kDistHQ) / (kDistLQ - kDistHQ);
746 mix0 = std::max(0.0f, std::min(1.0f, mix0));
747 float mix1 = 1.0f - mix0;
748 for (int c = 0; c < cinfo->num_components; ++c) {
749 for (int k = 0; k < DCTSIZE2; ++k) {
750 float mul0 = kZeroBiasMulYCbCrLQ[c * DCTSIZE2 + k];
751 float mul1 = kZeroBiasMulYCbCrHQ[c * DCTSIZE2 + k];
752 m->zero_bias_mul[c][k] = mix0 * mul0 + mix1 * mul1;
753 m->zero_bias_offset[c][k] =
754 k == 0 ? kZeroBiasOffsetYCbCrDC[c] : kZeroBiasOffsetYCbCrAC[c];
758 } else if (cinfo->jpeg_color_space == JCS_YCbCr) {
759 for (int c = 0; c < cinfo->num_components; ++c) {
760 for (int k = 0; k < DCTSIZE2; ++k) {
761 m->zero_bias_offset[c][k] =
762 k == 0 ? kZeroBiasOffsetYCbCrDC[c] : kZeroBiasOffsetYCbCrAC[c];
768 } // namespace jpegli