tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

quant.cc (24750B)


      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.
      5 
      6 #include "lib/jpegli/quant.h"
      7 
      8 #include <algorithm>
      9 #include <cmath>
     10 #include <vector>
     11 
     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"
     19 
     20 namespace jpegli {
     21 
     22 namespace {
     23 
     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;
     28 
     29 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,
    225 };
    226 
    227 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,  //
    423 };
    424 
    425 const float k420GlobalScale = 1.22;
    426 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,  //
    435 };
    436 
    437 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,  //
    456 };
    457 
    458 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,  //
    486 };
    487 
    488 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,  //
    516 };
    517 
    518 const float kZeroBiasOffsetYCbCrDC[] = {0.0f, 0.0f, 0.0f};
    519 
    520 const float kZeroBiasOffsetYCbCrAC[] = {
    521    0.59082f,
    522    0.58146f,
    523    0.57988f,
    524 };
    525 
    526 constexpr uint8_t kTransferFunctionPQ = 16;
    527 constexpr uint8_t kTransferFunctionHLG = 18;
    528 
    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;
    542  }
    543 }
    544 
    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,  //
    554 };
    555 constexpr float kDist0 = 1.5f;  // distance where non-linearity kicks in.
    556 
    557 float DistanceToScale(float distance, int k) {
    558  if (distance < kDist0) {
    559    return distance;
    560  }
    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));
    564 }
    565 
    566 float ScaleToDistance(float scale, int k) {
    567  if (scale < kDist0) {
    568    return scale;
    569  }
    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));
    573 }
    574 
    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;
    582  }
    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);
    599      }
    600      if (qval < quant_max) {
    601        float scale_max = (qval + 0.5f) * invq;
    602        dmax = ScaleToDistance(scale_max, k);
    603      }
    604      if (dmin <= dist_max) {
    605        dist_min = std::max(dmin, dist_min);
    606      }
    607      if (dmax >= dist_min) {
    608        dist_max = std::min(dist_max, dmax);
    609      }
    610    }
    611  }
    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);
    619  }
    620  return distance;
    621 }
    622 
    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);
    631 }
    632 
    633 }  // namespace
    634 
    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);
    640 
    641  float global_scale;
    642  bool non_linear_scaling = true;
    643  const float* base_quant_matrix[NUM_QUANT_TBLS];
    644  int num_base_tables;
    645 
    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;
    658    }
    659    if (is_yuv420) {
    660      global_scale *= k420GlobalScale;
    661    }
    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;
    673    }
    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;
    680  }
    681 
    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));
    688    }
    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];
    695        }
    696      } else {
    697        scale *= DistanceToLinearQuality(distances[quant_idx]);
    698      }
    699      int qval = std::round(scale * base_qm[k]);
    700      (*qtable)->quantval[k] = std::max(1, std::min(qval, quant_max));
    701    }
    702    (*qtable)->sent_table = FALSE;
    703  }
    704 }
    705 
    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,
    714                   c);
    715    }
    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.");
    720      }
    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;
    731      }
    732    }
    733  }
    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;
    739      }
    740    }
    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];
    755        }
    756      }
    757    }
    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];
    763      }
    764    }
    765  }
    766 }
    767 
    768 }  // namespace jpegli