libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

test_utils-inl.h (15861B)


      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 // This template file is included in both the libjpeg_test_util.cc and the
      7 // test_utils.cc files with different JPEG_API_FN macros and possibly different
      8 // include paths for the jpeg headers.
      9 
     10 // Sequential non-interleaved.
     11 constexpr jpeg_scan_info kScript1[] = {
     12     {1, {0}, 0, 63, 0, 0},
     13     {1, {1}, 0, 63, 0, 0},
     14     {1, {2}, 0, 63, 0, 0},
     15 };
     16 // Sequential partially interleaved, chroma first.
     17 constexpr jpeg_scan_info kScript2[] = {
     18     {2, {1, 2}, 0, 63, 0, 0},
     19     {1, {0}, 0, 63, 0, 0},
     20 };
     21 
     22 // Rest of the scan scripts are progressive.
     23 
     24 constexpr jpeg_scan_info kScript3[] = {
     25     // Interleaved full DC.
     26     {3, {0, 1, 2}, 0, 0, 0, 0},
     27     // Full AC scans.
     28     {1, {0}, 1, 63, 0, 0},
     29     {1, {1}, 1, 63, 0, 0},
     30     {1, {2}, 1, 63, 0, 0},
     31 };
     32 constexpr jpeg_scan_info kScript4[] = {
     33     // Non-interleaved full DC.
     34     {1, {0}, 0, 0, 0, 0},
     35     {1, {1}, 0, 0, 0, 0},
     36     {1, {2}, 0, 0, 0, 0},
     37     // Full AC scans.
     38     {1, {0}, 1, 63, 0, 0},
     39     {1, {1}, 1, 63, 0, 0},
     40     {1, {2}, 1, 63, 0, 0},
     41 };
     42 constexpr jpeg_scan_info kScript5[] = {
     43     // Partially interleaved full DC, chroma first.
     44     {2, {1, 2}, 0, 0, 0, 0},
     45     {1, {0}, 0, 0, 0, 0},
     46     // AC shifted by 1 bit.
     47     {1, {0}, 1, 63, 0, 1},
     48     {1, {1}, 1, 63, 0, 1},
     49     {1, {2}, 1, 63, 0, 1},
     50     // AC refinement scan.
     51     {1, {0}, 1, 63, 1, 0},
     52     {1, {1}, 1, 63, 1, 0},
     53     {1, {2}, 1, 63, 1, 0},
     54 };
     55 constexpr jpeg_scan_info kScript6[] = {
     56     // Interleaved DC shifted by 2 bits.
     57     {3, {0, 1, 2}, 0, 0, 0, 2},
     58     // Interleaved DC refinement scans.
     59     {3, {0, 1, 2}, 0, 0, 2, 1},
     60     {3, {0, 1, 2}, 0, 0, 1, 0},
     61     // Full AC scans.
     62     {1, {0}, 1, 63, 0, 0},
     63     {1, {1}, 1, 63, 0, 0},
     64     {1, {2}, 1, 63, 0, 0},
     65 };
     66 
     67 constexpr jpeg_scan_info kScript7[] = {
     68     // Non-interleaved DC shifted by 2 bits.
     69     {1, {0}, 0, 0, 0, 2},
     70     {1, {1}, 0, 0, 0, 2},
     71     {1, {2}, 0, 0, 0, 2},
     72     // Non-interleaved DC first refinement scans.
     73     {1, {0}, 0, 0, 2, 1},
     74     {1, {1}, 0, 0, 2, 1},
     75     {1, {2}, 0, 0, 2, 1},
     76     // Non-interleaved DC second refinement scans.
     77     {1, {0}, 0, 0, 1, 0},
     78     {1, {1}, 0, 0, 1, 0},
     79     {1, {2}, 0, 0, 1, 0},
     80     // Full AC scans.
     81     {1, {0}, 1, 63, 0, 0},
     82     {1, {1}, 1, 63, 0, 0},
     83     {1, {2}, 1, 63, 0, 0},
     84 };
     85 
     86 constexpr jpeg_scan_info kScript8[] = {
     87     // Partially interleaved DC shifted by 2 bits, chroma first
     88     {2, {1, 2}, 0, 0, 0, 2},
     89     {1, {0}, 0, 0, 0, 2},
     90     // Partially interleaved DC first refinement scans.
     91     {2, {0, 2}, 0, 0, 2, 1},
     92     {1, {1}, 0, 0, 2, 1},
     93     // Partially interleaved DC first refinement scans, chroma first.
     94     {2, {1, 2}, 0, 0, 1, 0},
     95     {1, {0}, 0, 0, 1, 0},
     96     // Full AC scans.
     97     {1, {0}, 1, 63, 0, 0},
     98     {1, {1}, 1, 63, 0, 0},
     99     {1, {2}, 1, 63, 0, 0},
    100 };
    101 
    102 constexpr jpeg_scan_info kScript9[] = {
    103     // Interleaved full DC.
    104     {3, {0, 1, 2}, 0, 0, 0, 0},
    105     // AC scans for component 0
    106     // shifted by 1 bit, two spectral ranges
    107     {1, {0}, 1, 6, 0, 1},
    108     {1, {0}, 7, 63, 0, 1},
    109     // refinement scan, full
    110     {1, {0}, 1, 63, 1, 0},
    111     // AC scans for component 1
    112     // shifted by 1 bit, full
    113     {1, {1}, 1, 63, 0, 1},
    114     // refinement scan, two spectral ranges
    115     {1, {1}, 1, 6, 1, 0},
    116     {1, {1}, 7, 63, 1, 0},
    117     // AC scans for component 2
    118     // shifted by 1 bit, two spectral ranges
    119     {1, {2}, 1, 6, 0, 1},
    120     {1, {2}, 7, 63, 0, 1},
    121     // refinement scan, two spectral ranges (but different from above)
    122     {1, {2}, 1, 16, 1, 0},
    123     {1, {2}, 17, 63, 1, 0},
    124 };
    125 
    126 constexpr jpeg_scan_info kScript10[] = {
    127     // Interleaved full DC.
    128     {3, {0, 1, 2}, 0, 0, 0, 0},
    129     // AC scans for spectral range 1..16
    130     // shifted by 1
    131     {1, {0}, 1, 16, 0, 1},
    132     {1, {1}, 1, 16, 0, 1},
    133     {1, {2}, 1, 16, 0, 1},
    134     // refinement scans, two sub-ranges
    135     {1, {0}, 1, 8, 1, 0},
    136     {1, {0}, 9, 16, 1, 0},
    137     {1, {1}, 1, 8, 1, 0},
    138     {1, {1}, 9, 16, 1, 0},
    139     {1, {2}, 1, 8, 1, 0},
    140     {1, {2}, 9, 16, 1, 0},
    141     // AC scans for spectral range 17..63
    142     {1, {0}, 17, 63, 0, 1},
    143     {1, {1}, 17, 63, 0, 1},
    144     {1, {2}, 17, 63, 0, 1},
    145     // refinement scans, two sub-ranges
    146     {1, {0}, 17, 28, 1, 0},
    147     {1, {0}, 29, 63, 1, 0},
    148     {1, {1}, 17, 28, 1, 0},
    149     {1, {1}, 29, 63, 1, 0},
    150     {1, {2}, 17, 28, 1, 0},
    151     {1, {2}, 29, 63, 1, 0},
    152 };
    153 
    154 struct ScanScript {
    155   int num_scans;
    156   const jpeg_scan_info* scans;
    157 };
    158 
    159 constexpr ScanScript kTestScript[] = {
    160     {ARRAY_SIZE(kScript1), kScript1}, {ARRAY_SIZE(kScript2), kScript2},
    161     {ARRAY_SIZE(kScript3), kScript3}, {ARRAY_SIZE(kScript4), kScript4},
    162     {ARRAY_SIZE(kScript5), kScript5}, {ARRAY_SIZE(kScript6), kScript6},
    163     {ARRAY_SIZE(kScript7), kScript7}, {ARRAY_SIZE(kScript8), kScript8},
    164     {ARRAY_SIZE(kScript9), kScript9}, {ARRAY_SIZE(kScript10), kScript10},
    165 };
    166 constexpr int kNumTestScripts = ARRAY_SIZE(kTestScript);
    167 
    168 void SetScanDecompressParams(const DecompressParams& dparams,
    169                              j_decompress_ptr cinfo, int scan_number) {
    170   const ScanDecompressParams* sparams = nullptr;
    171   for (const auto& sp : dparams.scan_params) {
    172     if (scan_number <= sp.max_scan_number) {
    173       sparams = &sp;
    174       break;
    175     }
    176   }
    177   if (sparams == nullptr) {
    178     return;
    179   }
    180   if (dparams.quantize_colors) {
    181     cinfo->dither_mode = static_cast<J_DITHER_MODE>(sparams->dither_mode);
    182     if (sparams->color_quant_mode == CQUANT_1PASS) {
    183       cinfo->two_pass_quantize = FALSE;
    184       cinfo->colormap = nullptr;
    185     } else if (sparams->color_quant_mode == CQUANT_2PASS) {
    186       JXL_CHECK(cinfo->out_color_space == JCS_RGB);
    187       cinfo->two_pass_quantize = TRUE;
    188       cinfo->colormap = nullptr;
    189     } else if (sparams->color_quant_mode == CQUANT_EXTERNAL) {
    190       JXL_CHECK(cinfo->out_color_space == JCS_RGB);
    191       cinfo->two_pass_quantize = FALSE;
    192       bool have_colormap = cinfo->colormap != nullptr;
    193       cinfo->actual_number_of_colors = kTestColorMapNumColors;
    194       cinfo->colormap = (*cinfo->mem->alloc_sarray)(
    195           reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE,
    196           cinfo->actual_number_of_colors, 3);
    197       jxl::msan::UnpoisonMemory(reinterpret_cast<void*>(cinfo->colormap),
    198                                 3 * sizeof(JSAMPLE*));
    199       for (int i = 0; i < kTestColorMapNumColors; ++i) {
    200         cinfo->colormap[0][i] = (kTestColorMap[i] >> 16) & 0xff;
    201         cinfo->colormap[1][i] = (kTestColorMap[i] >> 8) & 0xff;
    202         cinfo->colormap[2][i] = (kTestColorMap[i] >> 0) & 0xff;
    203       }
    204       if (have_colormap) {
    205         JPEG_API_FN(new_colormap)(cinfo);
    206       }
    207     } else if (sparams->color_quant_mode == CQUANT_REUSE) {
    208       JXL_CHECK(cinfo->out_color_space == JCS_RGB);
    209       JXL_CHECK(cinfo->colormap);
    210     }
    211   }
    212 }
    213 
    214 void SetDecompressParams(const DecompressParams& dparams,
    215                          j_decompress_ptr cinfo) {
    216   cinfo->do_block_smoothing = dparams.do_block_smoothing ? 1 : 0;
    217   cinfo->do_fancy_upsampling = dparams.do_fancy_upsampling ? 1 : 0;
    218   if (dparams.output_mode == RAW_DATA) {
    219     cinfo->raw_data_out = TRUE;
    220   }
    221   if (dparams.set_out_color_space) {
    222     cinfo->out_color_space =
    223         static_cast<J_COLOR_SPACE>(dparams.out_color_space);
    224     if (dparams.out_color_space == JCS_UNKNOWN) {
    225       cinfo->jpeg_color_space = JCS_UNKNOWN;
    226     }
    227   }
    228   cinfo->scale_num = dparams.scale_num;
    229   cinfo->scale_denom = dparams.scale_denom;
    230   cinfo->quantize_colors = dparams.quantize_colors ? 1 : 0;
    231   cinfo->desired_number_of_colors = dparams.desired_number_of_colors;
    232   if (!dparams.scan_params.empty()) {
    233     if (cinfo->buffered_image) {
    234       for (const auto& sparams : dparams.scan_params) {
    235         if (sparams.color_quant_mode == CQUANT_1PASS) {
    236           cinfo->enable_1pass_quant = TRUE;
    237         } else if (sparams.color_quant_mode == CQUANT_2PASS) {
    238           cinfo->enable_2pass_quant = TRUE;
    239         } else if (sparams.color_quant_mode == CQUANT_EXTERNAL) {
    240           cinfo->enable_external_quant = TRUE;
    241         }
    242       }
    243       SetScanDecompressParams(dparams, cinfo, 1);
    244     } else {
    245       SetScanDecompressParams(dparams, cinfo, kLastScan);
    246     }
    247   }
    248 }
    249 
    250 void CheckMarkerPresent(j_decompress_ptr cinfo, uint8_t marker_type) {
    251   bool marker_found = false;
    252   for (jpeg_saved_marker_ptr marker = cinfo->marker_list; marker != nullptr;
    253        marker = marker->next) {
    254     jxl::msan::UnpoisonMemory(marker, sizeof(*marker));
    255     jxl::msan::UnpoisonMemory(marker->data, marker->data_length);
    256     if (marker->marker == marker_type &&
    257         marker->data_length == sizeof(kMarkerData) &&
    258         memcmp(marker->data, kMarkerData, sizeof(kMarkerData)) == 0) {
    259       marker_found = true;
    260     }
    261   }
    262   JXL_CHECK(marker_found);
    263 }
    264 
    265 void VerifyHeader(const CompressParams& jparams, j_decompress_ptr cinfo) {
    266   if (jparams.set_jpeg_colorspace) {
    267     JXL_CHECK(cinfo->jpeg_color_space == jparams.jpeg_color_space);
    268   }
    269   if (jparams.override_JFIF >= 0) {
    270     JXL_CHECK(cinfo->saw_JFIF_marker == jparams.override_JFIF);
    271   }
    272   if (jparams.override_Adobe >= 0) {
    273     JXL_CHECK(cinfo->saw_Adobe_marker == jparams.override_Adobe);
    274   }
    275   if (jparams.add_marker) {
    276     CheckMarkerPresent(cinfo, kSpecialMarker0);
    277     CheckMarkerPresent(cinfo, kSpecialMarker1);
    278   }
    279   jxl::msan::UnpoisonMemory(
    280       cinfo->comp_info, cinfo->num_components * sizeof(cinfo->comp_info[0]));
    281   int max_h_samp_factor = 1;
    282   int max_v_samp_factor = 1;
    283   for (int i = 0; i < cinfo->num_components; ++i) {
    284     jpeg_component_info* comp = &cinfo->comp_info[i];
    285     if (!jparams.comp_ids.empty()) {
    286       JXL_CHECK(comp->component_id == jparams.comp_ids[i]);
    287     }
    288     if (!jparams.h_sampling.empty()) {
    289       JXL_CHECK(comp->h_samp_factor == jparams.h_sampling[i]);
    290     }
    291     if (!jparams.v_sampling.empty()) {
    292       JXL_CHECK(comp->v_samp_factor == jparams.v_sampling[i]);
    293     }
    294     if (!jparams.quant_indexes.empty()) {
    295       JXL_CHECK(comp->quant_tbl_no == jparams.quant_indexes[i]);
    296     }
    297     max_h_samp_factor = std::max(max_h_samp_factor, comp->h_samp_factor);
    298     max_v_samp_factor = std::max(max_v_samp_factor, comp->v_samp_factor);
    299   }
    300   JXL_CHECK(max_h_samp_factor == cinfo->max_h_samp_factor);
    301   JXL_CHECK(max_v_samp_factor == cinfo->max_v_samp_factor);
    302   int referenced_tables[NUM_QUANT_TBLS] = {};
    303   for (int i = 0; i < cinfo->num_components; ++i) {
    304     jpeg_component_info* comp = &cinfo->comp_info[i];
    305     JXL_CHECK(comp->width_in_blocks ==
    306               DivCeil(cinfo->image_width * comp->h_samp_factor,
    307                       max_h_samp_factor * DCTSIZE));
    308     JXL_CHECK(comp->height_in_blocks ==
    309               DivCeil(cinfo->image_height * comp->v_samp_factor,
    310                       max_v_samp_factor * DCTSIZE));
    311     referenced_tables[comp->quant_tbl_no] = 1;
    312   }
    313   for (const auto& table : jparams.quant_tables) {
    314     JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[table.slot_idx];
    315     if (!referenced_tables[table.slot_idx]) {
    316       JXL_CHECK(quant_table == nullptr);
    317       continue;
    318     }
    319     JXL_CHECK(quant_table != nullptr);
    320     jxl::msan::UnpoisonMemory(quant_table, sizeof(*quant_table));
    321     for (int k = 0; k < DCTSIZE2; ++k) {
    322       JXL_CHECK(quant_table->quantval[k] == table.quantval[k]);
    323     }
    324   }
    325 }
    326 
    327 void VerifyScanHeader(const CompressParams& jparams, j_decompress_ptr cinfo) {
    328   JXL_CHECK(cinfo->input_scan_number > 0);
    329   if (cinfo->progressive_mode) {
    330     JXL_CHECK(cinfo->Ss != 0 || cinfo->Se != 63);
    331   } else {
    332     JXL_CHECK(cinfo->Ss == 0 && cinfo->Se == 63);
    333   }
    334   if (jparams.progressive_mode > 2) {
    335     JXL_CHECK(jparams.progressive_mode < 3 + kNumTestScripts);
    336     const ScanScript& script = kTestScript[jparams.progressive_mode - 3];
    337     JXL_CHECK(cinfo->input_scan_number <= script.num_scans);
    338     const jpeg_scan_info& scan = script.scans[cinfo->input_scan_number - 1];
    339     JXL_CHECK(cinfo->comps_in_scan == scan.comps_in_scan);
    340     for (int i = 0; i < cinfo->comps_in_scan; ++i) {
    341       JXL_CHECK(cinfo->cur_comp_info[i]->component_index ==
    342                 scan.component_index[i]);
    343     }
    344     JXL_CHECK(cinfo->Ss == scan.Ss);
    345     JXL_CHECK(cinfo->Se == scan.Se);
    346     JXL_CHECK(cinfo->Ah == scan.Ah);
    347     JXL_CHECK(cinfo->Al == scan.Al);
    348   }
    349   if (jparams.restart_interval > 0) {
    350     JXL_CHECK(cinfo->restart_interval == jparams.restart_interval);
    351   } else if (jparams.restart_in_rows > 0) {
    352     JXL_CHECK(cinfo->restart_interval ==
    353               jparams.restart_in_rows * cinfo->MCUs_per_row);
    354   }
    355   if (jparams.progressive_mode == 0 && jparams.optimize_coding == 0) {
    356     if (cinfo->jpeg_color_space == JCS_RGB) {
    357       JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
    358       JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0);
    359       JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0);
    360       JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
    361       JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0);
    362       JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0);
    363     } else if (cinfo->jpeg_color_space == JCS_YCbCr) {
    364       JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
    365       JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1);
    366       JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1);
    367       JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
    368       JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1);
    369       JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1);
    370     } else if (cinfo->jpeg_color_space == JCS_CMYK) {
    371       JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
    372       JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 0);
    373       JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 0);
    374       JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0);
    375       JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
    376       JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 0);
    377       JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 0);
    378       JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0);
    379     } else if (cinfo->jpeg_color_space == JCS_YCCK) {
    380       JXL_CHECK(cinfo->comp_info[0].dc_tbl_no == 0);
    381       JXL_CHECK(cinfo->comp_info[1].dc_tbl_no == 1);
    382       JXL_CHECK(cinfo->comp_info[2].dc_tbl_no == 1);
    383       JXL_CHECK(cinfo->comp_info[3].dc_tbl_no == 0);
    384       JXL_CHECK(cinfo->comp_info[0].ac_tbl_no == 0);
    385       JXL_CHECK(cinfo->comp_info[1].ac_tbl_no == 1);
    386       JXL_CHECK(cinfo->comp_info[2].ac_tbl_no == 1);
    387       JXL_CHECK(cinfo->comp_info[3].ac_tbl_no == 0);
    388     }
    389     if (jparams.use_flat_dc_luma_code) {
    390       JHUFF_TBL* tbl = cinfo->dc_huff_tbl_ptrs[0];
    391       jxl::msan::UnpoisonMemory(tbl, sizeof(*tbl));
    392       for (int i = 0; i < 15; ++i) {
    393         JXL_CHECK(tbl->huffval[i] == i);
    394       }
    395     }
    396   }
    397 }
    398 
    399 void UnmapColors(uint8_t* row, size_t xsize, int components,
    400                  JSAMPARRAY colormap, size_t num_colors) {
    401   JXL_CHECK(colormap != nullptr);
    402   std::vector<uint8_t> tmp(xsize * components);
    403   for (size_t x = 0; x < xsize; ++x) {
    404     JXL_CHECK(row[x] < num_colors);
    405     for (int c = 0; c < components; ++c) {
    406       tmp[x * components + c] = colormap[c][row[x]];
    407     }
    408   }
    409   memcpy(row, tmp.data(), tmp.size());
    410 }
    411 
    412 void CopyCoefficients(j_decompress_ptr cinfo, jvirt_barray_ptr* coef_arrays,
    413                       TestImage* output) {
    414   output->xsize = cinfo->image_width;
    415   output->ysize = cinfo->image_height;
    416   output->components = cinfo->num_components;
    417   output->color_space = cinfo->out_color_space;
    418   j_common_ptr comptr = reinterpret_cast<j_common_ptr>(cinfo);
    419   for (int c = 0; c < cinfo->num_components; ++c) {
    420     jpeg_component_info* comp = &cinfo->comp_info[c];
    421     std::vector<JCOEF> coeffs(comp->width_in_blocks * comp->height_in_blocks *
    422                               DCTSIZE2);
    423     for (size_t by = 0; by < comp->height_in_blocks; ++by) {
    424       JBLOCKARRAY ba = (*cinfo->mem->access_virt_barray)(comptr, coef_arrays[c],
    425                                                          by, 1, TRUE);
    426       size_t stride = comp->width_in_blocks * sizeof(JBLOCK);
    427       size_t offset = by * comp->width_in_blocks * DCTSIZE2;
    428       memcpy(&coeffs[offset], ba[0], stride);
    429     }
    430     output->coeffs.emplace_back(std::move(coeffs));
    431   }
    432 }