1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
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"
9 #include <initializer_list>
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"
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
);
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;
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;
69 #if JPEG_LIB_VERSION >= 70
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
;
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
));
85 scale_factor
< 100 ? 100 - scale_factor
/ 2 : 5000 / scale_factor
;
86 return jpegli_quality_to_distance(quality
);
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
{
105 void SetDefaultScanScript(j_compress_ptr cinfo
) {
106 int level
= cinfo
->master
->progressive_level
;
107 std::vector
<ProgressiveScan
> progressive_mode
;
109 (cinfo
->max_h_samp_factor
== 1 && cinfo
->max_v_samp_factor
== 1);
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});
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
;
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
);
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
);
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");
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) {
201 JPEGLI_ERROR("Invalid first scan refinement bit");
203 comp_mask
[ci
][k
] = ((0xffff << si
.Al
) & 0xffff);
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) {
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
);
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;
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
;
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
)
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
) {
382 // TODO(szabadka) Remove this restriction.
383 if (cinfo
->restart_interval
> 0 || cinfo
->restart_in_rows
> 0) {
386 if (cinfo
->num_scans
> 1) {
389 if (cinfo
->master
->psnr_target
> 0) {
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
));
405 m
->total_num_tokens
= 0;
407 if (cinfo
->global_state
== kEncWriteCoeffs
) {
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
)) {
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
;
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
);
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) {
487 if (IsStreamingSupported(cinfo
)) {
488 // We have only one input pass.
489 cinfo
->progress
->total_passes
= 1;
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;
534 void ProgressMonitorInputPass(j_compress_ptr cinfo
) {
535 if (cinfo
->progress
== nullptr) {
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
);
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]));
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]));
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
);
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
) {
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
647 void jpegli_CreateCompress(j_compress_ptr cinfo
, int version
,
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
),
708 jpegli::AddStandardHuffmanTables(reinterpret_cast<j_common_ptr
>(cinfo
),
712 void jpegli_default_colorspace(j_compress_ptr cinfo
) {
713 CheckState(cinfo
, jpegli::kEncStart
);
714 switch (cinfo
->in_color_space
) {
716 jpegli_set_colorspace(cinfo
, JCS_GRAYSCALE
);
719 if (cinfo
->master
->xyb_mode
) {
720 jpegli_set_colorspace(cinfo
, JCS_RGB
);
722 jpegli_set_colorspace(cinfo
, JCS_YCbCr
);
727 jpegli_set_colorspace(cinfo
, JCS_YCbCr
);
730 jpegli_set_colorspace(cinfo
, JCS_CMYK
);
733 jpegli_set_colorspace(cinfo
, JCS_YCCK
);
736 jpegli_set_colorspace(cinfo
, JCS_UNKNOWN
);
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
) {
748 cinfo
->num_components
= 1;
752 cinfo
->num_components
= 3;
756 cinfo
->num_components
= 4;
759 cinfo
->num_components
=
760 std::min
<int>(jpegli::kMaxComponents
, cinfo
->input_components
);
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) {
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;
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);
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
);
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
);
917 case JPEGLI_TYPE_UINT8
:
918 case JPEGLI_TYPE_UINT16
:
919 case JPEGLI_TYPE_FLOAT
:
920 cinfo
->master
->data_type
= data_type
;
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
;
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
;
944 void jpegli_copy_critical_parameters(j_decompress_ptr srcinfo
,
945 j_compress_ptr dstinfo
) {
946 CheckState(dstinfo
, jpegli::kEncStart
);
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
],
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
);
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)) {
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
) {
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
));
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
]);
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
)) {
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
)) {
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
) {
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
)) {
1161 cinfo
->next_scanline
= m
->next_input_row
;
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]));
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
)) {
1189 cinfo
->next_scanline
+= 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
;
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
);
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
));