libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | 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