tor-browser

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

encode.cc (46169B)


      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/encode.h"
      7 
      8 #include <jxl/types.h>
      9 
     10 #include <cmath>
     11 #include <initializer_list>
     12 #include <vector>
     13 
     14 #include "lib/jpegli/adaptive_quantization.h"
     15 #include "lib/jpegli/bit_writer.h"
     16 #include "lib/jpegli/bitstream.h"
     17 #include "lib/jpegli/color_transform.h"
     18 #include "lib/jpegli/downsample.h"
     19 #include "lib/jpegli/encode_finish.h"
     20 #include "lib/jpegli/encode_internal.h"
     21 #include "lib/jpegli/encode_streaming.h"
     22 #include "lib/jpegli/entropy_coding.h"
     23 #include "lib/jpegli/error.h"
     24 #include "lib/jpegli/huffman.h"
     25 #include "lib/jpegli/input.h"
     26 #include "lib/jpegli/memory_manager.h"
     27 #include "lib/jpegli/quant.h"
     28 
     29 namespace jpegli {
     30 
     31 constexpr size_t kMaxBytesInMarker = 65533;
     32 
     33 void CheckState(j_compress_ptr cinfo, int state) {
     34  if (cinfo->global_state != state) {
     35    JPEGLI_ERROR("Unexpected global state %d [expected %d]",
     36                 cinfo->global_state, state);
     37  }
     38 }
     39 
     40 void CheckState(j_compress_ptr cinfo, int state1, int state2) {
     41  if (cinfo->global_state != state1 && cinfo->global_state != state2) {
     42    JPEGLI_ERROR("Unexpected global state %d [expected %d or %d]",
     43                 cinfo->global_state, state1, state2);
     44  }
     45 }
     46 
     47 //
     48 // Parameter setup
     49 //
     50 
     51 // Initialize cinfo fields that are not dependent on input image. This is shared
     52 // between jpegli_CreateCompress() and jpegli_set_defaults()
     53 void InitializeCompressParams(j_compress_ptr cinfo) {
     54  cinfo->data_precision = 8;
     55  cinfo->num_scans = 0;
     56  cinfo->scan_info = nullptr;
     57  cinfo->raw_data_in = FALSE;
     58  cinfo->arith_code = FALSE;
     59  cinfo->optimize_coding = FALSE;
     60  cinfo->CCIR601_sampling = FALSE;
     61  cinfo->smoothing_factor = 0;
     62  cinfo->dct_method = JDCT_FLOAT;
     63  cinfo->restart_interval = 0;
     64  cinfo->restart_in_rows = 0;
     65  cinfo->write_JFIF_header = FALSE;
     66  cinfo->JFIF_major_version = 1;
     67  cinfo->JFIF_minor_version = 1;
     68  cinfo->density_unit = 0;
     69  cinfo->X_density = 1;
     70  cinfo->Y_density = 1;
     71 #if JPEG_LIB_VERSION >= 70
     72  cinfo->scale_num = 1;
     73  cinfo->scale_denom = 1;
     74  cinfo->do_fancy_downsampling = FALSE;
     75  cinfo->min_DCT_h_scaled_size = DCTSIZE;
     76  cinfo->min_DCT_v_scaled_size = DCTSIZE;
     77 #endif
     78  cinfo->master->psnr_target = 0.0f;
     79  cinfo->master->psnr_tolerance = 0.01f;
     80  cinfo->master->min_distance = 0.1f;
     81  cinfo->master->max_distance = 25.0f;
     82 }
     83 
     84 float LinearQualityToDistance(int scale_factor) {
     85  scale_factor = std::min(5000, std::max(0, scale_factor));
     86  int quality =
     87      scale_factor < 100 ? 100 - scale_factor / 2 : 5000 / scale_factor;
     88  return jpegli_quality_to_distance(quality);
     89 }
     90 
     91 template <typename T>
     92 void SetSentTableFlag(T** table_ptrs, size_t num, boolean val) {
     93  for (size_t i = 0; i < num; ++i) {
     94    if (table_ptrs[i]) table_ptrs[i]->sent_table = val;
     95  }
     96 }
     97 
     98 //
     99 // Compressor initialization
    100 //
    101 
    102 struct ProgressiveScan {
    103  int Ss, Se, Ah, Al;
    104  bool interleaved;
    105 };
    106 
    107 void SetDefaultScanScript(j_compress_ptr cinfo) {
    108  int level = cinfo->master->progressive_level;
    109  std::vector<ProgressiveScan> progressive_mode;
    110  bool interleave_dc =
    111      (cinfo->max_h_samp_factor == 1 && cinfo->max_v_samp_factor == 1);
    112  if (level == 0) {
    113    progressive_mode.push_back({0, 63, 0, 0, true});
    114  } else if (level == 1) {
    115    progressive_mode.push_back({0, 0, 0, 0, interleave_dc});
    116    progressive_mode.push_back({1, 63, 0, 1, false});
    117    progressive_mode.push_back({1, 63, 1, 0, false});
    118  } else {
    119    progressive_mode.push_back({0, 0, 0, 0, interleave_dc});
    120    progressive_mode.push_back({1, 2, 0, 0, false});
    121    progressive_mode.push_back({3, 63, 0, 2, false});
    122    progressive_mode.push_back({3, 63, 2, 1, false});
    123    progressive_mode.push_back({3, 63, 1, 0, false});
    124  }
    125 
    126  cinfo->script_space_size = 0;
    127  for (const auto& scan : progressive_mode) {
    128    int comps = scan.interleaved ? MAX_COMPS_IN_SCAN : 1;
    129    cinfo->script_space_size += DivCeil(cinfo->num_components, comps);
    130  }
    131  cinfo->script_space =
    132      Allocate<jpeg_scan_info>(cinfo, cinfo->script_space_size);
    133 
    134  jpeg_scan_info* next_scan = cinfo->script_space;
    135  for (const auto& scan : progressive_mode) {
    136    int comps = scan.interleaved ? MAX_COMPS_IN_SCAN : 1;
    137    for (int c = 0; c < cinfo->num_components; c += comps) {
    138      next_scan->Ss = scan.Ss;
    139      next_scan->Se = scan.Se;
    140      next_scan->Ah = scan.Ah;
    141      next_scan->Al = scan.Al;
    142      next_scan->comps_in_scan = std::min(comps, cinfo->num_components - c);
    143      for (int j = 0; j < next_scan->comps_in_scan; ++j) {
    144        next_scan->component_index[j] = c + j;
    145      }
    146      ++next_scan;
    147    }
    148  }
    149  JPEGLI_CHECK(next_scan - cinfo->script_space == cinfo->script_space_size);
    150  cinfo->scan_info = cinfo->script_space;
    151  cinfo->num_scans = cinfo->script_space_size;
    152 }
    153 
    154 void ValidateScanScript(j_compress_ptr cinfo) {
    155  // Mask of coefficient bits defined by the scan script, for each component
    156  // and coefficient index.
    157  uint16_t comp_mask[kMaxComponents][DCTSIZE2] = {};
    158  static constexpr int kMaxRefinementBit = 10;
    159 
    160  for (int i = 0; i < cinfo->num_scans; ++i) {
    161    const jpeg_scan_info& si = cinfo->scan_info[i];
    162    if (si.comps_in_scan < 1 || si.comps_in_scan > MAX_COMPS_IN_SCAN) {
    163      JPEGLI_ERROR("Invalid number of components in scan %d", si.comps_in_scan);
    164    }
    165    int last_ci = -1;
    166    for (int j = 0; j < si.comps_in_scan; ++j) {
    167      int ci = si.component_index[j];
    168      if (ci < 0 || ci >= cinfo->num_components) {
    169        JPEGLI_ERROR("Invalid component index %d in scan", ci);
    170      } else if (ci == last_ci) {
    171        JPEGLI_ERROR("Duplicate component index %d in scan", ci);
    172      } else if (ci < last_ci) {
    173        JPEGLI_ERROR("Out of order component index %d in scan", ci);
    174      }
    175      last_ci = ci;
    176    }
    177    if (si.Ss < 0 || si.Se < si.Ss || si.Se >= DCTSIZE2) {
    178      JPEGLI_ERROR("Invalid spectral range %d .. %d in scan", si.Ss, si.Se);
    179    }
    180    if (si.Ah < 0 || si.Al < 0 || si.Al > kMaxRefinementBit) {
    181      JPEGLI_ERROR("Invalid refinement bits %d/%d", si.Ah, si.Al);
    182    }
    183    if (!cinfo->progressive_mode) {
    184      if (si.Ss != 0 || si.Se != DCTSIZE2 - 1 || si.Ah != 0 || si.Al != 0) {
    185        JPEGLI_ERROR("Invalid scan for sequential mode");
    186      }
    187    } else {
    188      if (si.Ss == 0 && si.Se != 0) {
    189        JPEGLI_ERROR("DC and AC together in progressive scan");
    190      }
    191    }
    192    if (si.Ss != 0 && si.comps_in_scan != 1) {
    193      JPEGLI_ERROR("Interleaved AC only scan.");
    194    }
    195    for (int j = 0; j < si.comps_in_scan; ++j) {
    196      int ci = si.component_index[j];
    197      if (si.Ss != 0 && comp_mask[ci][0] == 0) {
    198        JPEGLI_ERROR("AC before DC in component %d of scan", ci);
    199      }
    200      for (int k = si.Ss; k <= si.Se; ++k) {
    201        if (comp_mask[ci][k] == 0) {
    202          if (si.Ah != 0) {
    203            JPEGLI_ERROR("Invalid first scan refinement bit");
    204          }
    205          comp_mask[ci][k] = ((0xffff << si.Al) & 0xffff);
    206        } else {
    207          if (comp_mask[ci][k] != ((0xffff << si.Ah) & 0xffff) ||
    208              si.Al != si.Ah - 1) {
    209            JPEGLI_ERROR("Invalid refinement bit progression.");
    210          }
    211          comp_mask[ci][k] |= 1 << si.Al;
    212        }
    213      }
    214    }
    215    if (si.comps_in_scan > 1) {
    216      size_t mcu_size = 0;
    217      for (int j = 0; j < si.comps_in_scan; ++j) {
    218        int ci = si.component_index[j];
    219        jpeg_component_info* comp = &cinfo->comp_info[ci];
    220        mcu_size += comp->h_samp_factor * comp->v_samp_factor;
    221      }
    222      if (mcu_size > C_MAX_BLOCKS_IN_MCU) {
    223        JPEGLI_ERROR("MCU size too big");
    224      }
    225    }
    226  }
    227  for (int c = 0; c < cinfo->num_components; ++c) {
    228    for (int k = 0; k < DCTSIZE2; ++k) {
    229      if (comp_mask[c][k] != 0xffff) {
    230        JPEGLI_ERROR("Incomplete scan of component %d and frequency %d", c, k);
    231      }
    232    }
    233  }
    234 }
    235 
    236 void ProcessCompressionParams(j_compress_ptr cinfo) {
    237  if (cinfo->dest == nullptr) {
    238    JPEGLI_ERROR("Missing destination.");
    239  }
    240  if (cinfo->image_width < 1 || cinfo->image_height < 1 ||
    241      cinfo->input_components < 1) {
    242    JPEGLI_ERROR("Empty input image.");
    243  }
    244  if (cinfo->image_width > static_cast<int>(JPEG_MAX_DIMENSION) ||
    245      cinfo->image_height > static_cast<int>(JPEG_MAX_DIMENSION) ||
    246      cinfo->input_components > static_cast<int>(kMaxComponents)) {
    247    JPEGLI_ERROR("Input image too big.");
    248  }
    249  if (cinfo->num_components < 1 ||
    250      cinfo->num_components > static_cast<int>(kMaxComponents)) {
    251    JPEGLI_ERROR("Invalid number of components.");
    252  }
    253  if (cinfo->data_precision != kJpegPrecision) {
    254    JPEGLI_ERROR("Invalid data precision");
    255  }
    256  if (cinfo->arith_code) {
    257    JPEGLI_ERROR("Arithmetic coding is not implemented.");
    258  }
    259  if (cinfo->CCIR601_sampling) {
    260    JPEGLI_ERROR("CCIR601 sampling is not implemented.");
    261  }
    262  if (cinfo->restart_interval > 65535u) {
    263    JPEGLI_ERROR("Restart interval too big");
    264  }
    265  if (cinfo->smoothing_factor < 0 || cinfo->smoothing_factor > 100) {
    266    JPEGLI_ERROR("Invalid smoothing factor %d", cinfo->smoothing_factor);
    267  }
    268  jpeg_comp_master* m = cinfo->master;
    269  cinfo->max_h_samp_factor = cinfo->max_v_samp_factor = 1;
    270  for (int c = 0; c < cinfo->num_components; ++c) {
    271    jpeg_component_info* comp = &cinfo->comp_info[c];
    272    if (comp->component_index != c) {
    273      JPEGLI_ERROR("Invalid component index");
    274    }
    275    for (int j = 0; j < c; ++j) {
    276      if (cinfo->comp_info[j].component_id == comp->component_id) {
    277        JPEGLI_ERROR("Duplicate component id %d", comp->component_id);
    278      }
    279    }
    280    if (comp->h_samp_factor <= 0 || comp->v_samp_factor <= 0 ||
    281        comp->h_samp_factor > MAX_SAMP_FACTOR ||
    282        comp->v_samp_factor > MAX_SAMP_FACTOR) {
    283      JPEGLI_ERROR("Invalid sampling factor %d x %d", comp->h_samp_factor,
    284                   comp->v_samp_factor);
    285    }
    286    if (cinfo->num_components == 1) {
    287      // Force samp factors to 1x1 for single-component images.
    288      comp->h_samp_factor = comp->v_samp_factor = 1;
    289    }
    290    cinfo->max_h_samp_factor =
    291        std::max(comp->h_samp_factor, cinfo->max_h_samp_factor);
    292    cinfo->max_v_samp_factor =
    293        std::max(comp->v_samp_factor, cinfo->max_v_samp_factor);
    294  }
    295  size_t iMCU_width = DCTSIZE * cinfo->max_h_samp_factor;
    296  size_t iMCU_height = DCTSIZE * cinfo->max_v_samp_factor;
    297  size_t total_iMCU_cols = DivCeil(cinfo->image_width, iMCU_width);
    298  cinfo->total_iMCU_rows = DivCeil(cinfo->image_height, iMCU_height);
    299  m->xsize_blocks = total_iMCU_cols * cinfo->max_h_samp_factor;
    300  m->ysize_blocks = cinfo->total_iMCU_rows * cinfo->max_v_samp_factor;
    301 
    302  size_t blocks_per_iMCU = 0;
    303  for (int c = 0; c < cinfo->num_components; ++c) {
    304    jpeg_component_info* comp = &cinfo->comp_info[c];
    305    if (cinfo->max_h_samp_factor % comp->h_samp_factor != 0 ||
    306        cinfo->max_v_samp_factor % comp->v_samp_factor != 0) {
    307      JPEGLI_ERROR("Non-integral sampling ratios are not supported.");
    308    }
    309    m->h_factor[c] = cinfo->max_h_samp_factor / comp->h_samp_factor;
    310    m->v_factor[c] = cinfo->max_v_samp_factor / comp->v_samp_factor;
    311    comp->downsampled_width = DivCeil(cinfo->image_width, m->h_factor[c]);
    312    comp->downsampled_height = DivCeil(cinfo->image_height, m->v_factor[c]);
    313    comp->width_in_blocks = DivCeil(comp->downsampled_width, DCTSIZE);
    314    comp->height_in_blocks = DivCeil(comp->downsampled_height, DCTSIZE);
    315    blocks_per_iMCU += comp->h_samp_factor * comp->v_samp_factor;
    316  }
    317  m->blocks_per_iMCU_row = total_iMCU_cols * blocks_per_iMCU;
    318  // Disable adaptive quantization for subsampled luma channel.
    319  int y_channel = cinfo->jpeg_color_space == JCS_RGB ? 1 : 0;
    320  jpeg_component_info* y_comp = &cinfo->comp_info[y_channel];
    321  if (y_comp->h_samp_factor != cinfo->max_h_samp_factor ||
    322      y_comp->v_samp_factor != cinfo->max_v_samp_factor) {
    323    m->use_adaptive_quantization = false;
    324  }
    325  if (cinfo->scan_info == nullptr) {
    326    SetDefaultScanScript(cinfo);
    327  }
    328  cinfo->progressive_mode = TO_JXL_BOOL(cinfo->scan_info->Ss != 0 ||
    329                                        cinfo->scan_info->Se != DCTSIZE2 - 1);
    330  ValidateScanScript(cinfo);
    331  m->scan_token_info =
    332      Allocate<ScanTokenInfo>(cinfo, cinfo->num_scans, JPOOL_IMAGE);
    333  memset(m->scan_token_info, 0, cinfo->num_scans * sizeof(ScanTokenInfo));
    334  m->ac_ctx_offset = Allocate<uint8_t>(cinfo, cinfo->num_scans, JPOOL_IMAGE);
    335  size_t num_ac_contexts = 0;
    336  for (int i = 0; i < cinfo->num_scans; ++i) {
    337    const jpeg_scan_info* scan_info = &cinfo->scan_info[i];
    338    m->ac_ctx_offset[i] = 4 + num_ac_contexts;
    339    if (scan_info->Se > 0) {
    340      num_ac_contexts += scan_info->comps_in_scan;
    341    }
    342    if (num_ac_contexts > 252) {
    343      JPEGLI_ERROR("Too many AC scans in image");
    344    }
    345    ScanTokenInfo* sti = &m->scan_token_info[i];
    346    if (scan_info->comps_in_scan == 1) {
    347      int comp_idx = scan_info->component_index[0];
    348      jpeg_component_info* comp = &cinfo->comp_info[comp_idx];
    349      sti->MCUs_per_row = comp->width_in_blocks;
    350      sti->MCU_rows_in_scan = comp->height_in_blocks;
    351      sti->blocks_in_MCU = 1;
    352    } else {
    353      sti->MCUs_per_row =
    354          DivCeil(cinfo->image_width, DCTSIZE * cinfo->max_h_samp_factor);
    355      sti->MCU_rows_in_scan =
    356          DivCeil(cinfo->image_height, DCTSIZE * cinfo->max_v_samp_factor);
    357      sti->blocks_in_MCU = 0;
    358      for (int j = 0; j < scan_info->comps_in_scan; ++j) {
    359        int comp_idx = scan_info->component_index[j];
    360        jpeg_component_info* comp = &cinfo->comp_info[comp_idx];
    361        sti->blocks_in_MCU += comp->h_samp_factor * comp->v_samp_factor;
    362      }
    363    }
    364    size_t num_MCUs = sti->MCU_rows_in_scan * sti->MCUs_per_row;
    365    sti->num_blocks = num_MCUs * sti->blocks_in_MCU;
    366    if (cinfo->restart_in_rows <= 0) {
    367      sti->restart_interval = cinfo->restart_interval;
    368    } else {
    369      sti->restart_interval =
    370          std::min<size_t>(sti->MCUs_per_row * cinfo->restart_in_rows, 65535u);
    371    }
    372    sti->num_restarts = sti->restart_interval > 0
    373                            ? DivCeil(num_MCUs, sti->restart_interval)
    374                            : 1;
    375    sti->restarts = Allocate<size_t>(cinfo, sti->num_restarts, JPOOL_IMAGE);
    376  }
    377  m->num_contexts = 4 + num_ac_contexts;
    378 }
    379 
    380 bool IsStreamingSupported(j_compress_ptr cinfo) {
    381  if (cinfo->global_state == kEncWriteCoeffs) {
    382    return false;
    383  }
    384  // TODO(szabadka) Remove this restriction.
    385  if (cinfo->restart_interval > 0 || cinfo->restart_in_rows > 0) {
    386    return false;
    387  }
    388  if (cinfo->num_scans > 1) {
    389    return false;
    390  }
    391  if (cinfo->master->psnr_target > 0) {
    392    return false;
    393  }
    394  return true;
    395 }
    396 
    397 void AllocateBuffers(j_compress_ptr cinfo) {
    398  jpeg_comp_master* m = cinfo->master;
    399  memset(m->last_dc_coeff, 0, sizeof(m->last_dc_coeff));
    400  if (!IsStreamingSupported(cinfo) || cinfo->optimize_coding) {
    401    int ysize_blocks = DivCeil(cinfo->image_height, DCTSIZE);
    402    int num_arrays = cinfo->num_scans * ysize_blocks;
    403    m->token_arrays = Allocate<TokenArray>(cinfo, num_arrays, JPOOL_IMAGE);
    404    m->cur_token_array = 0;
    405    memset(m->token_arrays, 0, num_arrays * sizeof(TokenArray));
    406    m->num_tokens = 0;
    407    m->total_num_tokens = 0;
    408  }
    409  if (cinfo->global_state == kEncWriteCoeffs) {
    410    return;
    411  }
    412  size_t iMCU_width = DCTSIZE * cinfo->max_h_samp_factor;
    413  size_t iMCU_height = DCTSIZE * cinfo->max_v_samp_factor;
    414  size_t total_iMCU_cols = DivCeil(cinfo->image_width, iMCU_width);
    415  size_t xsize_full = total_iMCU_cols * iMCU_width;
    416  size_t ysize_full = 3 * iMCU_height;
    417  if (!cinfo->raw_data_in) {
    418    int num_all_components =
    419        std::max(cinfo->input_components, cinfo->num_components);
    420    for (int c = 0; c < num_all_components; ++c) {
    421      m->input_buffer[c].Allocate(cinfo, ysize_full, xsize_full);
    422    }
    423  }
    424  for (int c = 0; c < cinfo->num_components; ++c) {
    425    jpeg_component_info* comp = &cinfo->comp_info[c];
    426    size_t xsize = total_iMCU_cols * comp->h_samp_factor * DCTSIZE;
    427    size_t ysize = 3 * comp->v_samp_factor * DCTSIZE;
    428    if (cinfo->raw_data_in) {
    429      m->input_buffer[c].Allocate(cinfo, ysize, xsize);
    430    }
    431    m->smooth_input[c] = &m->input_buffer[c];
    432    if (!cinfo->raw_data_in && cinfo->smoothing_factor) {
    433      m->smooth_input[c] = Allocate<RowBuffer<float>>(cinfo, 1, JPOOL_IMAGE);
    434      m->smooth_input[c]->Allocate(cinfo, ysize_full, xsize_full);
    435    }
    436    m->raw_data[c] = m->smooth_input[c];
    437    if (!cinfo->raw_data_in && (m->h_factor[c] > 1 || m->v_factor[c] > 1)) {
    438      m->raw_data[c] = Allocate<RowBuffer<float>>(cinfo, 1, JPOOL_IMAGE);
    439      m->raw_data[c]->Allocate(cinfo, ysize, xsize);
    440    }
    441    m->quant_mul[c] = Allocate<float>(cinfo, DCTSIZE2, JPOOL_IMAGE_ALIGNED);
    442  }
    443  m->dct_buffer = Allocate<float>(cinfo, 2 * DCTSIZE2, JPOOL_IMAGE_ALIGNED);
    444  m->block_tmp = Allocate<int32_t>(cinfo, DCTSIZE2 * 4, JPOOL_IMAGE_ALIGNED);
    445  if (!IsStreamingSupported(cinfo)) {
    446    m->coeff_buffers =
    447        Allocate<jvirt_barray_ptr>(cinfo, cinfo->num_components, JPOOL_IMAGE);
    448    for (int c = 0; c < cinfo->num_components; ++c) {
    449      jpeg_component_info* comp = &cinfo->comp_info[c];
    450      const size_t xsize_blocks = comp->width_in_blocks;
    451      const size_t ysize_blocks = comp->height_in_blocks;
    452      m->coeff_buffers[c] = (*cinfo->mem->request_virt_barray)(
    453          reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE,
    454          /*pre_zero=*/FALSE, xsize_blocks, ysize_blocks, comp->v_samp_factor);
    455    }
    456  }
    457  if (m->use_adaptive_quantization) {
    458    int y_channel = cinfo->jpeg_color_space == JCS_RGB ? 1 : 0;
    459    jpeg_component_info* y_comp = &cinfo->comp_info[y_channel];
    460    const size_t xsize_blocks = y_comp->width_in_blocks;
    461    const size_t vecsize = VectorSize();
    462    const size_t xsize_padded = DivCeil(2 * xsize_blocks, vecsize) * vecsize;
    463    m->diff_buffer =
    464        Allocate<float>(cinfo, xsize_blocks * DCTSIZE + 8, JPOOL_IMAGE_ALIGNED);
    465    m->fuzzy_erosion_tmp.Allocate(cinfo, 2, xsize_padded);
    466    m->pre_erosion.Allocate(cinfo, 6 * cinfo->max_v_samp_factor, xsize_padded);
    467    size_t qf_height = cinfo->max_v_samp_factor;
    468    if (m->psnr_target > 0) {
    469      qf_height *= cinfo->total_iMCU_rows;
    470    }
    471    m->quant_field.Allocate(cinfo, qf_height, xsize_blocks);
    472  } else {
    473    m->quant_field.Allocate(cinfo, 1, m->xsize_blocks);
    474    m->quant_field.FillRow(0, 0, m->xsize_blocks);
    475  }
    476  for (int c = 0; c < cinfo->num_components; ++c) {
    477    m->zero_bias_offset[c] =
    478        Allocate<float>(cinfo, DCTSIZE2, JPOOL_IMAGE_ALIGNED);
    479    m->zero_bias_mul[c] = Allocate<float>(cinfo, DCTSIZE2, JPOOL_IMAGE_ALIGNED);
    480    memset(m->zero_bias_mul[c], 0, DCTSIZE2 * sizeof(float));
    481    memset(m->zero_bias_offset[c], 0, DCTSIZE2 * sizeof(float));
    482  }
    483 }
    484 
    485 void InitProgressMonitor(j_compress_ptr cinfo) {
    486  if (cinfo->progress == nullptr) {
    487    return;
    488  }
    489  if (IsStreamingSupported(cinfo)) {
    490    // We have only one input pass.
    491    cinfo->progress->total_passes = 1;
    492  } else {
    493    // We have one input pass, a histogram pass for each scan, and an encode
    494    // pass for each scan.
    495    cinfo->progress->total_passes = 1 + 2 * cinfo->num_scans;
    496  }
    497 }
    498 
    499 // Common setup code between streaming and transcoding code paths. Called in
    500 // both jpegli_start_compress() and jpegli_write_coefficients().
    501 void InitCompress(j_compress_ptr cinfo, boolean write_all_tables) {
    502  jpeg_comp_master* m = cinfo->master;
    503  (*cinfo->err->reset_error_mgr)(reinterpret_cast<j_common_ptr>(cinfo));
    504  ProcessCompressionParams(cinfo);
    505  InitProgressMonitor(cinfo);
    506  AllocateBuffers(cinfo);
    507  if (cinfo->global_state != kEncWriteCoeffs) {
    508    ChooseInputMethod(cinfo);
    509    if (!cinfo->raw_data_in) {
    510      ChooseColorTransform(cinfo);
    511      ChooseDownsampleMethods(cinfo);
    512    }
    513    QuantPass pass = m->psnr_target > 0 ? QuantPass::SEARCH_FIRST_PASS
    514                                        : QuantPass::NO_SEARCH;
    515    InitQuantizer(cinfo, pass);
    516  }
    517  if (write_all_tables) {
    518    jpegli_suppress_tables(cinfo, FALSE);
    519  }
    520  if (!cinfo->optimize_coding && !cinfo->progressive_mode) {
    521    CopyHuffmanTables(cinfo);
    522    InitEntropyCoder(cinfo);
    523  }
    524  (*cinfo->dest->init_destination)(cinfo);
    525  WriteFileHeader(cinfo);
    526  JpegBitWriterInit(cinfo);
    527  m->next_iMCU_row = 0;
    528  m->last_restart_interval = 0;
    529  m->next_dht_index = 0;
    530 }
    531 
    532 //
    533 // Input streaming
    534 //
    535 
    536 void ProgressMonitorInputPass(j_compress_ptr cinfo) {
    537  if (cinfo->progress == nullptr) {
    538    return;
    539  }
    540  cinfo->progress->completed_passes = 0;
    541  cinfo->progress->pass_counter = cinfo->next_scanline;
    542  cinfo->progress->pass_limit = cinfo->image_height;
    543  (*cinfo->progress->progress_monitor)(reinterpret_cast<j_common_ptr>(cinfo));
    544 }
    545 
    546 void ReadInputRow(j_compress_ptr cinfo, const uint8_t* scanline,
    547                  float* row[kMaxComponents]) {
    548  jpeg_comp_master* m = cinfo->master;
    549  int num_all_components =
    550      std::max(cinfo->input_components, cinfo->num_components);
    551  for (int c = 0; c < num_all_components; ++c) {
    552    row[c] = m->input_buffer[c].Row(m->next_input_row);
    553  }
    554  ++m->next_input_row;
    555  if (scanline == nullptr) {
    556    for (int c = 0; c < cinfo->input_components; ++c) {
    557      memset(row[c], 0, cinfo->image_width * sizeof(row[c][0]));
    558    }
    559    return;
    560  }
    561  (*m->input_method)(scanline, cinfo->image_width, row);
    562 }
    563 
    564 void PadInputBuffer(j_compress_ptr cinfo, float* row[kMaxComponents]) {
    565  jpeg_comp_master* m = cinfo->master;
    566  const size_t len0 = cinfo->image_width;
    567  const size_t len1 = m->xsize_blocks * DCTSIZE;
    568  for (int c = 0; c < cinfo->num_components; ++c) {
    569    // Pad row to a multiple of the iMCU width, plus create a border of 1
    570    // repeated pixel for adaptive quant field calculation.
    571    float last_val = row[c][len0 - 1];
    572    for (size_t x = len0; x <= len1; ++x) {
    573      row[c][x] = last_val;
    574    }
    575    row[c][-1] = row[c][0];
    576  }
    577  if (m->next_input_row == cinfo->image_height) {
    578    size_t num_rows = m->ysize_blocks * DCTSIZE - cinfo->image_height;
    579    for (size_t i = 0; i < num_rows; ++i) {
    580      for (int c = 0; c < cinfo->num_components; ++c) {
    581        float* dest = m->input_buffer[c].Row(m->next_input_row) - 1;
    582        memcpy(dest, row[c] - 1, (len1 + 2) * sizeof(dest[0]));
    583      }
    584      ++m->next_input_row;
    585    }
    586  }
    587 }
    588 
    589 void ProcessiMCURow(j_compress_ptr cinfo) {
    590  JPEGLI_CHECK(cinfo->master->next_iMCU_row < cinfo->total_iMCU_rows);
    591  if (!cinfo->raw_data_in) {
    592    ApplyInputSmoothing(cinfo);
    593    DownsampleInputBuffer(cinfo);
    594  }
    595  ComputeAdaptiveQuantField(cinfo);
    596  if (IsStreamingSupported(cinfo)) {
    597    if (cinfo->optimize_coding) {
    598      ComputeTokensForiMCURow(cinfo);
    599    } else {
    600      WriteiMCURow(cinfo);
    601    }
    602  } else {
    603    ComputeCoefficientsForiMCURow(cinfo);
    604  }
    605  ++cinfo->master->next_iMCU_row;
    606 }
    607 
    608 void ProcessiMCURows(j_compress_ptr cinfo) {
    609  jpeg_comp_master* m = cinfo->master;
    610  size_t iMCU_height = DCTSIZE * cinfo->max_v_samp_factor;
    611  // To have context rows both above and below the current iMCU row, we delay
    612  // processing the first iMCU row and process two iMCU rows after we receive
    613  // the last input row.
    614  if (m->next_input_row % iMCU_height == 0 && m->next_input_row > iMCU_height) {
    615    ProcessiMCURow(cinfo);
    616  }
    617  if (m->next_input_row >= cinfo->image_height) {
    618    ProcessiMCURow(cinfo);
    619  }
    620 }
    621 
    622 //
    623 // Non-streaming part
    624 //
    625 
    626 void ZigZagShuffleBlocks(j_compress_ptr cinfo) {
    627  JCOEF tmp[DCTSIZE2];
    628  for (int c = 0; c < cinfo->num_components; ++c) {
    629    jpeg_component_info* comp = &cinfo->comp_info[c];
    630    for (JDIMENSION by = 0; by < comp->height_in_blocks; ++by) {
    631      JBLOCKARRAY blocks = GetBlockRow(cinfo, c, by);
    632      for (JDIMENSION bx = 0; bx < comp->width_in_blocks; ++bx) {
    633        JCOEF* block = &blocks[0][bx][0];
    634        for (int k = 0; k < DCTSIZE2; ++k) {
    635          tmp[k] = block[kJPEGNaturalOrder[k]];
    636        }
    637        memcpy(block, tmp, sizeof(tmp));
    638      }
    639    }
    640  }
    641 }
    642 
    643 }  // namespace jpegli
    644 
    645 //
    646 // Parameter setup
    647 //
    648 
    649 void jpegli_CreateCompress(j_compress_ptr cinfo, int version,
    650                           size_t structsize) {
    651  cinfo->mem = nullptr;
    652  if (structsize != sizeof(*cinfo)) {
    653    JPEGLI_ERROR("jpegli_compress_struct has wrong size.");
    654  }
    655  jpegli::InitMemoryManager(reinterpret_cast<j_common_ptr>(cinfo));
    656  cinfo->progress = nullptr;
    657  cinfo->is_decompressor = FALSE;
    658  cinfo->global_state = jpegli::kEncStart;
    659  cinfo->dest = nullptr;
    660  cinfo->image_width = 0;
    661  cinfo->image_height = 0;
    662  cinfo->input_components = 0;
    663  cinfo->in_color_space = JCS_UNKNOWN;
    664  cinfo->input_gamma = 1.0f;
    665  cinfo->num_components = 0;
    666  cinfo->jpeg_color_space = JCS_UNKNOWN;
    667  cinfo->comp_info = nullptr;
    668  for (auto& quant_tbl_ptr : cinfo->quant_tbl_ptrs) {
    669    quant_tbl_ptr = nullptr;
    670  }
    671  for (int i = 0; i < NUM_HUFF_TBLS; ++i) {
    672    cinfo->dc_huff_tbl_ptrs[i] = nullptr;
    673    cinfo->ac_huff_tbl_ptrs[i] = nullptr;
    674  }
    675  memset(cinfo->arith_dc_L, 0, sizeof(cinfo->arith_dc_L));
    676  memset(cinfo->arith_dc_U, 0, sizeof(cinfo->arith_dc_U));
    677  memset(cinfo->arith_ac_K, 0, sizeof(cinfo->arith_ac_K));
    678  cinfo->write_Adobe_marker = FALSE;
    679  cinfo->master = jpegli::Allocate<jpeg_comp_master>(cinfo, 1);
    680  jpegli::InitializeCompressParams(cinfo);
    681  cinfo->master->force_baseline = true;
    682  cinfo->master->xyb_mode = false;
    683  cinfo->master->cicp_transfer_function = 2;  // unknown transfer function code
    684  cinfo->master->use_std_tables = false;
    685  cinfo->master->use_adaptive_quantization = true;
    686  cinfo->master->progressive_level = jpegli::kDefaultProgressiveLevel;
    687  cinfo->master->data_type = JPEGLI_TYPE_UINT8;
    688  cinfo->master->endianness = JPEGLI_NATIVE_ENDIAN;
    689  cinfo->master->coeff_buffers = nullptr;
    690 }
    691 
    692 void jpegli_set_xyb_mode(j_compress_ptr cinfo) {
    693  CheckState(cinfo, jpegli::kEncStart);
    694  cinfo->master->xyb_mode = true;
    695 }
    696 
    697 void jpegli_set_cicp_transfer_function(j_compress_ptr cinfo, int code) {
    698  CheckState(cinfo, jpegli::kEncStart);
    699  cinfo->master->cicp_transfer_function = code;
    700 }
    701 
    702 void jpegli_set_defaults(j_compress_ptr cinfo) {
    703  CheckState(cinfo, jpegli::kEncStart);
    704  jpegli::InitializeCompressParams(cinfo);
    705  jpegli_default_colorspace(cinfo);
    706  jpegli_set_quality(cinfo, 90, TRUE);
    707  jpegli_set_progressive_level(cinfo, jpegli::kDefaultProgressiveLevel);
    708  jpegli::AddStandardHuffmanTables(reinterpret_cast<j_common_ptr>(cinfo),
    709                                   /*is_dc=*/false);
    710  jpegli::AddStandardHuffmanTables(reinterpret_cast<j_common_ptr>(cinfo),
    711                                   /*is_dc=*/true);
    712 }
    713 
    714 void jpegli_default_colorspace(j_compress_ptr cinfo) {
    715  CheckState(cinfo, jpegli::kEncStart);
    716  if (cinfo->in_color_space == JCS_RGB && cinfo->master->xyb_mode) {
    717    jpegli_set_colorspace(cinfo, JCS_RGB);
    718    return;
    719  }
    720  switch (cinfo->in_color_space) {
    721    case JCS_GRAYSCALE:
    722      jpegli_set_colorspace(cinfo, JCS_GRAYSCALE);
    723      break;
    724    case JCS_RGB:
    725 #ifdef JCS_EXTENSIONS
    726    case JCS_EXT_RGB:
    727    case JCS_EXT_BGR:
    728    case JCS_EXT_RGBX:
    729    case JCS_EXT_BGRX:
    730    case JCS_EXT_XRGB:
    731    case JCS_EXT_XBGR:
    732 #endif
    733 #if JCS_ALPHA_EXTENSIONS
    734    case JCS_EXT_RGBA:
    735    case JCS_EXT_BGRA:
    736    case JCS_EXT_ARGB:
    737    case JCS_EXT_ABGR:
    738 #endif
    739      jpegli_set_colorspace(cinfo, JCS_YCbCr);
    740      break;
    741    case JCS_YCbCr:
    742      jpegli_set_colorspace(cinfo, JCS_YCbCr);
    743      break;
    744    case JCS_CMYK:
    745      jpegli_set_colorspace(cinfo, JCS_CMYK);
    746      break;
    747    case JCS_YCCK:
    748      jpegli_set_colorspace(cinfo, JCS_YCCK);
    749      break;
    750    case JCS_UNKNOWN:
    751      jpegli_set_colorspace(cinfo, JCS_UNKNOWN);
    752      break;
    753    default:
    754      JPEGLI_ERROR("Unsupported input colorspace %d", cinfo->in_color_space);
    755  }
    756 }
    757 
    758 void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) {
    759  CheckState(cinfo, jpegli::kEncStart);
    760  cinfo->jpeg_color_space = colorspace;
    761  switch (colorspace) {
    762    case JCS_GRAYSCALE:
    763      cinfo->num_components = 1;
    764      break;
    765    case JCS_RGB:
    766    case JCS_YCbCr:
    767      cinfo->num_components = 3;
    768      break;
    769    case JCS_CMYK:
    770    case JCS_YCCK:
    771      cinfo->num_components = 4;
    772      break;
    773    case JCS_UNKNOWN:
    774      cinfo->num_components =
    775          std::min<int>(jpegli::kMaxComponents, cinfo->input_components);
    776      break;
    777    default:
    778      JPEGLI_ERROR("Unsupported jpeg colorspace %d", colorspace);
    779  }
    780  // Adobe marker is only needed to distinguish CMYK and YCCK JPEGs.
    781  cinfo->write_Adobe_marker = TO_JXL_BOOL(cinfo->jpeg_color_space == JCS_YCCK);
    782  if (cinfo->comp_info == nullptr) {
    783    cinfo->comp_info =
    784        jpegli::Allocate<jpeg_component_info>(cinfo, MAX_COMPONENTS);
    785  }
    786  memset(cinfo->comp_info, 0,
    787         jpegli::kMaxComponents * sizeof(jpeg_component_info));
    788  for (int c = 0; c < cinfo->num_components; ++c) {
    789    jpeg_component_info* comp = &cinfo->comp_info[c];
    790    comp->component_index = c;
    791    comp->component_id = c + 1;
    792    comp->h_samp_factor = 1;
    793    comp->v_samp_factor = 1;
    794    comp->quant_tbl_no = 0;
    795    comp->dc_tbl_no = 0;
    796    comp->ac_tbl_no = 0;
    797  }
    798  if (colorspace == JCS_RGB) {
    799    cinfo->comp_info[0].component_id = 'R';
    800    cinfo->comp_info[1].component_id = 'G';
    801    cinfo->comp_info[2].component_id = 'B';
    802    if (cinfo->master->xyb_mode) {
    803      // Subsample blue channel.
    804      cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2;
    805      cinfo->comp_info[1].h_samp_factor = cinfo->comp_info[1].v_samp_factor = 2;
    806      cinfo->comp_info[2].h_samp_factor = cinfo->comp_info[2].v_samp_factor = 1;
    807      // Use separate quantization tables for each component
    808      cinfo->comp_info[1].quant_tbl_no = 1;
    809      cinfo->comp_info[2].quant_tbl_no = 2;
    810    }
    811  } else if (colorspace == JCS_CMYK) {
    812    cinfo->comp_info[0].component_id = 'C';
    813    cinfo->comp_info[1].component_id = 'M';
    814    cinfo->comp_info[2].component_id = 'Y';
    815    cinfo->comp_info[3].component_id = 'K';
    816  } else if (colorspace == JCS_YCbCr || colorspace == JCS_YCCK) {
    817    // Use separate quantization and Huffman tables for luma and chroma
    818    cinfo->comp_info[1].quant_tbl_no = 1;
    819    cinfo->comp_info[2].quant_tbl_no = 1;
    820    cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1;
    821    cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1;
    822    // Use chroma subsampling by default
    823    cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2;
    824    if (colorspace == JCS_YCCK) {
    825      cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2;
    826    }
    827  }
    828 }
    829 
    830 void jpegli_set_distance(j_compress_ptr cinfo, float distance,
    831                         boolean force_baseline) {
    832  CheckState(cinfo, jpegli::kEncStart);
    833  cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline);
    834  float distances[NUM_QUANT_TBLS] = {distance, distance, distance};
    835  jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true);
    836 }
    837 
    838 float jpegli_quality_to_distance(int quality) {
    839  return (quality >= 100  ? 0.01f
    840          : quality >= 30 ? 0.1f + (100 - quality) * 0.09f
    841                          : 53.0f / 3000.0f * quality * quality -
    842                                23.0f / 20.0f * quality + 25.0f);
    843 }
    844 
    845 void jpegli_set_psnr(j_compress_ptr cinfo, float psnr, float tolerance,
    846                     float min_distance, float max_distance) {
    847  CheckState(cinfo, jpegli::kEncStart);
    848  cinfo->master->psnr_target = psnr;
    849  cinfo->master->psnr_tolerance = tolerance;
    850  cinfo->master->min_distance = min_distance;
    851  cinfo->master->max_distance = max_distance;
    852 }
    853 
    854 void jpegli_set_quality(j_compress_ptr cinfo, int quality,
    855                        boolean force_baseline) {
    856  CheckState(cinfo, jpegli::kEncStart);
    857  cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline);
    858  float distance = jpegli_quality_to_distance(quality);
    859  float distances[NUM_QUANT_TBLS] = {distance, distance, distance};
    860  jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false);
    861 }
    862 
    863 void jpegli_set_linear_quality(j_compress_ptr cinfo, int scale_factor,
    864                               boolean force_baseline) {
    865  CheckState(cinfo, jpegli::kEncStart);
    866  cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline);
    867  float distance = jpegli::LinearQualityToDistance(scale_factor);
    868  float distances[NUM_QUANT_TBLS] = {distance, distance, distance};
    869  jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false);
    870 }
    871 
    872 #if JPEG_LIB_VERSION >= 70
    873 void jpegli_default_qtables(j_compress_ptr cinfo, boolean force_baseline) {
    874  CheckState(cinfo, jpegli::kEncStart);
    875  cinfo->master->force_baseline = force_baseline;
    876  float distances[NUM_QUANT_TBLS];
    877  for (int i = 0; i < NUM_QUANT_TBLS; ++i) {
    878    distances[i] = jpegli::LinearQualityToDistance(cinfo->q_scale_factor[i]);
    879  }
    880  jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false);
    881 }
    882 #endif
    883 
    884 int jpegli_quality_scaling(int quality) {
    885  quality = std::min(100, std::max(1, quality));
    886  return quality < 50 ? 5000 / quality : 200 - 2 * quality;
    887 }
    888 
    889 void jpegli_use_standard_quant_tables(j_compress_ptr cinfo) {
    890  CheckState(cinfo, jpegli::kEncStart);
    891  cinfo->master->use_std_tables = true;
    892 }
    893 
    894 void jpegli_add_quant_table(j_compress_ptr cinfo, int which_tbl,
    895                            const unsigned int* basic_table, int scale_factor,
    896                            boolean force_baseline) {
    897  CheckState(cinfo, jpegli::kEncStart);
    898  if (which_tbl < 0 || which_tbl > NUM_QUANT_TBLS) {
    899    JPEGLI_ERROR("Invalid quant table index %d", which_tbl);
    900  }
    901  if (cinfo->quant_tbl_ptrs[which_tbl] == nullptr) {
    902    cinfo->quant_tbl_ptrs[which_tbl] =
    903        jpegli_alloc_quant_table(reinterpret_cast<j_common_ptr>(cinfo));
    904  }
    905  int max_qval = force_baseline ? 255 : 32767U;
    906  JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[which_tbl];
    907  for (int k = 0; k < DCTSIZE2; ++k) {
    908    int qval = (basic_table[k] * scale_factor + 50) / 100;
    909    qval = std::max(1, std::min(qval, max_qval));
    910    quant_table->quantval[k] = qval;
    911  }
    912  quant_table->sent_table = FALSE;
    913 }
    914 
    915 void jpegli_enable_adaptive_quantization(j_compress_ptr cinfo, boolean value) {
    916  CheckState(cinfo, jpegli::kEncStart);
    917  cinfo->master->use_adaptive_quantization = FROM_JXL_BOOL(value);
    918 }
    919 
    920 void jpegli_simple_progression(j_compress_ptr cinfo) {
    921  CheckState(cinfo, jpegli::kEncStart);
    922  jpegli_set_progressive_level(cinfo, 2);
    923 }
    924 
    925 void jpegli_set_progressive_level(j_compress_ptr cinfo, int level) {
    926  CheckState(cinfo, jpegli::kEncStart);
    927  if (level < 0) {
    928    JPEGLI_ERROR("Invalid progressive level %d", level);
    929  }
    930  cinfo->master->progressive_level = level;
    931 }
    932 
    933 void jpegli_set_input_format(j_compress_ptr cinfo, JpegliDataType data_type,
    934                             JpegliEndianness endianness) {
    935  CheckState(cinfo, jpegli::kEncStart);
    936  switch (data_type) {
    937    case JPEGLI_TYPE_UINT8:
    938    case JPEGLI_TYPE_UINT16:
    939    case JPEGLI_TYPE_FLOAT:
    940      cinfo->master->data_type = data_type;
    941      break;
    942    default:
    943      JPEGLI_ERROR("Unsupported data type %d", data_type);
    944  }
    945  switch (endianness) {
    946    case JPEGLI_NATIVE_ENDIAN:
    947    case JPEGLI_LITTLE_ENDIAN:
    948    case JPEGLI_BIG_ENDIAN:
    949      cinfo->master->endianness = endianness;
    950      break;
    951    default:
    952      JPEGLI_ERROR("Unsupported endianness %d", endianness);
    953  }
    954 }
    955 
    956 #if JPEG_LIB_VERSION >= 70
    957 void jpegli_calc_jpeg_dimensions(j_compress_ptr cinfo) {
    958  // Since input scaling is not supported, we just copy the image dimensions.
    959  cinfo->jpeg_width = cinfo->image_width;
    960  cinfo->jpeg_height = cinfo->image_height;
    961 }
    962 #endif
    963 
    964 void jpegli_copy_critical_parameters(j_decompress_ptr srcinfo,
    965                                     j_compress_ptr dstinfo) {
    966  CheckState(dstinfo, jpegli::kEncStart);
    967  // Image parameters.
    968  dstinfo->image_width = srcinfo->image_width;
    969  dstinfo->image_height = srcinfo->image_height;
    970  dstinfo->input_components = srcinfo->num_components;
    971  dstinfo->in_color_space = srcinfo->jpeg_color_space;
    972  dstinfo->input_gamma = srcinfo->output_gamma;
    973  // Compression parameters.
    974  jpegli_set_defaults(dstinfo);
    975  jpegli_set_colorspace(dstinfo, srcinfo->jpeg_color_space);
    976  if (dstinfo->num_components != srcinfo->num_components) {
    977    const auto& cinfo = dstinfo;
    978    JPEGLI_ERROR("Mismatch between src colorspace and components");
    979  }
    980  dstinfo->data_precision = srcinfo->data_precision;
    981  dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;
    982  dstinfo->JFIF_major_version = srcinfo->JFIF_major_version;
    983  dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version;
    984  dstinfo->density_unit = srcinfo->density_unit;
    985  dstinfo->X_density = srcinfo->X_density;
    986  dstinfo->Y_density = srcinfo->Y_density;
    987  for (int c = 0; c < dstinfo->num_components; ++c) {
    988    jpeg_component_info* srccomp = &srcinfo->comp_info[c];
    989    jpeg_component_info* dstcomp = &dstinfo->comp_info[c];
    990    dstcomp->component_id = srccomp->component_id;
    991    dstcomp->h_samp_factor = srccomp->h_samp_factor;
    992    dstcomp->v_samp_factor = srccomp->v_samp_factor;
    993    dstcomp->quant_tbl_no = srccomp->quant_tbl_no;
    994  }
    995  for (int i = 0; i < NUM_QUANT_TBLS; ++i) {
    996    if (!srcinfo->quant_tbl_ptrs[i]) continue;
    997    if (dstinfo->quant_tbl_ptrs[i] == nullptr) {
    998      dstinfo->quant_tbl_ptrs[i] = jpegli::Allocate<JQUANT_TBL>(dstinfo, 1);
    999    }
   1000    memcpy(dstinfo->quant_tbl_ptrs[i], srcinfo->quant_tbl_ptrs[i],
   1001           sizeof(JQUANT_TBL));
   1002    dstinfo->quant_tbl_ptrs[i]->sent_table = FALSE;
   1003  }
   1004 }
   1005 
   1006 void jpegli_suppress_tables(j_compress_ptr cinfo, boolean suppress) {
   1007  jpegli::SetSentTableFlag(cinfo->quant_tbl_ptrs, NUM_QUANT_TBLS, suppress);
   1008  jpegli::SetSentTableFlag(cinfo->dc_huff_tbl_ptrs, NUM_HUFF_TBLS, suppress);
   1009  jpegli::SetSentTableFlag(cinfo->ac_huff_tbl_ptrs, NUM_HUFF_TBLS, suppress);
   1010 }
   1011 
   1012 //
   1013 // Compressor initialization
   1014 //
   1015 
   1016 void jpegli_start_compress(j_compress_ptr cinfo, boolean write_all_tables) {
   1017  CheckState(cinfo, jpegli::kEncStart);
   1018  cinfo->global_state = jpegli::kEncHeader;
   1019  jpegli::InitCompress(cinfo, write_all_tables);
   1020  cinfo->next_scanline = 0;
   1021  cinfo->master->next_input_row = 0;
   1022 }
   1023 
   1024 void jpegli_write_coefficients(j_compress_ptr cinfo,
   1025                               jvirt_barray_ptr* coef_arrays) {
   1026  CheckState(cinfo, jpegli::kEncStart);
   1027  cinfo->global_state = jpegli::kEncWriteCoeffs;
   1028  jpegli::InitCompress(cinfo, /*write_all_tables=*/TRUE);
   1029  cinfo->master->coeff_buffers = coef_arrays;
   1030  cinfo->next_scanline = cinfo->image_height;
   1031  cinfo->master->next_input_row = cinfo->image_height;
   1032 }
   1033 
   1034 void jpegli_write_tables(j_compress_ptr cinfo) {
   1035  CheckState(cinfo, jpegli::kEncStart);
   1036  if (cinfo->dest == nullptr) {
   1037    JPEGLI_ERROR("Missing destination.");
   1038  }
   1039  jpeg_comp_master* m = cinfo->master;
   1040  (*cinfo->err->reset_error_mgr)(reinterpret_cast<j_common_ptr>(cinfo));
   1041  (*cinfo->dest->init_destination)(cinfo);
   1042  jpegli::WriteOutput(cinfo, {0xFF, 0xD8});  // SOI
   1043  jpegli::EncodeDQT(cinfo, /*write_all_tables=*/true);
   1044  jpegli::CopyHuffmanTables(cinfo);
   1045  jpegli::EncodeDHT(cinfo, 0, m->num_huffman_tables);
   1046  jpegli::WriteOutput(cinfo, {0xFF, 0xD9});  // EOI
   1047  (*cinfo->dest->term_destination)(cinfo);
   1048  jpegli_suppress_tables(cinfo, TRUE);
   1049 }
   1050 
   1051 //
   1052 // Marker writing
   1053 //
   1054 
   1055 void jpegli_write_m_header(j_compress_ptr cinfo, int marker,
   1056                           unsigned int datalen) {
   1057  CheckState(cinfo, jpegli::kEncHeader, jpegli::kEncWriteCoeffs);
   1058  if (datalen > jpegli::kMaxBytesInMarker) {
   1059    JPEGLI_ERROR("Invalid marker length %u", datalen);
   1060  }
   1061  if (marker != 0xfe && (marker < 0xe0 || marker > 0xef)) {
   1062    JPEGLI_ERROR(
   1063        "jpegli_write_m_header: Only APP and COM markers are supported.");
   1064  }
   1065  std::vector<uint8_t> marker_data(4 + datalen);
   1066  marker_data[0] = 0xff;
   1067  marker_data[1] = marker;
   1068  marker_data[2] = (datalen + 2) >> 8;
   1069  marker_data[3] = (datalen + 2) & 0xff;
   1070  jpegli::WriteOutput(cinfo, marker_data.data(), 4);
   1071 }
   1072 
   1073 void jpegli_write_m_byte(j_compress_ptr cinfo, int val) {
   1074  uint8_t data = val;
   1075  jpegli::WriteOutput(cinfo, &data, 1);
   1076 }
   1077 
   1078 void jpegli_write_marker(j_compress_ptr cinfo, int marker,
   1079                         const JOCTET* dataptr, unsigned int datalen) {
   1080  jpegli_write_m_header(cinfo, marker, datalen);
   1081  jpegli::WriteOutput(cinfo, dataptr, datalen);
   1082 }
   1083 
   1084 void jpegli_write_icc_profile(j_compress_ptr cinfo, const JOCTET* icc_data_ptr,
   1085                              unsigned int icc_data_len) {
   1086  constexpr size_t kMaxIccBytesInMarker =
   1087      jpegli::kMaxBytesInMarker - sizeof jpegli::kICCSignature - 2;
   1088  const int num_markers =
   1089      static_cast<int>(jpegli::DivCeil(icc_data_len, kMaxIccBytesInMarker));
   1090  size_t begin = 0;
   1091  for (int current_marker = 0; current_marker < num_markers; ++current_marker) {
   1092    const size_t length = std::min(kMaxIccBytesInMarker, icc_data_len - begin);
   1093    jpegli_write_m_header(
   1094        cinfo, jpegli::kICCMarker,
   1095        static_cast<unsigned int>(length + sizeof jpegli::kICCSignature + 2));
   1096    for (const unsigned char c : jpegli::kICCSignature) {
   1097      jpegli_write_m_byte(cinfo, c);
   1098    }
   1099    jpegli_write_m_byte(cinfo, current_marker + 1);
   1100    jpegli_write_m_byte(cinfo, num_markers);
   1101    for (size_t i = 0; i < length; ++i) {
   1102      jpegli_write_m_byte(cinfo, icc_data_ptr[begin]);
   1103      ++begin;
   1104    }
   1105  }
   1106 }
   1107 
   1108 //
   1109 // Input streaming
   1110 //
   1111 
   1112 JDIMENSION jpegli_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines,
   1113                                  JDIMENSION num_lines) {
   1114  CheckState(cinfo, jpegli::kEncHeader, jpegli::kEncReadImage);
   1115  if (cinfo->raw_data_in) {
   1116    JPEGLI_ERROR("jpegli_write_raw_data() must be called for raw data mode.");
   1117  }
   1118  jpegli::ProgressMonitorInputPass(cinfo);
   1119  if (cinfo->global_state == jpegli::kEncHeader &&
   1120      jpegli::IsStreamingSupported(cinfo) && !cinfo->optimize_coding) {
   1121    jpegli::WriteFrameHeader(cinfo);
   1122    jpegli::WriteScanHeader(cinfo, 0);
   1123  }
   1124  cinfo->global_state = jpegli::kEncReadImage;
   1125  jpeg_comp_master* m = cinfo->master;
   1126  if (num_lines + cinfo->next_scanline > cinfo->image_height) {
   1127    num_lines = cinfo->image_height - cinfo->next_scanline;
   1128  }
   1129  JDIMENSION prev_scanline = cinfo->next_scanline;
   1130  size_t input_lag = (std::min<size_t>(cinfo->image_height, m->next_input_row) -
   1131                      cinfo->next_scanline);
   1132  if (input_lag > num_lines) {
   1133    JPEGLI_ERROR("Need at least %u lines to continue", input_lag);
   1134  }
   1135  if (input_lag > 0) {
   1136    if (!jpegli::EmptyBitWriterBuffer(&m->bw)) {
   1137      return 0;
   1138    }
   1139    cinfo->next_scanline += input_lag;
   1140  }
   1141  float* rows[jpegli::kMaxComponents];
   1142  for (size_t i = input_lag; i < num_lines; ++i) {
   1143    jpegli::ReadInputRow(cinfo, scanlines[i], rows);
   1144    (*m->color_transform)(rows, cinfo->image_width);
   1145    jpegli::PadInputBuffer(cinfo, rows);
   1146    jpegli::ProcessiMCURows(cinfo);
   1147    if (!jpegli::EmptyBitWriterBuffer(&m->bw)) {
   1148      break;
   1149    }
   1150    ++cinfo->next_scanline;
   1151  }
   1152  return cinfo->next_scanline - prev_scanline;
   1153 }
   1154 
   1155 JDIMENSION jpegli_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
   1156                                 JDIMENSION num_lines) {
   1157  CheckState(cinfo, jpegli::kEncHeader, jpegli::kEncReadImage);
   1158  if (!cinfo->raw_data_in) {
   1159    JPEGLI_ERROR("jpegli_write_raw_data(): raw data mode was not set");
   1160  }
   1161  jpegli::ProgressMonitorInputPass(cinfo);
   1162  if (cinfo->global_state == jpegli::kEncHeader &&
   1163      jpegli::IsStreamingSupported(cinfo) && !cinfo->optimize_coding) {
   1164    jpegli::WriteFrameHeader(cinfo);
   1165    jpegli::WriteScanHeader(cinfo, 0);
   1166  }
   1167  cinfo->global_state = jpegli::kEncReadImage;
   1168  jpeg_comp_master* m = cinfo->master;
   1169  if (cinfo->next_scanline >= cinfo->image_height) {
   1170    return 0;
   1171  }
   1172  size_t iMCU_height = DCTSIZE * cinfo->max_v_samp_factor;
   1173  if (num_lines < iMCU_height) {
   1174    JPEGLI_ERROR("Missing input lines, minimum is %u", iMCU_height);
   1175  }
   1176  if (cinfo->next_scanline < m->next_input_row) {
   1177    JPEGLI_CHECK(m->next_input_row - cinfo->next_scanline == iMCU_height);
   1178    if (!jpegli::EmptyBitWriterBuffer(&m->bw)) {
   1179      return 0;
   1180    }
   1181    cinfo->next_scanline = m->next_input_row;
   1182    return iMCU_height;
   1183  }
   1184  size_t iMCU_y = m->next_input_row / iMCU_height;
   1185  float* rows[jpegli::kMaxComponents];
   1186  for (int c = 0; c < cinfo->num_components; ++c) {
   1187    JSAMPARRAY plane = data[c];
   1188    jpeg_component_info* comp = &cinfo->comp_info[c];
   1189    size_t xsize = comp->width_in_blocks * DCTSIZE;
   1190    size_t ysize = comp->v_samp_factor * DCTSIZE;
   1191    size_t y0 = iMCU_y * ysize;
   1192    auto& buffer = m->input_buffer[c];
   1193    for (size_t i = 0; i < ysize; ++i) {
   1194      rows[0] = buffer.Row(y0 + i);
   1195      if (plane[i] == nullptr) {
   1196        memset(rows[0], 0, xsize * sizeof(rows[0][0]));
   1197      } else {
   1198        (*m->input_method)(plane[i], xsize, rows);
   1199      }
   1200      // We need a border of 1 repeated pixel for adaptive quant field.
   1201      buffer.PadRow(y0 + i, xsize, /*border=*/1);
   1202    }
   1203  }
   1204  m->next_input_row += iMCU_height;
   1205  jpegli::ProcessiMCURows(cinfo);
   1206  if (!jpegli::EmptyBitWriterBuffer(&m->bw)) {
   1207    return 0;
   1208  }
   1209  cinfo->next_scanline += iMCU_height;
   1210  return iMCU_height;
   1211 }
   1212 
   1213 //
   1214 // Non-streaming part
   1215 //
   1216 
   1217 void jpegli_finish_compress(j_compress_ptr cinfo) {
   1218  CheckState(cinfo, jpegli::kEncReadImage, jpegli::kEncWriteCoeffs);
   1219  jpeg_comp_master* m = cinfo->master;
   1220  if (cinfo->next_scanline < cinfo->image_height) {
   1221    JPEGLI_ERROR("Incomplete image, expected %d rows, got %d",
   1222                 cinfo->image_height, cinfo->next_scanline);
   1223  }
   1224 
   1225  if (cinfo->global_state == jpegli::kEncWriteCoeffs) {
   1226    // Zig-zag shuffle all the blocks. For non-transcoding case it was already
   1227    // done in EncodeiMCURow().
   1228    jpegli::ZigZagShuffleBlocks(cinfo);
   1229  }
   1230 
   1231  if (m->psnr_target > 0) {
   1232    jpegli::QuantizetoPSNR(cinfo);
   1233  }
   1234 
   1235  const bool tokens_done = jpegli::IsStreamingSupported(cinfo);
   1236  const bool bitstream_done =
   1237      tokens_done && !FROM_JXL_BOOL(cinfo->optimize_coding);
   1238 
   1239  if (!tokens_done) {
   1240    jpegli::TokenizeJpeg(cinfo);
   1241  }
   1242 
   1243  if (cinfo->optimize_coding || cinfo->progressive_mode) {
   1244    jpegli::OptimizeHuffmanCodes(cinfo);
   1245    jpegli::InitEntropyCoder(cinfo);
   1246  }
   1247 
   1248  if (!bitstream_done) {
   1249    jpegli::WriteFrameHeader(cinfo);
   1250    for (int i = 0; i < cinfo->num_scans; ++i) {
   1251      jpegli::WriteScanHeader(cinfo, i);
   1252      jpegli::WriteScanData(cinfo, i);
   1253    }
   1254  } else {
   1255    JumpToByteBoundary(&m->bw);
   1256    if (!EmptyBitWriterBuffer(&m->bw)) {
   1257      JPEGLI_ERROR("Output suspension is not supported in finish_compress");
   1258    }
   1259  }
   1260 
   1261  jpegli::WriteOutput(cinfo, {0xFF, 0xD9});  // EOI
   1262  (*cinfo->dest->term_destination)(cinfo);
   1263 
   1264  // Release memory and reset global state.
   1265  jpegli_abort_compress(cinfo);
   1266 }
   1267 
   1268 void jpegli_abort_compress(j_compress_ptr cinfo) {
   1269  jpegli_abort(reinterpret_cast<j_common_ptr>(cinfo));
   1270 }
   1271 
   1272 void jpegli_destroy_compress(j_compress_ptr cinfo) {
   1273  jpegli_destroy(reinterpret_cast<j_common_ptr>(cinfo));
   1274 }