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"
11 #include <initializer_list>
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"
31 constexpr size_t kMaxBytesInMarker
= 65533;
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
);
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
);
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;
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;
71 #if JPEG_LIB_VERSION >= 70
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
;
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
;
84 float LinearQualityToDistance(int scale_factor
) {
85 scale_factor
= std::min(5000, std::max(0, scale_factor
));
87 scale_factor
< 100 ? 100 - scale_factor
/ 2 : 5000 / scale_factor
;
88 return jpegli_quality_to_distance(quality
);
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
;
99 // Compressor initialization
102 struct ProgressiveScan
{
107 void SetDefaultScanScript(j_compress_ptr cinfo
) {
108 int level
= cinfo
->master
->progressive_level
;
109 std::vector
<ProgressiveScan
> progressive_mode
;
111 (cinfo
->max_h_samp_factor
== 1 && cinfo
->max_v_samp_factor
== 1);
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});
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});
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
);
131 cinfo
->script_space
=
132 Allocate
<jpeg_scan_info
>(cinfo
, cinfo
->script_space_size
);
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
;
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
;
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;
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
);
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
);
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
);
180 if (si
.Ah
< 0 || si
.Al
< 0 || si
.Al
> kMaxRefinementBit
) {
181 JPEGLI_ERROR("Invalid refinement bits %d/%d", si
.Ah
, si
.Al
);
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");
188 if (si
.Ss
== 0 && si
.Se
!= 0) {
189 JPEGLI_ERROR("DC and AC together in progressive scan");
192 if (si
.Ss
!= 0 && si
.comps_in_scan
!= 1) {
193 JPEGLI_ERROR("Interleaved AC only scan.");
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
);
200 for (int k
= si
.Ss
; k
<= si
.Se
; ++k
) {
201 if (comp_mask
[ci
][k
] == 0) {
203 JPEGLI_ERROR("Invalid first scan refinement bit");
205 comp_mask
[ci
][k
] = ((0xffff << si
.Al
) & 0xffff);
207 if (comp_mask
[ci
][k
] != ((0xffff << si
.Ah
) & 0xffff) ||
208 si
.Al
!= si
.Ah
- 1) {
209 JPEGLI_ERROR("Invalid refinement bit progression.");
211 comp_mask
[ci
][k
] |= 1 << si
.Al
;
215 if (si
.comps_in_scan
> 1) {
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
;
222 if (mcu_size
> C_MAX_BLOCKS_IN_MCU
) {
223 JPEGLI_ERROR("MCU size too big");
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
);
236 void ProcessCompressionParams(j_compress_ptr cinfo
) {
237 if (cinfo
->dest
== nullptr) {
238 JPEGLI_ERROR("Missing destination.");
240 if (cinfo
->image_width
< 1 || cinfo
->image_height
< 1 ||
241 cinfo
->input_components
< 1) {
242 JPEGLI_ERROR("Empty input image.");
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.");
249 if (cinfo
->num_components
< 1 ||
250 cinfo
->num_components
> static_cast<int>(kMaxComponents
)) {
251 JPEGLI_ERROR("Invalid number of components.");
253 if (cinfo
->data_precision
!= kJpegPrecision
) {
254 JPEGLI_ERROR("Invalid data precision");
256 if (cinfo
->arith_code
) {
257 JPEGLI_ERROR("Arithmetic coding is not implemented.");
259 if (cinfo
->CCIR601_sampling
) {
260 JPEGLI_ERROR("CCIR601 sampling is not implemented.");
262 if (cinfo
->restart_interval
> 65535u) {
263 JPEGLI_ERROR("Restart interval too big");
265 if (cinfo
->smoothing_factor
< 0 || cinfo
->smoothing_factor
> 100) {
266 JPEGLI_ERROR("Invalid smoothing factor %d", cinfo
->smoothing_factor
);
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");
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
);
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
);
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;
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
);
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
;
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.");
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
;
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;
325 if (cinfo
->scan_info
== nullptr) {
326 SetDefaultScanScript(cinfo
);
328 cinfo
->progressive_mode
= TO_JXL_BOOL(cinfo
->scan_info
->Ss
!= 0 ||
329 cinfo
->scan_info
->Se
!= DCTSIZE2
- 1);
330 ValidateScanScript(cinfo
);
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
;
342 if (num_ac_contexts
> 252) {
343 JPEGLI_ERROR("Too many AC scans in image");
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;
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
;
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
;
369 sti
->restart_interval
=
370 std::min
<size_t>(sti
->MCUs_per_row
* cinfo
->restart_in_rows
, 65535u);
372 sti
->num_restarts
= sti
->restart_interval
> 0
373 ? DivCeil(num_MCUs
, sti
->restart_interval
)
375 sti
->restarts
= Allocate
<size_t>(cinfo
, sti
->num_restarts
, JPOOL_IMAGE
);
377 m
->num_contexts
= 4 + num_ac_contexts
;
380 bool IsStreamingSupported(j_compress_ptr cinfo
) {
381 if (cinfo
->global_state
== kEncWriteCoeffs
) {
384 // TODO(szabadka) Remove this restriction.
385 if (cinfo
->restart_interval
> 0 || cinfo
->restart_in_rows
> 0) {
388 if (cinfo
->num_scans
> 1) {
391 if (cinfo
->master
->psnr_target
> 0) {
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
));
407 m
->total_num_tokens
= 0;
409 if (cinfo
->global_state
== kEncWriteCoeffs
) {
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
);
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
);
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
);
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
);
441 m
->quant_mul
[c
] = Allocate
<float>(cinfo
, DCTSIZE2
, JPOOL_IMAGE_ALIGNED
);
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
)) {
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
);
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
;
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
;
471 m
->quant_field
.Allocate(cinfo
, qf_height
, xsize_blocks
);
473 m
->quant_field
.Allocate(cinfo
, 1, m
->xsize_blocks
);
474 m
->quant_field
.FillRow(0, 0, m
->xsize_blocks
);
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));
485 void InitProgressMonitor(j_compress_ptr cinfo
) {
486 if (cinfo
->progress
== nullptr) {
489 if (IsStreamingSupported(cinfo
)) {
490 // We have only one input pass.
491 cinfo
->progress
->total_passes
= 1;
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
;
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
);
513 QuantPass pass
= m
->psnr_target
> 0 ? QuantPass::SEARCH_FIRST_PASS
514 : QuantPass::NO_SEARCH
;
515 InitQuantizer(cinfo
, pass
);
517 if (write_all_tables
) {
518 jpegli_suppress_tables(cinfo
, FALSE
);
520 if (!cinfo
->optimize_coding
&& !cinfo
->progressive_mode
) {
521 CopyHuffmanTables(cinfo
);
522 InitEntropyCoder(cinfo
);
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;
536 void ProgressMonitorInputPass(j_compress_ptr cinfo
) {
537 if (cinfo
->progress
== nullptr) {
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
));
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
);
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]));
561 (*m
->input_method
)(scanline
, cinfo
->image_width
, row
);
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
;
575 row
[c
][-1] = row
[c
][0];
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]));
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
);
595 ComputeAdaptiveQuantField(cinfo
);
596 if (IsStreamingSupported(cinfo
)) {
597 if (cinfo
->optimize_coding
) {
598 ComputeTokensForiMCURow(cinfo
);
603 ComputeCoefficientsForiMCURow(cinfo
);
605 ++cinfo
->master
->next_iMCU_row
;
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
);
617 if (m
->next_input_row
>= cinfo
->image_height
) {
618 ProcessiMCURow(cinfo
);
623 // Non-streaming part
626 void ZigZagShuffleBlocks(j_compress_ptr cinfo
) {
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
]];
637 memcpy(block
, tmp
, sizeof(tmp
));
643 } // namespace jpegli
649 void jpegli_CreateCompress(j_compress_ptr cinfo
, int version
,
651 cinfo
->mem
= nullptr;
652 if (structsize
!= sizeof(*cinfo
)) {
653 JPEGLI_ERROR("jpegli_compress_struct has wrong size.");
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;
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;
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;
692 void jpegli_set_xyb_mode(j_compress_ptr cinfo
) {
693 CheckState(cinfo
, jpegli::kEncStart
);
694 cinfo
->master
->xyb_mode
= true;
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
;
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
),
710 jpegli::AddStandardHuffmanTables(reinterpret_cast<j_common_ptr
>(cinfo
),
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
);
720 switch (cinfo
->in_color_space
) {
722 jpegli_set_colorspace(cinfo
, JCS_GRAYSCALE
);
725 #ifdef JCS_EXTENSIONS
733 #if JCS_ALPHA_EXTENSIONS
739 jpegli_set_colorspace(cinfo
, JCS_YCbCr
);
742 jpegli_set_colorspace(cinfo
, JCS_YCbCr
);
745 jpegli_set_colorspace(cinfo
, JCS_CMYK
);
748 jpegli_set_colorspace(cinfo
, JCS_YCCK
);
751 jpegli_set_colorspace(cinfo
, JCS_UNKNOWN
);
754 JPEGLI_ERROR("Unsupported input colorspace %d", cinfo
->in_color_space
);
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
) {
763 cinfo
->num_components
= 1;
767 cinfo
->num_components
= 3;
771 cinfo
->num_components
= 4;
774 cinfo
->num_components
=
775 std::min
<int>(jpegli::kMaxComponents
, cinfo
->input_components
);
778 JPEGLI_ERROR("Unsupported jpeg colorspace %d", colorspace
);
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) {
784 jpegli::Allocate
<jpeg_component_info
>(cinfo
, MAX_COMPONENTS
);
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;
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;
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;
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);
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
);
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
;
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);
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);
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
]);
880 jpegli::SetQuantMatrices(cinfo
, distances
, /*add_two_chroma_tables=*/false);
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
;
889 void jpegli_use_standard_quant_tables(j_compress_ptr cinfo
) {
890 CheckState(cinfo
, jpegli::kEncStart
);
891 cinfo
->master
->use_std_tables
= true;
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
);
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
));
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
;
912 quant_table
->sent_table
= FALSE
;
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
);
920 void jpegli_simple_progression(j_compress_ptr cinfo
) {
921 CheckState(cinfo
, jpegli::kEncStart
);
922 jpegli_set_progressive_level(cinfo
, 2);
925 void jpegli_set_progressive_level(j_compress_ptr cinfo
, int level
) {
926 CheckState(cinfo
, jpegli::kEncStart
);
928 JPEGLI_ERROR("Invalid progressive level %d", level
);
930 cinfo
->master
->progressive_level
= level
;
933 void jpegli_set_input_format(j_compress_ptr cinfo
, JpegliDataType data_type
,
934 JpegliEndianness endianness
) {
935 CheckState(cinfo
, jpegli::kEncStart
);
937 case JPEGLI_TYPE_UINT8
:
938 case JPEGLI_TYPE_UINT16
:
939 case JPEGLI_TYPE_FLOAT
:
940 cinfo
->master
->data_type
= data_type
;
943 JPEGLI_ERROR("Unsupported data type %d", data_type
);
945 switch (endianness
) {
946 case JPEGLI_NATIVE_ENDIAN
:
947 case JPEGLI_LITTLE_ENDIAN
:
948 case JPEGLI_BIG_ENDIAN
:
949 cinfo
->master
->endianness
= endianness
;
952 JPEGLI_ERROR("Unsupported endianness %d", endianness
);
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
;
964 void jpegli_copy_critical_parameters(j_decompress_ptr srcinfo
,
965 j_compress_ptr dstinfo
) {
966 CheckState(dstinfo
, jpegli::kEncStart
);
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");
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
;
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);
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
;
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
);
1013 // Compressor initialization
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;
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
;
1034 void jpegli_write_tables(j_compress_ptr cinfo
) {
1035 CheckState(cinfo
, jpegli::kEncStart
);
1036 if (cinfo
->dest
== nullptr) {
1037 JPEGLI_ERROR("Missing destination.");
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
);
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
);
1061 if (marker
!= 0xfe && (marker
< 0xe0 || marker
> 0xef)) {
1063 "jpegli_write_m_header: Only APP and COM markers are supported.");
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);
1073 void jpegli_write_m_byte(j_compress_ptr cinfo
, int val
) {
1075 jpegli::WriteOutput(cinfo
, &data
, 1);
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
);
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
));
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
);
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
]);
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.");
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);
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
;
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
);
1135 if (input_lag
> 0) {
1136 if (!jpegli::EmptyBitWriterBuffer(&m
->bw
)) {
1139 cinfo
->next_scanline
+= input_lag
;
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
)) {
1150 ++cinfo
->next_scanline
;
1152 return cinfo
->next_scanline
- prev_scanline
;
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");
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);
1167 cinfo
->global_state
= jpegli::kEncReadImage
;
1168 jpeg_comp_master
* m
= cinfo
->master
;
1169 if (cinfo
->next_scanline
>= cinfo
->image_height
) {
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
);
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
)) {
1181 cinfo
->next_scanline
= m
->next_input_row
;
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]));
1198 (*m
->input_method
)(plane
[i
], xsize
, rows
);
1200 // We need a border of 1 repeated pixel for adaptive quant field.
1201 buffer
.PadRow(y0
+ i
, xsize
, /*border=*/1);
1204 m
->next_input_row
+= iMCU_height
;
1205 jpegli::ProcessiMCURows(cinfo
);
1206 if (!jpegli::EmptyBitWriterBuffer(&m
->bw
)) {
1209 cinfo
->next_scanline
+= iMCU_height
;
1214 // Non-streaming part
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
);
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
);
1231 if (m
->psnr_target
> 0) {
1232 jpegli::QuantizetoPSNR(cinfo
);
1235 const bool tokens_done
= jpegli::IsStreamingSupported(cinfo
);
1236 const bool bitstream_done
=
1237 tokens_done
&& !FROM_JXL_BOOL(cinfo
->optimize_coding
);
1240 jpegli::TokenizeJpeg(cinfo
);
1243 if (cinfo
->optimize_coding
|| cinfo
->progressive_mode
) {
1244 jpegli::OptimizeHuffmanCodes(cinfo
);
1245 jpegli::InitEntropyCoder(cinfo
);
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
);
1255 JumpToByteBoundary(&m
->bw
);
1256 if (!EmptyBitWriterBuffer(&m
->bw
)) {
1257 JPEGLI_ERROR("Output suspension is not supported in finish_compress");
1261 jpegli::WriteOutput(cinfo
, {0xFF, 0xD9}); // EOI
1262 (*cinfo
->dest
->term_destination
)(cinfo
);
1264 // Release memory and reset global state.
1265 jpegli_abort_compress(cinfo
);
1268 void jpegli_abort_compress(j_compress_ptr cinfo
) {
1269 jpegli_abort(reinterpret_cast<j_common_ptr
>(cinfo
));
1272 void jpegli_destroy_compress(j_compress_ptr cinfo
) {
1273 jpegli_destroy(reinterpret_cast<j_common_ptr
>(cinfo
));