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