libjxl

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

decode.cc (37293B)


      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/decode.h"
      7 
      8 #include <string.h>
      9 
     10 #include <vector>
     11 
     12 #include "lib/jpegli/color_quantize.h"
     13 #include "lib/jpegli/decode_internal.h"
     14 #include "lib/jpegli/decode_marker.h"
     15 #include "lib/jpegli/decode_scan.h"
     16 #include "lib/jpegli/error.h"
     17 #include "lib/jpegli/memory_manager.h"
     18 #include "lib/jpegli/render.h"
     19 #include "lib/jxl/base/byte_order.h"
     20 #include "lib/jxl/base/status.h"
     21 
     22 namespace jpegli {
     23 
     24 void InitializeImage(j_decompress_ptr cinfo) {
     25   cinfo->restart_interval = 0;
     26   cinfo->saw_JFIF_marker = FALSE;
     27   cinfo->JFIF_major_version = 1;
     28   cinfo->JFIF_minor_version = 1;
     29   cinfo->density_unit = 0;
     30   cinfo->X_density = 1;
     31   cinfo->Y_density = 1;
     32   cinfo->saw_Adobe_marker = FALSE;
     33   cinfo->Adobe_transform = 0;
     34   cinfo->CCIR601_sampling = FALSE;  // not used
     35   cinfo->marker_list = nullptr;
     36   cinfo->comp_info = nullptr;
     37   cinfo->input_scan_number = 0;
     38   cinfo->input_iMCU_row = 0;
     39   cinfo->output_scan_number = 0;
     40   cinfo->output_iMCU_row = 0;
     41   cinfo->output_scanline = 0;
     42   cinfo->unread_marker = 0;
     43   cinfo->coef_bits = nullptr;
     44   // We set all these to zero since we don't yet support arithmetic coding.
     45   memset(cinfo->arith_dc_L, 0, sizeof(cinfo->arith_dc_L));
     46   memset(cinfo->arith_dc_U, 0, sizeof(cinfo->arith_dc_U));
     47   memset(cinfo->arith_ac_K, 0, sizeof(cinfo->arith_ac_K));
     48   // Initialize the private fields.
     49   jpeg_decomp_master* m = cinfo->master;
     50   m->input_buffer_.clear();
     51   m->input_buffer_pos_ = 0;
     52   m->codestream_bits_ahead_ = 0;
     53   m->is_multiscan_ = false;
     54   m->found_soi_ = false;
     55   m->found_dri_ = false;
     56   m->found_sof_ = false;
     57   m->found_eoi_ = false;
     58   m->icc_index_ = 0;
     59   m->icc_total_ = 0;
     60   m->icc_profile_.clear();
     61   memset(m->dc_huff_lut_, 0, sizeof(m->dc_huff_lut_));
     62   memset(m->ac_huff_lut_, 0, sizeof(m->ac_huff_lut_));
     63   // Initialize the values to an invalid symbol so that we can recognize it
     64   // when reading the bit stream using a Huffman code with space > 0.
     65   for (size_t i = 0; i < kAllHuffLutSize; ++i) {
     66     m->dc_huff_lut_[i].bits = 0;
     67     m->dc_huff_lut_[i].value = 0xffff;
     68     m->ac_huff_lut_[i].bits = 0;
     69     m->ac_huff_lut_[i].value = 0xffff;
     70   }
     71   m->colormap_lut_ = nullptr;
     72   m->pixels_ = nullptr;
     73   m->scanlines_ = nullptr;
     74   m->regenerate_inverse_colormap_ = true;
     75   for (int i = 0; i < kMaxComponents; ++i) {
     76     m->dither_[i] = nullptr;
     77     m->error_row_[i] = nullptr;
     78   }
     79   m->output_passes_done_ = 0;
     80   m->xoffset_ = 0;
     81   m->dequant_ = nullptr;
     82 }
     83 
     84 void InitializeDecompressParams(j_decompress_ptr cinfo) {
     85   cinfo->jpeg_color_space = JCS_UNKNOWN;
     86   cinfo->out_color_space = JCS_UNKNOWN;
     87   cinfo->scale_num = 1;
     88   cinfo->scale_denom = 1;
     89   cinfo->output_gamma = 0.0f;
     90   cinfo->buffered_image = FALSE;
     91   cinfo->raw_data_out = FALSE;
     92   cinfo->dct_method = JDCT_DEFAULT;
     93   cinfo->do_fancy_upsampling = TRUE;
     94   cinfo->do_block_smoothing = TRUE;
     95   cinfo->quantize_colors = FALSE;
     96   cinfo->dither_mode = JDITHER_FS;
     97   cinfo->two_pass_quantize = TRUE;
     98   cinfo->desired_number_of_colors = 256;
     99   cinfo->enable_1pass_quant = FALSE;
    100   cinfo->enable_external_quant = FALSE;
    101   cinfo->enable_2pass_quant = FALSE;
    102   cinfo->actual_number_of_colors = 0;
    103   cinfo->colormap = nullptr;
    104 }
    105 
    106 void InitProgressMonitor(j_decompress_ptr cinfo, bool coef_only) {
    107   if (!cinfo->progress) return;
    108   jpeg_decomp_master* m = cinfo->master;
    109   int nc = cinfo->num_components;
    110   int estimated_num_scans =
    111       cinfo->progressive_mode ? 2 + 3 * nc : (m->is_multiscan_ ? nc : 1);
    112   cinfo->progress->pass_limit = cinfo->total_iMCU_rows * estimated_num_scans;
    113   cinfo->progress->pass_counter = 0;
    114   if (coef_only) {
    115     cinfo->progress->total_passes = 1;
    116   } else {
    117     int input_passes = !cinfo->buffered_image && m->is_multiscan_ ? 1 : 0;
    118     bool two_pass_quant = FROM_JXL_BOOL(cinfo->quantize_colors) &&
    119                           (cinfo->colormap != nullptr) &&
    120                           FROM_JXL_BOOL(cinfo->two_pass_quantize) &&
    121                           FROM_JXL_BOOL(cinfo->enable_2pass_quant);
    122     cinfo->progress->total_passes = input_passes + (two_pass_quant ? 2 : 1);
    123   }
    124   cinfo->progress->completed_passes = 0;
    125 }
    126 
    127 void InitProgressMonitorForOutput(j_decompress_ptr cinfo) {
    128   if (!cinfo->progress) return;
    129   jpeg_decomp_master* m = cinfo->master;
    130   int passes_per_output = cinfo->enable_2pass_quant ? 2 : 1;
    131   int output_passes_left = cinfo->buffered_image && !m->found_eoi_ ? 2 : 1;
    132   cinfo->progress->total_passes =
    133       m->output_passes_done_ + passes_per_output * output_passes_left;
    134   cinfo->progress->completed_passes = m->output_passes_done_;
    135 }
    136 
    137 void ProgressMonitorInputPass(j_decompress_ptr cinfo) {
    138   if (!cinfo->progress) return;
    139   cinfo->progress->pass_counter =
    140       ((cinfo->input_scan_number - 1) * cinfo->total_iMCU_rows +
    141        cinfo->input_iMCU_row);
    142   if (cinfo->progress->pass_counter > cinfo->progress->pass_limit) {
    143     cinfo->progress->pass_limit =
    144         cinfo->input_scan_number * cinfo->total_iMCU_rows;
    145   }
    146   (*cinfo->progress->progress_monitor)(reinterpret_cast<j_common_ptr>(cinfo));
    147 }
    148 
    149 void ProgressMonitorOutputPass(j_decompress_ptr cinfo) {
    150   if (!cinfo->progress) return;
    151   jpeg_decomp_master* m = cinfo->master;
    152   int input_passes = !cinfo->buffered_image && m->is_multiscan_ ? 1 : 0;
    153   cinfo->progress->pass_counter = cinfo->output_scanline;
    154   cinfo->progress->pass_limit = cinfo->output_height;
    155   cinfo->progress->completed_passes = input_passes + m->output_passes_done_;
    156   (*cinfo->progress->progress_monitor)(reinterpret_cast<j_common_ptr>(cinfo));
    157 }
    158 
    159 void BuildHuffmanLookupTable(j_decompress_ptr cinfo, JHUFF_TBL* table,
    160                              HuffmanTableEntry* huff_lut) {
    161   uint32_t counts[kJpegHuffmanMaxBitLength + 1] = {};
    162   counts[0] = 0;
    163   int total_count = 0;
    164   int space = 1 << kJpegHuffmanMaxBitLength;
    165   int max_depth = 1;
    166   for (size_t i = 1; i <= kJpegHuffmanMaxBitLength; ++i) {
    167     int count = table->bits[i];
    168     if (count != 0) {
    169       max_depth = i;
    170     }
    171     counts[i] = count;
    172     total_count += count;
    173     space -= count * (1 << (kJpegHuffmanMaxBitLength - i));
    174   }
    175   uint32_t values[kJpegHuffmanAlphabetSize + 1] = {};
    176   uint8_t values_seen[256] = {0};
    177   for (int i = 0; i < total_count; ++i) {
    178     int value = table->huffval[i];
    179     if (values_seen[value]) {
    180       return JPEGLI_ERROR("Duplicate Huffman code value %d", value);
    181     }
    182     values_seen[value] = 1;
    183     values[i] = value;
    184   }
    185   // Add an invalid symbol that will have the all 1 code.
    186   ++counts[max_depth];
    187   values[total_count] = kJpegHuffmanAlphabetSize;
    188   space -= (1 << (kJpegHuffmanMaxBitLength - max_depth));
    189   if (space < 0) {
    190     JPEGLI_ERROR("Invalid Huffman code lengths.");
    191   } else if (space > 0 && huff_lut[0].value != 0xffff) {
    192     // Re-initialize the values to an invalid symbol so that we can recognize
    193     // it when reading the bit stream using a Huffman code with space > 0.
    194     for (int i = 0; i < kJpegHuffmanLutSize; ++i) {
    195       huff_lut[i].bits = 0;
    196       huff_lut[i].value = 0xffff;
    197     }
    198   }
    199   BuildJpegHuffmanTable(&counts[0], &values[0], huff_lut);
    200 }
    201 
    202 void PrepareForScan(j_decompress_ptr cinfo) {
    203   jpeg_decomp_master* m = cinfo->master;
    204   for (int i = 0; i < cinfo->comps_in_scan; ++i) {
    205     int comp_idx = cinfo->cur_comp_info[i]->component_index;
    206     int* prev_coef_bits = cinfo->coef_bits[comp_idx + cinfo->num_components];
    207     for (int k = std::min(cinfo->Ss, 1); k <= std::max(cinfo->Se, 9); k++) {
    208       prev_coef_bits[k] =
    209           (cinfo->input_scan_number > 0) ? cinfo->coef_bits[comp_idx][k] : 0;
    210     }
    211     for (int k = cinfo->Ss; k <= cinfo->Se; ++k) {
    212       cinfo->coef_bits[comp_idx][k] = cinfo->Al;
    213     }
    214   }
    215   AddStandardHuffmanTables(reinterpret_cast<j_common_ptr>(cinfo),
    216                            /*is_dc=*/false);
    217   AddStandardHuffmanTables(reinterpret_cast<j_common_ptr>(cinfo),
    218                            /*is_dc=*/true);
    219   // Check that all the Huffman tables needed for this scan are defined and
    220   // build derived lookup tables.
    221   for (int i = 0; i < cinfo->comps_in_scan; ++i) {
    222     if (cinfo->Ss == 0) {
    223       int dc_tbl_idx = cinfo->cur_comp_info[i]->dc_tbl_no;
    224       JHUFF_TBL* table = cinfo->dc_huff_tbl_ptrs[dc_tbl_idx];
    225       HuffmanTableEntry* huff_lut =
    226           &m->dc_huff_lut_[dc_tbl_idx * kJpegHuffmanLutSize];
    227       if (!table) {
    228         return JPEGLI_ERROR("DC Huffman table %d not found", dc_tbl_idx);
    229       }
    230       BuildHuffmanLookupTable(cinfo, table, huff_lut);
    231     }
    232     if (cinfo->Se > 0) {
    233       int ac_tbl_idx = cinfo->cur_comp_info[i]->ac_tbl_no;
    234       JHUFF_TBL* table = cinfo->ac_huff_tbl_ptrs[ac_tbl_idx];
    235       HuffmanTableEntry* huff_lut =
    236           &m->ac_huff_lut_[ac_tbl_idx * kJpegHuffmanLutSize];
    237       if (!table) {
    238         return JPEGLI_ERROR("AC Huffman table %d not found", ac_tbl_idx);
    239       }
    240       BuildHuffmanLookupTable(cinfo, table, huff_lut);
    241     }
    242   }
    243   // Copy quantization tables into comp_info.
    244   for (int i = 0; i < cinfo->comps_in_scan; ++i) {
    245     jpeg_component_info* comp = cinfo->cur_comp_info[i];
    246     if (comp->quant_table == nullptr) {
    247       comp->quant_table = Allocate<JQUANT_TBL>(cinfo, 1, JPOOL_IMAGE);
    248       memcpy(comp->quant_table, cinfo->quant_tbl_ptrs[comp->quant_tbl_no],
    249              sizeof(JQUANT_TBL));
    250     }
    251   }
    252   if (cinfo->comps_in_scan == 1) {
    253     const auto& comp = *cinfo->cur_comp_info[0];
    254     cinfo->MCUs_per_row = DivCeil(cinfo->image_width * comp.h_samp_factor,
    255                                   cinfo->max_h_samp_factor * DCTSIZE);
    256     cinfo->MCU_rows_in_scan = DivCeil(cinfo->image_height * comp.v_samp_factor,
    257                                       cinfo->max_v_samp_factor * DCTSIZE);
    258     m->mcu_rows_per_iMCU_row_ = cinfo->cur_comp_info[0]->v_samp_factor;
    259   } else {
    260     cinfo->MCU_rows_in_scan = cinfo->total_iMCU_rows;
    261     cinfo->MCUs_per_row = m->iMCU_cols_;
    262     m->mcu_rows_per_iMCU_row_ = 1;
    263     size_t mcu_size = 0;
    264     for (int i = 0; i < cinfo->comps_in_scan; ++i) {
    265       jpeg_component_info* comp = cinfo->cur_comp_info[i];
    266       mcu_size += comp->h_samp_factor * comp->v_samp_factor;
    267     }
    268     if (mcu_size > D_MAX_BLOCKS_IN_MCU) {
    269       JPEGLI_ERROR("MCU size too big");
    270     }
    271   }
    272   memset(m->last_dc_coeff_, 0, sizeof(m->last_dc_coeff_));
    273   m->restarts_to_go_ = cinfo->restart_interval;
    274   m->next_restart_marker_ = 0;
    275   m->eobrun_ = -1;
    276   m->scan_mcu_row_ = 0;
    277   m->scan_mcu_col_ = 0;
    278   m->codestream_bits_ahead_ = 0;
    279   ++cinfo->input_scan_number;
    280   cinfo->input_iMCU_row = 0;
    281   PrepareForiMCURow(cinfo);
    282   cinfo->global_state = kDecProcessScan;
    283 }
    284 
    285 int ConsumeInput(j_decompress_ptr cinfo) {
    286   jpeg_decomp_master* m = cinfo->master;
    287   if (cinfo->global_state == kDecProcessScan && m->streaming_mode_ &&
    288       cinfo->input_iMCU_row > cinfo->output_iMCU_row) {
    289     // Prevent input from getting ahead of output in streaming mode.
    290     return JPEG_SUSPENDED;
    291   }
    292   jpeg_source_mgr* src = cinfo->src;
    293   int status;
    294   for (;;) {
    295     const uint8_t* data;
    296     size_t len;
    297     if (m->input_buffer_.empty()) {
    298       data = cinfo->src->next_input_byte;
    299       len = cinfo->src->bytes_in_buffer;
    300     } else {
    301       data = &m->input_buffer_[m->input_buffer_pos_];
    302       len = m->input_buffer_.size() - m->input_buffer_pos_;
    303     }
    304     size_t pos = 0;
    305     if (cinfo->global_state == kDecProcessScan) {
    306       status = ProcessScan(cinfo, data, len, &pos, &m->codestream_bits_ahead_);
    307     } else {
    308       status = ProcessMarkers(cinfo, data, len, &pos);
    309     }
    310     if (m->input_buffer_.empty()) {
    311       cinfo->src->next_input_byte += pos;
    312       cinfo->src->bytes_in_buffer -= pos;
    313     } else {
    314       m->input_buffer_pos_ += pos;
    315       size_t bytes_left = m->input_buffer_.size() - m->input_buffer_pos_;
    316       if (bytes_left <= src->bytes_in_buffer) {
    317         src->next_input_byte += (src->bytes_in_buffer - bytes_left);
    318         src->bytes_in_buffer = bytes_left;
    319         m->input_buffer_.clear();
    320         m->input_buffer_pos_ = 0;
    321       }
    322     }
    323     if (status == kHandleRestart) {
    324       JXL_DASSERT(m->input_buffer_.size() <=
    325                   m->input_buffer_pos_ + src->bytes_in_buffer);
    326       m->input_buffer_.clear();
    327       m->input_buffer_pos_ = 0;
    328       if (cinfo->unread_marker == 0xd0 + m->next_restart_marker_) {
    329         cinfo->unread_marker = 0;
    330       } else {
    331         if (!(*cinfo->src->resync_to_restart)(cinfo, m->next_restart_marker_)) {
    332           return JPEG_SUSPENDED;
    333         }
    334       }
    335       m->next_restart_marker_ += 1;
    336       m->next_restart_marker_ &= 0x7;
    337       m->restarts_to_go_ = cinfo->restart_interval;
    338       if (cinfo->unread_marker != 0) {
    339         JPEGLI_WARN("Failed to resync to next restart marker, skipping scan.");
    340         return JPEG_SCAN_COMPLETED;
    341       }
    342       continue;
    343     }
    344     if (status == kHandleMarkerProcessor) {
    345       JXL_DASSERT(m->input_buffer_.size() <=
    346                   m->input_buffer_pos_ + src->bytes_in_buffer);
    347       m->input_buffer_.clear();
    348       m->input_buffer_pos_ = 0;
    349       if (!(*GetMarkerProcessor(cinfo))(cinfo)) {
    350         return JPEG_SUSPENDED;
    351       }
    352       cinfo->unread_marker = 0;
    353       continue;
    354     }
    355     if (status != kNeedMoreInput) {
    356       break;
    357     }
    358     if (m->input_buffer_.empty()) {
    359       JXL_DASSERT(m->input_buffer_pos_ == 0);
    360       m->input_buffer_.assign(src->next_input_byte,
    361                               src->next_input_byte + src->bytes_in_buffer);
    362     }
    363     if (!(*cinfo->src->fill_input_buffer)(cinfo)) {
    364       m->input_buffer_.clear();
    365       m->input_buffer_pos_ = 0;
    366       return JPEG_SUSPENDED;
    367     }
    368     if (src->bytes_in_buffer == 0) {
    369       JPEGLI_ERROR("Empty input.");
    370     }
    371     m->input_buffer_.insert(m->input_buffer_.end(), src->next_input_byte,
    372                             src->next_input_byte + src->bytes_in_buffer);
    373   }
    374   if (status == JPEG_SCAN_COMPLETED) {
    375     cinfo->global_state = kDecProcessMarkers;
    376   } else if (status == JPEG_REACHED_SOS) {
    377     if (cinfo->global_state == kDecInHeader) {
    378       cinfo->global_state = kDecHeaderDone;
    379     } else {
    380       PrepareForScan(cinfo);
    381     }
    382   }
    383   return status;
    384 }
    385 
    386 bool IsInputReady(j_decompress_ptr cinfo) {
    387   if (cinfo->master->found_eoi_) {
    388     return true;
    389   }
    390   if (cinfo->input_scan_number > cinfo->output_scan_number) {
    391     return true;
    392   }
    393   if (cinfo->input_scan_number < cinfo->output_scan_number) {
    394     return false;
    395   }
    396   if (cinfo->input_iMCU_row == cinfo->total_iMCU_rows) {
    397     return true;
    398   }
    399   return cinfo->input_iMCU_row >
    400          cinfo->output_iMCU_row + (cinfo->master->streaming_mode_ ? 0 : 2);
    401 }
    402 
    403 bool ReadOutputPass(j_decompress_ptr cinfo) {
    404   jpeg_decomp_master* m = cinfo->master;
    405   if (!m->pixels_) {
    406     size_t stride = cinfo->out_color_components * cinfo->output_width;
    407     size_t num_samples = cinfo->output_height * stride;
    408     m->pixels_ = Allocate<uint8_t>(cinfo, num_samples, JPOOL_IMAGE);
    409     m->scanlines_ =
    410         Allocate<JSAMPROW>(cinfo, cinfo->output_height, JPOOL_IMAGE);
    411     for (size_t i = 0; i < cinfo->output_height; ++i) {
    412       m->scanlines_[i] = &m->pixels_[i * stride];
    413     }
    414   }
    415   size_t num_output_rows = 0;
    416   while (num_output_rows < cinfo->output_height) {
    417     if (IsInputReady(cinfo)) {
    418       ProgressMonitorOutputPass(cinfo);
    419       ProcessOutput(cinfo, &num_output_rows, m->scanlines_,
    420                     cinfo->output_height);
    421     } else if (ConsumeInput(cinfo) == JPEG_SUSPENDED) {
    422       return false;
    423     }
    424   }
    425   cinfo->output_scanline = 0;
    426   cinfo->output_iMCU_row = 0;
    427   return true;
    428 }
    429 
    430 boolean PrepareQuantizedOutput(j_decompress_ptr cinfo) {
    431   jpeg_decomp_master* m = cinfo->master;
    432   if (cinfo->raw_data_out) {
    433     JPEGLI_ERROR("Color quantization is not supported in raw data mode.");
    434   }
    435   if (m->output_data_type_ != JPEGLI_TYPE_UINT8) {
    436     JPEGLI_ERROR("Color quantization must use 8-bit mode.");
    437   }
    438   if (cinfo->colormap) {
    439     m->quant_mode_ = 3;
    440   } else if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
    441     m->quant_mode_ = 2;
    442   } else if (cinfo->enable_1pass_quant) {
    443     m->quant_mode_ = 1;
    444   } else {
    445     JPEGLI_ERROR("Invalid quantization mode change");
    446   }
    447   if (m->quant_mode_ > 1 && cinfo->dither_mode == JDITHER_ORDERED) {
    448     cinfo->dither_mode = JDITHER_FS;
    449   }
    450   if (m->quant_mode_ == 1) {
    451     ChooseColorMap1Pass(cinfo);
    452   } else if (m->quant_mode_ == 2) {
    453     m->quant_pass_ = 0;
    454     if (!ReadOutputPass(cinfo)) {
    455       return FALSE;
    456     }
    457     ChooseColorMap2Pass(cinfo);
    458   }
    459   if (m->quant_mode_ == 2 ||
    460       (m->quant_mode_ == 3 && m->regenerate_inverse_colormap_)) {
    461     CreateInverseColorMap(cinfo);
    462   }
    463   if (cinfo->dither_mode == JDITHER_ORDERED) {
    464     CreateOrderedDitherTables(cinfo);
    465   } else if (cinfo->dither_mode == JDITHER_FS) {
    466     InitFSDitherState(cinfo);
    467   }
    468   m->quant_pass_ = 1;
    469   return TRUE;
    470 }
    471 
    472 void AllocateCoefficientBuffer(j_decompress_ptr cinfo) {
    473   jpeg_decomp_master* m = cinfo->master;
    474   j_common_ptr comptr = reinterpret_cast<j_common_ptr>(cinfo);
    475   jvirt_barray_ptr* coef_arrays = jpegli::Allocate<jvirt_barray_ptr>(
    476       cinfo, cinfo->num_components, JPOOL_IMAGE);
    477   for (int c = 0; c < cinfo->num_components; ++c) {
    478     jpeg_component_info* comp = &cinfo->comp_info[c];
    479     size_t height_in_blocks =
    480         m->streaming_mode_ ? comp->v_samp_factor : comp->height_in_blocks;
    481     coef_arrays[c] = (*cinfo->mem->request_virt_barray)(
    482         comptr, JPOOL_IMAGE, TRUE, comp->width_in_blocks, height_in_blocks,
    483         comp->v_samp_factor);
    484   }
    485   cinfo->master->coef_arrays = coef_arrays;
    486   (*cinfo->mem->realize_virt_arrays)(comptr);
    487 }
    488 
    489 void AllocateOutputBuffers(j_decompress_ptr cinfo) {
    490   jpeg_decomp_master* m = cinfo->master;
    491   size_t iMCU_width = cinfo->max_h_samp_factor * m->min_scaled_dct_size;
    492   size_t output_stride = m->iMCU_cols_ * iMCU_width;
    493   m->need_context_rows_ = false;
    494   for (int c = 0; c < cinfo->num_components; ++c) {
    495     if (cinfo->do_fancy_upsampling && m->v_factor[c] == 2) {
    496       m->need_context_rows_ = true;
    497     }
    498   }
    499   for (int c = 0; c < cinfo->num_components; ++c) {
    500     const auto& comp = cinfo->comp_info[c];
    501     size_t cheight = comp.v_samp_factor * m->scaled_dct_size[c];
    502     int downsampled_width = output_stride / m->h_factor[c];
    503     m->raw_height_[c] = cinfo->total_iMCU_rows * cheight;
    504     if (m->need_context_rows_) {
    505       cheight *= 3;
    506     }
    507     m->raw_output_[c].Allocate(cinfo, cheight, downsampled_width);
    508   }
    509   int num_all_components =
    510       std::max(cinfo->out_color_components, cinfo->num_components);
    511   for (int c = 0; c < num_all_components; ++c) {
    512     m->render_output_[c].Allocate(cinfo, cinfo->max_v_samp_factor,
    513                                   output_stride);
    514   }
    515   m->idct_scratch_ = Allocate<float>(cinfo, 5 * DCTSIZE2, JPOOL_IMAGE_ALIGNED);
    516   // Padding for horizontal chroma upsampling.
    517   constexpr size_t kPaddingLeft = 64;
    518   constexpr size_t kPaddingRight = 64;
    519   m->upsample_scratch_ = Allocate<float>(
    520       cinfo, output_stride + kPaddingLeft + kPaddingRight, JPOOL_IMAGE_ALIGNED);
    521   size_t bytes_per_sample = jpegli_bytes_per_sample(m->output_data_type_);
    522   size_t bytes_per_pixel = cinfo->out_color_components * bytes_per_sample;
    523   size_t scratch_stride = RoundUpTo(output_stride, HWY_ALIGNMENT);
    524   m->output_scratch_ = Allocate<uint8_t>(
    525       cinfo, bytes_per_pixel * scratch_stride, JPOOL_IMAGE_ALIGNED);
    526   m->smoothing_scratch_ =
    527       Allocate<int16_t>(cinfo, DCTSIZE2, JPOOL_IMAGE_ALIGNED);
    528   size_t coeffs_per_block = cinfo->num_components * DCTSIZE2;
    529   m->nonzeros_ = Allocate<int>(cinfo, coeffs_per_block, JPOOL_IMAGE_ALIGNED);
    530   m->sumabs_ = Allocate<int>(cinfo, coeffs_per_block, JPOOL_IMAGE_ALIGNED);
    531   m->biases_ = Allocate<float>(cinfo, coeffs_per_block, JPOOL_IMAGE_ALIGNED);
    532   m->dequant_ = Allocate<float>(cinfo, coeffs_per_block, JPOOL_IMAGE_ALIGNED);
    533   memset(m->dequant_, 0, coeffs_per_block * sizeof(float));
    534 }
    535 
    536 }  // namespace jpegli
    537 
    538 void jpegli_CreateDecompress(j_decompress_ptr cinfo, int version,
    539                              size_t structsize) {
    540   cinfo->mem = nullptr;
    541   if (structsize != sizeof(*cinfo)) {
    542     JPEGLI_ERROR("jpeg_decompress_struct has wrong size.");
    543   }
    544   jpegli::InitMemoryManager(reinterpret_cast<j_common_ptr>(cinfo));
    545   cinfo->is_decompressor = TRUE;
    546   cinfo->progress = nullptr;
    547   cinfo->src = nullptr;
    548   for (auto& quant_tbl_ptr : cinfo->quant_tbl_ptrs) {
    549     quant_tbl_ptr = nullptr;
    550   }
    551   for (int i = 0; i < NUM_HUFF_TBLS; i++) {
    552     cinfo->dc_huff_tbl_ptrs[i] = nullptr;
    553     cinfo->ac_huff_tbl_ptrs[i] = nullptr;
    554   }
    555   cinfo->global_state = jpegli::kDecStart;
    556   cinfo->sample_range_limit = nullptr;  // not used
    557   cinfo->rec_outbuf_height = 1;         // output works with any buffer height
    558   cinfo->master = new jpeg_decomp_master;
    559   jpeg_decomp_master* m = cinfo->master;
    560   for (auto& app_marker_parser : m->app_marker_parsers) {
    561     app_marker_parser = nullptr;
    562   }
    563   m->com_marker_parser = nullptr;
    564   memset(m->markers_to_save_, 0, sizeof(m->markers_to_save_));
    565   jpegli::InitializeDecompressParams(cinfo);
    566   jpegli::InitializeImage(cinfo);
    567 }
    568 
    569 void jpegli_destroy_decompress(j_decompress_ptr cinfo) {
    570   jpegli_destroy(reinterpret_cast<j_common_ptr>(cinfo));
    571 }
    572 
    573 void jpegli_abort_decompress(j_decompress_ptr cinfo) {
    574   jpegli_abort(reinterpret_cast<j_common_ptr>(cinfo));
    575 }
    576 
    577 void jpegli_save_markers(j_decompress_ptr cinfo, int marker_code,
    578                          unsigned int length_limit) {
    579   // TODO(szabadka) Limit our memory usage by taking into account length_limit.
    580   jpeg_decomp_master* m = cinfo->master;
    581   if (marker_code < 0xe0) {
    582     JPEGLI_ERROR("jpegli_save_markers: invalid marker code %d", marker_code);
    583   }
    584   m->markers_to_save_[marker_code - 0xe0] = 1;
    585 }
    586 
    587 void jpegli_set_marker_processor(j_decompress_ptr cinfo, int marker_code,
    588                                  jpeg_marker_parser_method routine) {
    589   jpeg_decomp_master* m = cinfo->master;
    590   if (marker_code == 0xfe) {
    591     m->com_marker_parser = routine;
    592   } else if (marker_code >= 0xe0 && marker_code <= 0xef) {
    593     m->app_marker_parsers[marker_code - 0xe0] = routine;
    594   } else {
    595     JPEGLI_ERROR("jpegli_set_marker_processor: invalid marker code %d",
    596                  marker_code);
    597   }
    598 }
    599 
    600 int jpegli_consume_input(j_decompress_ptr cinfo) {
    601   if (cinfo->global_state == jpegli::kDecStart) {
    602     (*cinfo->err->reset_error_mgr)(reinterpret_cast<j_common_ptr>(cinfo));
    603     (*cinfo->src->init_source)(cinfo);
    604     jpegli::InitializeDecompressParams(cinfo);
    605     jpegli::InitializeImage(cinfo);
    606     cinfo->global_state = jpegli::kDecInHeader;
    607   }
    608   if (cinfo->global_state == jpegli::kDecHeaderDone) {
    609     return JPEG_REACHED_SOS;
    610   }
    611   if (cinfo->master->found_eoi_) {
    612     return JPEG_REACHED_EOI;
    613   }
    614   if (cinfo->global_state == jpegli::kDecInHeader ||
    615       cinfo->global_state == jpegli::kDecProcessMarkers ||
    616       cinfo->global_state == jpegli::kDecProcessScan) {
    617     return jpegli::ConsumeInput(cinfo);
    618   }
    619   JPEGLI_ERROR("Unexpected state %d", cinfo->global_state);
    620   return JPEG_REACHED_EOI;  // return value does not matter
    621 }
    622 
    623 int jpegli_read_header(j_decompress_ptr cinfo, boolean require_image) {
    624   if (cinfo->global_state != jpegli::kDecStart &&
    625       cinfo->global_state != jpegli::kDecInHeader) {
    626     JPEGLI_ERROR("jpegli_read_header: unexpected state %d",
    627                  cinfo->global_state);
    628   }
    629   if (cinfo->src == nullptr) {
    630     JPEGLI_ERROR("Missing source.");
    631   }
    632   for (;;) {
    633     int retcode = jpegli_consume_input(cinfo);
    634     if (retcode == JPEG_SUSPENDED) {
    635       return retcode;
    636     } else if (retcode == JPEG_REACHED_SOS) {
    637       break;
    638     } else if (retcode == JPEG_REACHED_EOI) {
    639       if (require_image) {
    640         JPEGLI_ERROR("jpegli_read_header: unexpected EOI marker.");
    641       }
    642       jpegli_abort_decompress(cinfo);
    643       return JPEG_HEADER_TABLES_ONLY;
    644     }
    645   };
    646   return JPEG_HEADER_OK;
    647 }
    648 
    649 boolean jpegli_read_icc_profile(j_decompress_ptr cinfo, JOCTET** icc_data_ptr,
    650                                 unsigned int* icc_data_len) {
    651   if (cinfo->global_state == jpegli::kDecStart ||
    652       cinfo->global_state == jpegli::kDecInHeader) {
    653     JPEGLI_ERROR("jpegli_read_icc_profile: unexpected state %d",
    654                  cinfo->global_state);
    655   }
    656   if (icc_data_ptr == nullptr || icc_data_len == nullptr) {
    657     JPEGLI_ERROR("jpegli_read_icc_profile: invalid output buffer");
    658   }
    659   jpeg_decomp_master* m = cinfo->master;
    660   if (m->icc_profile_.empty()) {
    661     *icc_data_ptr = nullptr;
    662     *icc_data_len = 0;
    663     return FALSE;
    664   }
    665   *icc_data_len = m->icc_profile_.size();
    666   *icc_data_ptr = static_cast<JOCTET*>(malloc(*icc_data_len));
    667   if (*icc_data_ptr == nullptr) {
    668     JPEGLI_ERROR("jpegli_read_icc_profile: Out of memory");
    669   }
    670   memcpy(*icc_data_ptr, m->icc_profile_.data(), *icc_data_len);
    671   return TRUE;
    672 }
    673 
    674 void jpegli_core_output_dimensions(j_decompress_ptr cinfo) {
    675   jpeg_decomp_master* m = cinfo->master;
    676   if (!m->found_sof_) {
    677     JPEGLI_ERROR("No SOF marker found.");
    678   }
    679   if (cinfo->raw_data_out) {
    680     if (cinfo->scale_num != 1 || cinfo->scale_denom != 1) {
    681       JPEGLI_ERROR("Output scaling is not supported in raw output mode");
    682     }
    683   }
    684   if (cinfo->scale_num != 1 || cinfo->scale_denom != 1) {
    685     int dctsize = 16;
    686     while (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * (dctsize - 1)) {
    687       --dctsize;
    688     }
    689     m->min_scaled_dct_size = dctsize;
    690     cinfo->output_width =
    691         jpegli::DivCeil(cinfo->image_width * dctsize, DCTSIZE);
    692     cinfo->output_height =
    693         jpegli::DivCeil(cinfo->image_height * dctsize, DCTSIZE);
    694     for (int c = 0; c < cinfo->num_components; ++c) {
    695       m->scaled_dct_size[c] = m->min_scaled_dct_size;
    696     }
    697   } else {
    698     cinfo->output_width = cinfo->image_width;
    699     cinfo->output_height = cinfo->image_height;
    700     m->min_scaled_dct_size = DCTSIZE;
    701     for (int c = 0; c < cinfo->num_components; ++c) {
    702       m->scaled_dct_size[c] = DCTSIZE;
    703     }
    704   }
    705 }
    706 
    707 void jpegli_calc_output_dimensions(j_decompress_ptr cinfo) {
    708   jpeg_decomp_master* m = cinfo->master;
    709   jpegli_core_output_dimensions(cinfo);
    710   for (int c = 0; c < cinfo->num_components; ++c) {
    711     jpeg_component_info* comp = &cinfo->comp_info[c];
    712     m->h_factor[c] = cinfo->max_h_samp_factor / comp->h_samp_factor;
    713     m->v_factor[c] = cinfo->max_v_samp_factor / comp->v_samp_factor;
    714   }
    715   if (cinfo->scale_num != 1 || cinfo->scale_denom != 1) {
    716     for (int c = 0; c < cinfo->num_components; ++c) {
    717       // Prefer IDCT scaling over 2x upsampling.
    718       while (m->scaled_dct_size[c] < DCTSIZE && (m->v_factor[c] % 2) == 0 &&
    719              (m->h_factor[c] % 2) == 0) {
    720         m->scaled_dct_size[c] *= 2;
    721         m->v_factor[c] /= 2;
    722         m->h_factor[c] /= 2;
    723       }
    724     }
    725   }
    726   if (cinfo->out_color_space == JCS_GRAYSCALE) {
    727     cinfo->out_color_components = 1;
    728   } else if (cinfo->out_color_space == JCS_RGB ||
    729              cinfo->out_color_space == JCS_YCbCr) {
    730     cinfo->out_color_components = 3;
    731   } else if (cinfo->out_color_space == JCS_CMYK ||
    732              cinfo->out_color_space == JCS_YCCK) {
    733     cinfo->out_color_components = 4;
    734   } else {
    735     cinfo->out_color_components = cinfo->num_components;
    736   }
    737   cinfo->output_components =
    738       cinfo->quantize_colors ? 1 : cinfo->out_color_components;
    739   cinfo->rec_outbuf_height = 1;
    740 }
    741 
    742 boolean jpegli_has_multiple_scans(j_decompress_ptr cinfo) {
    743   if (cinfo->input_scan_number == 0) {
    744     JPEGLI_ERROR("No SOS marker found.");
    745   }
    746   return TO_JXL_BOOL(cinfo->master->is_multiscan_);
    747 }
    748 
    749 boolean jpegli_input_complete(j_decompress_ptr cinfo) {
    750   return TO_JXL_BOOL(cinfo->master->found_eoi_);
    751 }
    752 
    753 boolean jpegli_start_decompress(j_decompress_ptr cinfo) {
    754   jpeg_decomp_master* m = cinfo->master;
    755   if (cinfo->global_state == jpegli::kDecHeaderDone) {
    756     m->streaming_mode_ = !m->is_multiscan_ &&
    757                          !FROM_JXL_BOOL(cinfo->buffered_image) &&
    758                          (!FROM_JXL_BOOL(cinfo->quantize_colors) ||
    759                           !FROM_JXL_BOOL(cinfo->two_pass_quantize));
    760     jpegli::AllocateCoefficientBuffer(cinfo);
    761     jpegli_calc_output_dimensions(cinfo);
    762     jpegli::PrepareForScan(cinfo);
    763     if (cinfo->quantize_colors) {
    764       if (cinfo->colormap != nullptr) {
    765         cinfo->enable_external_quant = TRUE;
    766       } else if (cinfo->two_pass_quantize &&
    767                  cinfo->out_color_space == JCS_RGB) {
    768         cinfo->enable_2pass_quant = TRUE;
    769       } else {
    770         cinfo->enable_1pass_quant = TRUE;
    771       }
    772     }
    773     jpegli::InitProgressMonitor(cinfo, /*coef_only=*/false);
    774     jpegli::AllocateOutputBuffers(cinfo);
    775     if (cinfo->buffered_image == TRUE) {
    776       cinfo->output_scan_number = 0;
    777       return TRUE;
    778     }
    779   } else if (!m->is_multiscan_) {
    780     JPEGLI_ERROR("jpegli_start_decompress: unexpected state %d",
    781                  cinfo->global_state);
    782   }
    783   if (m->is_multiscan_) {
    784     if (cinfo->global_state != jpegli::kDecProcessScan &&
    785         cinfo->global_state != jpegli::kDecProcessMarkers) {
    786       JPEGLI_ERROR("jpegli_start_decompress: unexpected state %d",
    787                    cinfo->global_state);
    788     }
    789     while (!m->found_eoi_) {
    790       jpegli::ProgressMonitorInputPass(cinfo);
    791       if (jpegli::ConsumeInput(cinfo) == JPEG_SUSPENDED) {
    792         return FALSE;
    793       }
    794     }
    795   }
    796   cinfo->output_scan_number = cinfo->input_scan_number;
    797   jpegli::PrepareForOutput(cinfo);
    798   if (cinfo->quantize_colors) {
    799     return jpegli::PrepareQuantizedOutput(cinfo);
    800   } else {
    801     return TRUE;
    802   }
    803 }
    804 
    805 boolean jpegli_start_output(j_decompress_ptr cinfo, int scan_number) {
    806   jpeg_decomp_master* m = cinfo->master;
    807   if (!cinfo->buffered_image) {
    808     JPEGLI_ERROR("jpegli_start_output: buffered image mode was not set");
    809   }
    810   if (cinfo->global_state != jpegli::kDecProcessScan &&
    811       cinfo->global_state != jpegli::kDecProcessMarkers) {
    812     JPEGLI_ERROR("jpegli_start_output: unexpected state %d",
    813                  cinfo->global_state);
    814   }
    815   cinfo->output_scan_number = std::max(1, scan_number);
    816   if (m->found_eoi_) {
    817     cinfo->output_scan_number =
    818         std::min(cinfo->output_scan_number, cinfo->input_scan_number);
    819   }
    820   jpegli::InitProgressMonitorForOutput(cinfo);
    821   jpegli::PrepareForOutput(cinfo);
    822   if (cinfo->quantize_colors) {
    823     return jpegli::PrepareQuantizedOutput(cinfo);
    824   } else {
    825     return TRUE;
    826   }
    827 }
    828 
    829 boolean jpegli_finish_output(j_decompress_ptr cinfo) {
    830   if (!cinfo->buffered_image) {
    831     JPEGLI_ERROR("jpegli_finish_output: buffered image mode was not set");
    832   }
    833   if (cinfo->global_state != jpegli::kDecProcessScan &&
    834       cinfo->global_state != jpegli::kDecProcessMarkers) {
    835     JPEGLI_ERROR("jpegli_finish_output: unexpected state %d",
    836                  cinfo->global_state);
    837   }
    838   // Advance input to the start of the next scan, or to the end of input.
    839   while (cinfo->input_scan_number <= cinfo->output_scan_number &&
    840          !cinfo->master->found_eoi_) {
    841     if (jpegli::ConsumeInput(cinfo) == JPEG_SUSPENDED) {
    842       return FALSE;
    843     }
    844   }
    845   return TRUE;
    846 }
    847 
    848 JDIMENSION jpegli_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines,
    849                                  JDIMENSION max_lines) {
    850   jpeg_decomp_master* m = cinfo->master;
    851   if (cinfo->global_state != jpegli::kDecProcessScan &&
    852       cinfo->global_state != jpegli::kDecProcessMarkers) {
    853     JPEGLI_ERROR("jpegli_read_scanlines: unexpected state %d",
    854                  cinfo->global_state);
    855   }
    856   if (cinfo->buffered_image) {
    857     if (cinfo->output_scan_number == 0) {
    858       JPEGLI_ERROR(
    859           "jpegli_read_scanlines: "
    860           "jpegli_start_output() was not called");
    861     }
    862   } else if (m->is_multiscan_ && !m->found_eoi_) {
    863     JPEGLI_ERROR(
    864         "jpegli_read_scanlines: "
    865         "jpegli_start_decompress() did not finish");
    866   }
    867   if (cinfo->output_scanline + max_lines > cinfo->output_height) {
    868     max_lines = cinfo->output_height - cinfo->output_scanline;
    869   }
    870   jpegli::ProgressMonitorOutputPass(cinfo);
    871   size_t num_output_rows = 0;
    872   while (num_output_rows < max_lines) {
    873     if (jpegli::IsInputReady(cinfo)) {
    874       jpegli::ProcessOutput(cinfo, &num_output_rows, scanlines, max_lines);
    875     } else if (jpegli::ConsumeInput(cinfo) == JPEG_SUSPENDED) {
    876       break;
    877     }
    878   }
    879   return num_output_rows;
    880 }
    881 
    882 JDIMENSION jpegli_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines) {
    883   // TODO(szabadka) Skip the IDCT for skipped over blocks.
    884   return jpegli_read_scanlines(cinfo, nullptr, num_lines);
    885 }
    886 
    887 void jpegli_crop_scanline(j_decompress_ptr cinfo, JDIMENSION* xoffset,
    888                           JDIMENSION* width) {
    889   jpeg_decomp_master* m = cinfo->master;
    890   if ((cinfo->global_state != jpegli::kDecProcessScan &&
    891        cinfo->global_state != jpegli::kDecProcessMarkers) ||
    892       cinfo->output_scanline != 0) {
    893     JPEGLI_ERROR("jpegli_crop_decompress: unexpected state %d",
    894                  cinfo->global_state);
    895   }
    896   if (cinfo->raw_data_out) {
    897     JPEGLI_ERROR("Output cropping is not supported in raw data mode");
    898   }
    899   if (xoffset == nullptr || width == nullptr || *width == 0 ||
    900       *xoffset + *width > cinfo->output_width) {
    901     JPEGLI_ERROR("jpegli_crop_scanline: Invalid arguments");
    902   }
    903   // TODO(szabadka) Skip the IDCT for skipped over blocks.
    904   size_t xend = *xoffset + *width;
    905   size_t iMCU_width = m->min_scaled_dct_size * cinfo->max_h_samp_factor;
    906   *xoffset = (*xoffset / iMCU_width) * iMCU_width;
    907   *width = xend - *xoffset;
    908   cinfo->master->xoffset_ = *xoffset;
    909   cinfo->output_width = *width;
    910 }
    911 
    912 JDIMENSION jpegli_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data,
    913                                 JDIMENSION max_lines) {
    914   if ((cinfo->global_state != jpegli::kDecProcessScan &&
    915        cinfo->global_state != jpegli::kDecProcessMarkers) ||
    916       !cinfo->raw_data_out) {
    917     JPEGLI_ERROR("jpegli_read_raw_data: unexpected state %d",
    918                  cinfo->global_state);
    919   }
    920   size_t iMCU_height = cinfo->max_v_samp_factor * DCTSIZE;
    921   if (max_lines < iMCU_height) {
    922     JPEGLI_ERROR("jpegli_read_raw_data: output buffer too small");
    923   }
    924   jpegli::ProgressMonitorOutputPass(cinfo);
    925   while (!jpegli::IsInputReady(cinfo)) {
    926     if (jpegli::ConsumeInput(cinfo) == JPEG_SUSPENDED) {
    927       return 0;
    928     }
    929   }
    930   if (cinfo->output_iMCU_row < cinfo->total_iMCU_rows) {
    931     jpegli::ProcessRawOutput(cinfo, data);
    932     return iMCU_height;
    933   }
    934   return 0;
    935 }
    936 
    937 jvirt_barray_ptr* jpegli_read_coefficients(j_decompress_ptr cinfo) {
    938   jpeg_decomp_master* m = cinfo->master;
    939   m->streaming_mode_ = false;
    940   if (!cinfo->buffered_image && cinfo->global_state == jpegli::kDecHeaderDone) {
    941     jpegli::AllocateCoefficientBuffer(cinfo);
    942     jpegli_calc_output_dimensions(cinfo);
    943     jpegli::InitProgressMonitor(cinfo, /*coef_only=*/true);
    944     jpegli::PrepareForScan(cinfo);
    945   }
    946   if (cinfo->global_state != jpegli::kDecProcessScan &&
    947       cinfo->global_state != jpegli::kDecProcessMarkers) {
    948     JPEGLI_ERROR("jpegli_read_coefficients: unexpected state %d",
    949                  cinfo->global_state);
    950   }
    951   if (!cinfo->buffered_image) {
    952     while (!m->found_eoi_) {
    953       jpegli::ProgressMonitorInputPass(cinfo);
    954       if (jpegli::ConsumeInput(cinfo) == JPEG_SUSPENDED) {
    955         return nullptr;
    956       }
    957     }
    958     cinfo->output_scanline = cinfo->output_height;
    959   }
    960   return m->coef_arrays;
    961 }
    962 
    963 boolean jpegli_finish_decompress(j_decompress_ptr cinfo) {
    964   if (cinfo->global_state != jpegli::kDecProcessScan &&
    965       cinfo->global_state != jpegli::kDecProcessMarkers) {
    966     JPEGLI_ERROR("jpegli_finish_decompress: unexpected state %d",
    967                  cinfo->global_state);
    968   }
    969   if (!cinfo->buffered_image && cinfo->output_scanline < cinfo->output_height) {
    970     JPEGLI_ERROR("Incomplete output");
    971   }
    972   while (!cinfo->master->found_eoi_) {
    973     if (jpegli::ConsumeInput(cinfo) == JPEG_SUSPENDED) {
    974       return FALSE;
    975     }
    976   }
    977   (*cinfo->src->term_source)(cinfo);
    978   jpegli_abort_decompress(cinfo);
    979   return TRUE;
    980 }
    981 
    982 boolean jpegli_resync_to_restart(j_decompress_ptr cinfo, int desired) {
    983   JPEGLI_WARN("Invalid restart marker found: 0x%02x vs 0x%02x.",
    984               cinfo->unread_marker, 0xd0 + desired);
    985   // This is a trivial implementation, we just let the decoder skip the entire
    986   // scan and attempt to render the partial input.
    987   return TRUE;
    988 }
    989 
    990 void jpegli_new_colormap(j_decompress_ptr cinfo) {
    991   if (cinfo->global_state != jpegli::kDecProcessScan &&
    992       cinfo->global_state != jpegli::kDecProcessMarkers) {
    993     JPEGLI_ERROR("jpegli_new_colormap: unexpected state %d",
    994                  cinfo->global_state);
    995   }
    996   if (!cinfo->buffered_image) {
    997     JPEGLI_ERROR("jpegli_new_colormap: not in  buffered image mode");
    998   }
    999   if (!cinfo->enable_external_quant) {
   1000     JPEGLI_ERROR("external colormap quantizer was not enabled");
   1001   }
   1002   if (!cinfo->quantize_colors || cinfo->colormap == nullptr) {
   1003     JPEGLI_ERROR("jpegli_new_colormap: not in external colormap mode");
   1004   }
   1005   cinfo->master->regenerate_inverse_colormap_ = true;
   1006 }
   1007 
   1008 void jpegli_set_output_format(j_decompress_ptr cinfo, JpegliDataType data_type,
   1009                               JpegliEndianness endianness) {
   1010   switch (data_type) {
   1011     case JPEGLI_TYPE_UINT8:
   1012     case JPEGLI_TYPE_UINT16:
   1013     case JPEGLI_TYPE_FLOAT:
   1014       cinfo->master->output_data_type_ = data_type;
   1015       break;
   1016     default:
   1017       JPEGLI_ERROR("Unsupported data type %d", data_type);
   1018   }
   1019   switch (endianness) {
   1020     case JPEGLI_NATIVE_ENDIAN:
   1021       cinfo->master->swap_endianness_ = false;
   1022       break;
   1023     case JPEGLI_LITTLE_ENDIAN:
   1024       cinfo->master->swap_endianness_ = !IsLittleEndian();
   1025       break;
   1026     case JPEGLI_BIG_ENDIAN:
   1027       cinfo->master->swap_endianness_ = IsLittleEndian();
   1028       break;
   1029     default:
   1030       JPEGLI_ERROR("Unsupported endianness %d", endianness);
   1031   }
   1032 }