4 * This file was part of the Independent JPEG Group's software:
5 * Copyright (C) 1994-1996, Thomas G. Lane.
6 * libjpeg-turbo Modifications:
7 * Copyright (C) 2022-2023, D. R. Commander.
8 * For conditions of distribution and use, see the accompanying README.ijg
11 * This file contains the decompression postprocessing controller.
12 * This controller manages the upsampling, color conversion, and color
13 * quantization/reduction steps; specifically, it controls the buffering
14 * between upsample/color conversion and color quantization/reduction.
16 * If no color quantization/reduction is required, then this module has no
17 * work to do, and it just hands off to the upsample/color conversion code.
18 * An integrated upsample/convert/quantize process would replace this module
22 #define JPEG_INTERNALS
25 #include "jsamplecomp.h"
28 #if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
30 /* Private buffer controller object */
33 struct jpeg_d_post_controller pub
; /* public fields */
35 /* Color quantization source buffer: this holds output data from
36 * the upsample/color conversion step to be passed to the quantizer.
37 * For two-pass color quantization, we need a full-image buffer;
38 * for one-pass operation, a strip buffer is sufficient.
40 jvirt_sarray_ptr whole_image
; /* virtual array, or NULL if one-pass */
41 _JSAMPARRAY buffer
; /* strip buffer, or current strip of virtual */
42 JDIMENSION strip_height
; /* buffer size in rows */
43 /* for two-pass mode only: */
44 JDIMENSION starting_row
; /* row # of first row in current strip */
45 JDIMENSION next_row
; /* index of next row to fill/empty in strip */
48 typedef my_post_controller
*my_post_ptr
;
51 /* Forward declarations */
52 #if BITS_IN_JSAMPLE != 16
53 METHODDEF(void) post_process_1pass(j_decompress_ptr cinfo
,
54 _JSAMPIMAGE input_buf
,
55 JDIMENSION
*in_row_group_ctr
,
56 JDIMENSION in_row_groups_avail
,
57 _JSAMPARRAY output_buf
,
58 JDIMENSION
*out_row_ctr
,
59 JDIMENSION out_rows_avail
);
61 #if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
62 METHODDEF(void) post_process_prepass(j_decompress_ptr cinfo
,
63 _JSAMPIMAGE input_buf
,
64 JDIMENSION
*in_row_group_ctr
,
65 JDIMENSION in_row_groups_avail
,
66 _JSAMPARRAY output_buf
,
67 JDIMENSION
*out_row_ctr
,
68 JDIMENSION out_rows_avail
);
69 METHODDEF(void) post_process_2pass(j_decompress_ptr cinfo
,
70 _JSAMPIMAGE input_buf
,
71 JDIMENSION
*in_row_group_ctr
,
72 JDIMENSION in_row_groups_avail
,
73 _JSAMPARRAY output_buf
,
74 JDIMENSION
*out_row_ctr
,
75 JDIMENSION out_rows_avail
);
80 * Initialize for a processing pass.
84 start_pass_dpost(j_decompress_ptr cinfo
, J_BUF_MODE pass_mode
)
86 my_post_ptr post
= (my_post_ptr
)cinfo
->post
;
90 #if BITS_IN_JSAMPLE != 16
91 if (cinfo
->quantize_colors
) {
92 /* Single-pass processing with color quantization. */
93 post
->pub
._post_process_data
= post_process_1pass
;
94 /* We could be doing buffered-image output before starting a 2-pass
95 * color quantization; in that case, jinit_d_post_controller did not
96 * allocate a strip buffer. Use the virtual-array buffer as workspace.
98 if (post
->buffer
== NULL
) {
99 post
->buffer
= (_JSAMPARRAY
)(*cinfo
->mem
->access_virt_sarray
)
100 ((j_common_ptr
)cinfo
, post
->whole_image
,
101 (JDIMENSION
)0, post
->strip_height
, TRUE
);
106 /* For single-pass processing without color quantization,
107 * I have no work to do; just call the upsampler directly.
109 post
->pub
._post_process_data
= cinfo
->upsample
->_upsample
;
112 #if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
113 case JBUF_SAVE_AND_PASS
:
114 /* First pass of 2-pass quantization */
115 if (post
->whole_image
== NULL
)
116 ERREXIT(cinfo
, JERR_BAD_BUFFER_MODE
);
117 post
->pub
._post_process_data
= post_process_prepass
;
119 case JBUF_CRANK_DEST
:
120 /* Second pass of 2-pass quantization */
121 if (post
->whole_image
== NULL
)
122 ERREXIT(cinfo
, JERR_BAD_BUFFER_MODE
);
123 post
->pub
._post_process_data
= post_process_2pass
;
125 #endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
127 ERREXIT(cinfo
, JERR_BAD_BUFFER_MODE
);
130 post
->starting_row
= post
->next_row
= 0;
135 * Process some data in the one-pass (strip buffer) case.
136 * This is used for color precision reduction as well as one-pass quantization.
139 #if BITS_IN_JSAMPLE != 16
142 post_process_1pass(j_decompress_ptr cinfo
, _JSAMPIMAGE input_buf
,
143 JDIMENSION
*in_row_group_ctr
,
144 JDIMENSION in_row_groups_avail
, _JSAMPARRAY output_buf
,
145 JDIMENSION
*out_row_ctr
, JDIMENSION out_rows_avail
)
147 my_post_ptr post
= (my_post_ptr
)cinfo
->post
;
148 JDIMENSION num_rows
, max_rows
;
150 /* Fill the buffer, but not more than what we can dump out in one go. */
151 /* Note we rely on the upsampler to detect bottom of image. */
152 max_rows
= out_rows_avail
- *out_row_ctr
;
153 if (max_rows
> post
->strip_height
)
154 max_rows
= post
->strip_height
;
156 (*cinfo
->upsample
->_upsample
) (cinfo
, input_buf
, in_row_group_ctr
,
157 in_row_groups_avail
, post
->buffer
, &num_rows
,
159 /* Quantize and emit data. */
160 (*cinfo
->cquantize
->_color_quantize
) (cinfo
, post
->buffer
,
161 output_buf
+ *out_row_ctr
,
163 *out_row_ctr
+= num_rows
;
169 #if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
172 * Process some data in the first pass of 2-pass quantization.
176 post_process_prepass(j_decompress_ptr cinfo
, _JSAMPIMAGE input_buf
,
177 JDIMENSION
*in_row_group_ctr
,
178 JDIMENSION in_row_groups_avail
, _JSAMPARRAY output_buf
,
179 JDIMENSION
*out_row_ctr
, JDIMENSION out_rows_avail
)
181 my_post_ptr post
= (my_post_ptr
)cinfo
->post
;
182 JDIMENSION old_next_row
, num_rows
;
184 /* Reposition virtual buffer if at start of strip. */
185 if (post
->next_row
== 0) {
186 post
->buffer
= (_JSAMPARRAY
)(*cinfo
->mem
->access_virt_sarray
)
187 ((j_common_ptr
)cinfo
, post
->whole_image
,
188 post
->starting_row
, post
->strip_height
, TRUE
);
191 /* Upsample some data (up to a strip height's worth). */
192 old_next_row
= post
->next_row
;
193 (*cinfo
->upsample
->_upsample
) (cinfo
, input_buf
, in_row_group_ctr
,
194 in_row_groups_avail
, post
->buffer
,
195 &post
->next_row
, post
->strip_height
);
197 /* Allow quantizer to scan new data. No data is emitted, */
198 /* but we advance out_row_ctr so outer loop can tell when we're done. */
199 if (post
->next_row
> old_next_row
) {
200 num_rows
= post
->next_row
- old_next_row
;
201 (*cinfo
->cquantize
->_color_quantize
) (cinfo
, post
->buffer
+ old_next_row
,
202 (_JSAMPARRAY
)NULL
, (int)num_rows
);
203 *out_row_ctr
+= num_rows
;
206 /* Advance if we filled the strip. */
207 if (post
->next_row
>= post
->strip_height
) {
208 post
->starting_row
+= post
->strip_height
;
215 * Process some data in the second pass of 2-pass quantization.
219 post_process_2pass(j_decompress_ptr cinfo
, _JSAMPIMAGE input_buf
,
220 JDIMENSION
*in_row_group_ctr
,
221 JDIMENSION in_row_groups_avail
, _JSAMPARRAY output_buf
,
222 JDIMENSION
*out_row_ctr
, JDIMENSION out_rows_avail
)
224 my_post_ptr post
= (my_post_ptr
)cinfo
->post
;
225 JDIMENSION num_rows
, max_rows
;
227 /* Reposition virtual buffer if at start of strip. */
228 if (post
->next_row
== 0) {
229 post
->buffer
= (_JSAMPARRAY
)(*cinfo
->mem
->access_virt_sarray
)
230 ((j_common_ptr
)cinfo
, post
->whole_image
,
231 post
->starting_row
, post
->strip_height
, FALSE
);
234 /* Determine number of rows to emit. */
235 num_rows
= post
->strip_height
- post
->next_row
; /* available in strip */
236 max_rows
= out_rows_avail
- *out_row_ctr
; /* available in output area */
237 if (num_rows
> max_rows
)
239 /* We have to check bottom of image here, can't depend on upsampler. */
240 max_rows
= cinfo
->output_height
- post
->starting_row
;
241 if (num_rows
> max_rows
)
244 /* Quantize and emit data. */
245 (*cinfo
->cquantize
->_color_quantize
) (cinfo
, post
->buffer
+ post
->next_row
,
246 output_buf
+ *out_row_ctr
,
248 *out_row_ctr
+= num_rows
;
250 /* Advance if we filled the strip. */
251 post
->next_row
+= num_rows
;
252 if (post
->next_row
>= post
->strip_height
) {
253 post
->starting_row
+= post
->strip_height
;
258 #endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
262 * Initialize postprocessing controller.
266 _jinit_d_post_controller(j_decompress_ptr cinfo
, boolean need_full_buffer
)
270 if (cinfo
->data_precision
!= BITS_IN_JSAMPLE
)
271 ERREXIT1(cinfo
, JERR_BAD_PRECISION
, cinfo
->data_precision
);
274 (*cinfo
->mem
->alloc_small
) ((j_common_ptr
)cinfo
, JPOOL_IMAGE
,
275 sizeof(my_post_controller
));
276 cinfo
->post
= (struct jpeg_d_post_controller
*)post
;
277 post
->pub
.start_pass
= start_pass_dpost
;
278 post
->whole_image
= NULL
; /* flag for no virtual arrays */
279 post
->buffer
= NULL
; /* flag for no strip buffer */
281 /* Create the quantization buffer, if needed */
282 if (cinfo
->quantize_colors
) {
283 #if BITS_IN_JSAMPLE != 16
284 /* The buffer strip height is max_v_samp_factor, which is typically
285 * an efficient number of rows for upsampling to return.
286 * (In the presence of output rescaling, we might want to be smarter?)
288 post
->strip_height
= (JDIMENSION
)cinfo
->max_v_samp_factor
;
289 if (need_full_buffer
) {
290 /* Two-pass color quantization: need full-image storage. */
291 /* We round up the number of rows to a multiple of the strip height. */
292 #ifdef QUANT_2PASS_SUPPORTED
293 post
->whole_image
= (*cinfo
->mem
->request_virt_sarray
)
294 ((j_common_ptr
)cinfo
, JPOOL_IMAGE
, FALSE
,
295 cinfo
->output_width
* cinfo
->out_color_components
,
296 (JDIMENSION
)jround_up((long)cinfo
->output_height
,
297 (long)post
->strip_height
),
300 ERREXIT(cinfo
, JERR_BAD_BUFFER_MODE
);
301 #endif /* QUANT_2PASS_SUPPORTED */
303 /* One-pass color quantization: just make a strip buffer. */
304 post
->buffer
= (_JSAMPARRAY
)(*cinfo
->mem
->alloc_sarray
)
305 ((j_common_ptr
)cinfo
, JPOOL_IMAGE
,
306 cinfo
->output_width
* cinfo
->out_color_components
,
310 ERREXIT(cinfo
, JERR_NOTIMPL
);
315 #endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */