blob: d6fa61a4b8a632cddadd6f7009d1667c11113129 [file] [log] [blame]
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +00001/*
2 * jdpostct.c
3 *
4 * Copyright (C) 1994, Thomas G. Lane.
5 * This file is part of the Independent JPEG Group's software.
6 * For conditions of distribution and use, see the accompanying README file.
7 *
8 * This file contains the decompression postprocessing controller.
9 * This controller manages the upsampling, color conversion, and color
10 * quantization/reduction steps; specifically, it controls the buffering
11 * between upsample/color conversion and color quantization/reduction.
12 *
13 * If no color quantization/reduction is required, then this module has no
14 * work to do, and it just hands off to the upsample/color conversion code.
15 * An integrated upsample/convert/quantize process would replace this module
16 * entirely.
17 */
18
19#define JPEG_INTERNALS
20#include "jinclude.h"
21#include "jpeglib.h"
22
23
24/* Private buffer controller object */
25
26typedef struct {
27 struct jpeg_d_post_controller pub; /* public fields */
28
29 /* Color quantization source buffer: this holds output data from
30 * the upsample/color conversion step to be passed to the quantizer.
31 * For two-pass color quantization, we need a full-image buffer;
32 * for one-pass operation, a strip buffer is sufficient.
33 */
34 jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */
35 JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
36 JDIMENSION strip_height; /* buffer size in rows */
37 /* for two-pass mode only: */
38 JDIMENSION starting_row; /* row # of first row in current strip */
39 JDIMENSION next_row; /* index of next row to fill/empty in strip */
40} my_post_controller;
41
42typedef my_post_controller * my_post_ptr;
43
44
45/* Forward declarations */
46METHODDEF void post_process_1pass
47 JPP((j_decompress_ptr cinfo,
48 JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
49 JDIMENSION in_row_groups_avail,
50 JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
51 JDIMENSION out_rows_avail));
52#ifdef QUANT_2PASS_SUPPORTED
53METHODDEF void post_process_prepass
54 JPP((j_decompress_ptr cinfo,
55 JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
56 JDIMENSION in_row_groups_avail,
57 JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
58 JDIMENSION out_rows_avail));
59METHODDEF void post_process_2pass
60 JPP((j_decompress_ptr cinfo,
61 JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
62 JDIMENSION in_row_groups_avail,
63 JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
64 JDIMENSION out_rows_avail));
65#endif
66
67
68/*
69 * Initialize for a processing pass.
70 */
71
72METHODDEF void
73start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
74{
75 my_post_ptr post = (my_post_ptr) cinfo->post;
76
77 switch (pass_mode) {
78 case JBUF_PASS_THRU:
79 if (cinfo->quantize_colors) {
80 /* Single-pass processing with color quantization. */
81 post->pub.post_process_data = post_process_1pass;
82 } else {
83 /* For single-pass processing without color quantization,
84 * I have no work to do; just call the upsampler directly.
85 */
86 post->pub.post_process_data = cinfo->upsample->upsample;
87 }
88 break;
89#ifdef QUANT_2PASS_SUPPORTED
90 case JBUF_SAVE_AND_PASS:
91 /* First pass of 2-pass quantization */
92 if (post->whole_image == NULL)
93 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
94 post->pub.post_process_data = post_process_prepass;
95 break;
96 case JBUF_CRANK_DEST:
97 /* Second pass of 2-pass quantization */
98 if (post->whole_image == NULL)
99 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
100 post->pub.post_process_data = post_process_2pass;
101 break;
102#endif /* QUANT_2PASS_SUPPORTED */
103 default:
104 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
105 break;
106 }
107 post->starting_row = post->next_row = 0;
108}
109
110
111/*
112 * Process some data in the one-pass (strip buffer) case.
113 * This is used for color precision reduction as well as one-pass quantization.
114 */
115
116METHODDEF void
117post_process_1pass (j_decompress_ptr cinfo,
118 JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
119 JDIMENSION in_row_groups_avail,
120 JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
121 JDIMENSION out_rows_avail)
122{
123 my_post_ptr post = (my_post_ptr) cinfo->post;
124 JDIMENSION num_rows, max_rows;
125
126 /* Fill the buffer, but not more than what we can dump out in one go. */
127 /* Note we rely on the upsampler to detect bottom of image. */
128 max_rows = out_rows_avail - *out_row_ctr;
129 if (max_rows > post->strip_height)
130 max_rows = post->strip_height;
131 num_rows = 0;
132 (*cinfo->upsample->upsample) (cinfo,
133 input_buf, in_row_group_ctr, in_row_groups_avail,
134 post->buffer, &num_rows, max_rows);
135 /* Quantize and emit data. */
136 (*cinfo->cquantize->color_quantize) (cinfo,
137 post->buffer, output_buf + *out_row_ctr, (int) num_rows);
138 *out_row_ctr += num_rows;
139}
140
141
142#ifdef QUANT_2PASS_SUPPORTED
143
144/*
145 * Process some data in the first pass of 2-pass quantization.
146 */
147
148METHODDEF void
149post_process_prepass (j_decompress_ptr cinfo,
150 JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
151 JDIMENSION in_row_groups_avail,
152 JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
153 JDIMENSION out_rows_avail)
154{
155 my_post_ptr post = (my_post_ptr) cinfo->post;
156 JDIMENSION old_next_row, num_rows;
157
158 /* Reposition virtual buffer if at start of strip. */
159 if (post->next_row == 0) {
160 post->buffer = (*cinfo->mem->access_virt_sarray)
161 ((j_common_ptr) cinfo, post->whole_image, post->starting_row, TRUE);
162 }
163
164 /* Upsample some data (up to a strip height's worth). */
165 old_next_row = post->next_row;
166 (*cinfo->upsample->upsample) (cinfo,
167 input_buf, in_row_group_ctr, in_row_groups_avail,
168 post->buffer, &post->next_row, post->strip_height);
169
170 /* Allow quantizer to scan new data. No data is emitted, */
171 /* but we advance out_row_ctr so outer loop can tell when we're done. */
172 if (post->next_row > old_next_row) {
173 num_rows = post->next_row - old_next_row;
174 (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,
175 (JSAMPARRAY) NULL, (int) num_rows);
176 *out_row_ctr += num_rows;
177 }
178
179 /* Advance if we filled the strip. */
180 if (post->next_row >= post->strip_height) {
181 post->starting_row += post->strip_height;
182 post->next_row = 0;
183 }
184}
185
186
187/*
188 * Process some data in the second pass of 2-pass quantization.
189 */
190
191METHODDEF void
192post_process_2pass (j_decompress_ptr cinfo,
193 JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
194 JDIMENSION in_row_groups_avail,
195 JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
196 JDIMENSION out_rows_avail)
197{
198 my_post_ptr post = (my_post_ptr) cinfo->post;
199 JDIMENSION num_rows, max_rows;
200
201 /* Reposition virtual buffer if at start of strip. */
202 if (post->next_row == 0) {
203 post->buffer = (*cinfo->mem->access_virt_sarray)
204 ((j_common_ptr) cinfo, post->whole_image, post->starting_row, FALSE);
205 }
206
207 /* Determine number of rows to emit. */
208 num_rows = post->strip_height - post->next_row; /* available in strip */
209 max_rows = out_rows_avail - *out_row_ctr; /* available in output area */
210 if (num_rows > max_rows)
211 num_rows = max_rows;
212 /* We have to check bottom of image here, can't depend on upsampler. */
213 max_rows = cinfo->output_height - post->starting_row;
214 if (num_rows > max_rows)
215 num_rows = max_rows;
216
217 /* Quantize and emit data. */
218 (*cinfo->cquantize->color_quantize) (cinfo,
219 post->buffer + post->next_row, output_buf + *out_row_ctr,
220 (int) num_rows);
221 *out_row_ctr += num_rows;
222
223 /* Advance if we filled the strip. */
224 post->next_row += num_rows;
225 if (post->next_row >= post->strip_height) {
226 post->starting_row += post->strip_height;
227 post->next_row = 0;
228 }
229}
230
231#endif /* QUANT_2PASS_SUPPORTED */
232
233
234/*
235 * Initialize postprocessing controller.
236 */
237
238GLOBAL void
239jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
240{
241 my_post_ptr post;
242
243 post = (my_post_ptr)
244 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
245 SIZEOF(my_post_controller));
246 cinfo->post = (struct jpeg_d_post_controller *) post;
247 post->pub.start_pass = start_pass_dpost;
248 post->whole_image = NULL; /* flag for no virtual arrays */
249
250 /* Create the quantization buffer, if needed */
251 if (cinfo->quantize_colors) {
252 /* The buffer strip height is max_v_samp_factor, which is typically
253 * an efficient number of rows for upsampling to return.
254 * (In the presence of output rescaling, we might want to be smarter?)
255 */
256 post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor;
257 if (need_full_buffer) {
258 /* Two-pass color quantization: need full-image storage. */
259#ifdef QUANT_2PASS_SUPPORTED
260 post->whole_image = (*cinfo->mem->request_virt_sarray)
261 ((j_common_ptr) cinfo, JPOOL_IMAGE,
262 cinfo->output_width * cinfo->out_color_components,
263 cinfo->output_height, post->strip_height);
264#else
265 ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
266#endif /* QUANT_2PASS_SUPPORTED */
267 } else {
268 /* One-pass color quantization: just make a strip buffer. */
269 post->buffer = (*cinfo->mem->alloc_sarray)
270 ((j_common_ptr) cinfo, JPOOL_IMAGE,
271 cinfo->output_width * cinfo->out_color_components,
272 post->strip_height);
273 }
274 }
275}