tor-browser

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

decode.cc (37938B)


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