1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
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"
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"
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
[] = {
227 static const float kBaseQuantMatrixYCbCr
[] = {
229 1.2397409345866273f
, //
230 1.7227115097630963f
, //
231 2.9212167156636855f
, //
232 2.812737435286529f
, //
233 3.339819711906184f
, //
234 3.463603762596166f
, //
235 3.840915217993518f
, //
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
, //
261 3.339819711906184f
, //
262 3.4407673520905337f
, //
263 3.619523781336757f
, //
264 4.1679867415584315f
, //
265 4.579851258441568f
, //
268 5.48533336146308f
, //
269 3.463603762596166f
, //
270 3.166232352090534f
, //
271 3.9046279999999998f
, //
272 4.805510627261856f
, //
275 5.093895741558431f
, //
276 6.0872254423617225f
, //
277 3.840915217993518f
, //
278 4.025208741558432f
, //
279 3.757835838431854f
, //
282 5.093895741558431f
, //
284 5.4037359493250845f
, //
286 4.035324490952577f
, //
287 4.237447515714274f
, //
289 5.48533336146308f
, //
290 6.0872254423617225f
, //
291 5.4037359493250845f
, //
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
, //
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
, //
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
, //
353 35.79788782635831f
, //
355 67.48111451705412f
, //
356 88.34665293823721f
, //
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
, //
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
, //
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
[] = {
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
, //
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
[] = {
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
, //
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
, //
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
[] = {
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
, //
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
, //
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
[] = {
526 constexpr uint8_t kTransferFunctionPQ
= 16;
527 constexpr uint8_t kTransferFunctionHLG
= 18;
529 float DistanceToLinearQuality(float distance
) {
530 if (distance
<= 0.1f
) {
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
) {
539 300.0f
* std::sqrt((848.0f
* distance
- 5330.0f
) / 120.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
) {
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
) {
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
) {
580 } else if (m
->cicp_transfer_function
== kTransferFunctionHLG
) {
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
) {
593 float dmax
= kDistMax
;
594 float invq
= 1.0f
/ base_qm
[k
] / global_scale
;
595 int qval
= quantval
[k
];
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
);
615 } else if (dist_max
== kDistMax
) {
618 distance
= 0.5f
* (dist_min
+ dist_max
);
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);
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
);
642 bool non_linear_scaling
= true;
643 const float* base_quant_matrix
[NUM_QUANT_TBLS
];
647 global_scale
= kGlobalScaleXYB
;
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
) {
656 } else if (m
->cicp_transfer_function
== kTransferFunctionHLG
) {
660 global_scale
*= k420GlobalScale
;
662 if (add_two_chroma_tables
) {
663 cinfo
->comp_info
[2].quant_tbl_no
= 2;
665 base_quant_matrix
[0] = kBaseQuantMatrixYCbCr
;
666 base_quant_matrix
[1] = kBaseQuantMatrixYCbCr
+ DCTSIZE2
;
667 base_quant_matrix
[2] = kBaseQuantMatrixYCbCr
+ 2 * DCTSIZE2
;
670 base_quant_matrix
[0] = kBaseQuantMatrixYCbCr
;
671 // Use the Cr table for both Cb and Cr.
672 base_quant_matrix
[1] = kBaseQuantMatrixYCbCr
+ 2 * DCTSIZE2
;
675 global_scale
= 0.01f
;
676 non_linear_scaling
= false;
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
];
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
];
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
];
719 JPEGLI_ERROR("Invalid quantval 0.");
722 case QuantPass::NO_SEARCH
:
723 m
->quant_mul
[c
][k
] = 8.0f
/ val
;
725 case QuantPass::SEARCH_FIRST_PASS
:
726 m
->quant_mul
[c
][k
] = 128.0f
;
728 case QuantPass::SEARCH_SECOND_PASS
:
729 m
->quant_mul
[c
][kJPEGZigZagOrder
[k
]] = 1.0f
/ (16 * val
);
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