Imported Upstream version 3.0.1
[platform/upstream/libjpeg-turbo.git] / jcprepct.c
1 /*
2  * jcprepct.c
3  *
4  * This file was part of the Independent JPEG Group's software:
5  * Copyright (C) 1994-1996, Thomas G. Lane.
6  * Lossless JPEG Modifications:
7  * Copyright (C) 1999, Ken Murchison.
8  * libjpeg-turbo Modifications:
9  * Copyright (C) 2022, D. R. Commander.
10  * For conditions of distribution and use, see the accompanying README.ijg
11  * file.
12  *
13  * This file contains the compression preprocessing controller.
14  * This controller manages the color conversion, downsampling,
15  * and edge expansion steps.
16  *
17  * Most of the complexity here is associated with buffering input rows
18  * as required by the downsampler.  See the comments at the head of
19  * jcsample.c for the downsampler's needs.
20  */
21
22 #define JPEG_INTERNALS
23 #include "jinclude.h"
24 #include "jpeglib.h"
25 #include "jsamplecomp.h"
26
27
28 #if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
29
30 /* At present, jcsample.c can request context rows only for smoothing.
31  * In the future, we might also need context rows for CCIR601 sampling
32  * or other more-complex downsampling procedures.  The code to support
33  * context rows should be compiled only if needed.
34  */
35 #ifdef INPUT_SMOOTHING_SUPPORTED
36 #define CONTEXT_ROWS_SUPPORTED
37 #endif
38
39
40 /*
41  * For the simple (no-context-row) case, we just need to buffer one
42  * row group's worth of pixels for the downsampling step.  At the bottom of
43  * the image, we pad to a full row group by replicating the last pixel row.
44  * The downsampler's last output row is then replicated if needed to pad
45  * out to a full iMCU row.
46  *
47  * When providing context rows, we must buffer three row groups' worth of
48  * pixels.  Three row groups are physically allocated, but the row pointer
49  * arrays are made five row groups high, with the extra pointers above and
50  * below "wrapping around" to point to the last and first real row groups.
51  * This allows the downsampler to access the proper context rows.
52  * At the top and bottom of the image, we create dummy context rows by
53  * copying the first or last real pixel row.  This copying could be avoided
54  * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the
55  * trouble on the compression side.
56  */
57
58
59 /* Private buffer controller object */
60
61 typedef struct {
62   struct jpeg_c_prep_controller pub; /* public fields */
63
64   /* Downsampling input buffer.  This buffer holds color-converted data
65    * until we have enough to do a downsample step.
66    */
67   _JSAMPARRAY color_buf[MAX_COMPONENTS];
68
69   JDIMENSION rows_to_go;        /* counts rows remaining in source image */
70   int next_buf_row;             /* index of next row to store in color_buf */
71
72 #ifdef CONTEXT_ROWS_SUPPORTED   /* only needed for context case */
73   int this_row_group;           /* starting row index of group to process */
74   int next_buf_stop;            /* downsample when we reach this index */
75 #endif
76 } my_prep_controller;
77
78 typedef my_prep_controller *my_prep_ptr;
79
80
81 /*
82  * Initialize for a processing pass.
83  */
84
85 METHODDEF(void)
86 start_pass_prep(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
87 {
88   my_prep_ptr prep = (my_prep_ptr)cinfo->prep;
89
90   if (pass_mode != JBUF_PASS_THRU)
91     ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
92
93   /* Initialize total-height counter for detecting bottom of image */
94   prep->rows_to_go = cinfo->image_height;
95   /* Mark the conversion buffer empty */
96   prep->next_buf_row = 0;
97 #ifdef CONTEXT_ROWS_SUPPORTED
98   /* Preset additional state variables for context mode.
99    * These aren't used in non-context mode, so we needn't test which mode.
100    */
101   prep->this_row_group = 0;
102   /* Set next_buf_stop to stop after two row groups have been read in. */
103   prep->next_buf_stop = 2 * cinfo->max_v_samp_factor;
104 #endif
105 }
106
107
108 /*
109  * Expand an image vertically from height input_rows to height output_rows,
110  * by duplicating the bottom row.
111  */
112
113 LOCAL(void)
114 expand_bottom_edge(_JSAMPARRAY image_data, JDIMENSION num_cols, int input_rows,
115                    int output_rows)
116 {
117   register int row;
118
119   for (row = input_rows; row < output_rows; row++) {
120     _jcopy_sample_rows(image_data, input_rows - 1, image_data, row, 1,
121                        num_cols);
122   }
123 }
124
125
126 /*
127  * Process some data in the simple no-context case.
128  *
129  * Preprocessor output data is counted in "row groups".  A row group
130  * is defined to be v_samp_factor sample rows of each component.
131  * Downsampling will produce this much data from each max_v_samp_factor
132  * input rows.
133  */
134
135 METHODDEF(void)
136 pre_process_data(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
137                  JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,
138                  _JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
139                  JDIMENSION out_row_groups_avail)
140 {
141   my_prep_ptr prep = (my_prep_ptr)cinfo->prep;
142   int numrows, ci;
143   JDIMENSION inrows;
144   jpeg_component_info *compptr;
145   int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
146
147   while (*in_row_ctr < in_rows_avail &&
148          *out_row_group_ctr < out_row_groups_avail) {
149     /* Do color conversion to fill the conversion buffer. */
150     inrows = in_rows_avail - *in_row_ctr;
151     numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
152     numrows = (int)MIN((JDIMENSION)numrows, inrows);
153     (*cinfo->cconvert->_color_convert) (cinfo, input_buf + *in_row_ctr,
154                                         prep->color_buf,
155                                         (JDIMENSION)prep->next_buf_row,
156                                         numrows);
157     *in_row_ctr += numrows;
158     prep->next_buf_row += numrows;
159     prep->rows_to_go -= numrows;
160     /* If at bottom of image, pad to fill the conversion buffer. */
161     if (prep->rows_to_go == 0 &&
162         prep->next_buf_row < cinfo->max_v_samp_factor) {
163       for (ci = 0; ci < cinfo->num_components; ci++) {
164         expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
165                            prep->next_buf_row, cinfo->max_v_samp_factor);
166       }
167       prep->next_buf_row = cinfo->max_v_samp_factor;
168     }
169     /* If we've filled the conversion buffer, empty it. */
170     if (prep->next_buf_row == cinfo->max_v_samp_factor) {
171       (*cinfo->downsample->_downsample) (cinfo,
172                                          prep->color_buf, (JDIMENSION)0,
173                                          output_buf, *out_row_group_ctr);
174       prep->next_buf_row = 0;
175       (*out_row_group_ctr)++;
176     }
177     /* If at bottom of image, pad the output to a full iMCU height.
178      * Note we assume the caller is providing a one-iMCU-height output buffer!
179      */
180     if (prep->rows_to_go == 0 && *out_row_group_ctr < out_row_groups_avail) {
181       for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
182            ci++, compptr++) {
183         expand_bottom_edge(output_buf[ci],
184                            compptr->width_in_blocks * data_unit,
185                            (int)(*out_row_group_ctr * compptr->v_samp_factor),
186                            (int)(out_row_groups_avail * compptr->v_samp_factor));
187       }
188       *out_row_group_ctr = out_row_groups_avail;
189       break;                    /* can exit outer loop without test */
190     }
191   }
192 }
193
194
195 #ifdef CONTEXT_ROWS_SUPPORTED
196
197 /*
198  * Process some data in the context case.
199  */
200
201 METHODDEF(void)
202 pre_process_context(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
203                     JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,
204                     _JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
205                     JDIMENSION out_row_groups_avail)
206 {
207   my_prep_ptr prep = (my_prep_ptr)cinfo->prep;
208   int numrows, ci;
209   int buf_height = cinfo->max_v_samp_factor * 3;
210   JDIMENSION inrows;
211
212   while (*out_row_group_ctr < out_row_groups_avail) {
213     if (*in_row_ctr < in_rows_avail) {
214       /* Do color conversion to fill the conversion buffer. */
215       inrows = in_rows_avail - *in_row_ctr;
216       numrows = prep->next_buf_stop - prep->next_buf_row;
217       numrows = (int)MIN((JDIMENSION)numrows, inrows);
218       (*cinfo->cconvert->_color_convert) (cinfo, input_buf + *in_row_ctr,
219                                           prep->color_buf,
220                                           (JDIMENSION)prep->next_buf_row,
221                                           numrows);
222       /* Pad at top of image, if first time through */
223       if (prep->rows_to_go == cinfo->image_height) {
224         for (ci = 0; ci < cinfo->num_components; ci++) {
225           int row;
226           for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
227             _jcopy_sample_rows(prep->color_buf[ci], 0, prep->color_buf[ci],
228                                -row, 1, cinfo->image_width);
229           }
230         }
231       }
232       *in_row_ctr += numrows;
233       prep->next_buf_row += numrows;
234       prep->rows_to_go -= numrows;
235     } else {
236       /* Return for more data, unless we are at the bottom of the image. */
237       if (prep->rows_to_go != 0)
238         break;
239       /* When at bottom of image, pad to fill the conversion buffer. */
240       if (prep->next_buf_row < prep->next_buf_stop) {
241         for (ci = 0; ci < cinfo->num_components; ci++) {
242           expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
243                              prep->next_buf_row, prep->next_buf_stop);
244         }
245         prep->next_buf_row = prep->next_buf_stop;
246       }
247     }
248     /* If we've gotten enough data, downsample a row group. */
249     if (prep->next_buf_row == prep->next_buf_stop) {
250       (*cinfo->downsample->_downsample) (cinfo, prep->color_buf,
251                                          (JDIMENSION)prep->this_row_group,
252                                          output_buf, *out_row_group_ctr);
253       (*out_row_group_ctr)++;
254       /* Advance pointers with wraparound as necessary. */
255       prep->this_row_group += cinfo->max_v_samp_factor;
256       if (prep->this_row_group >= buf_height)
257         prep->this_row_group = 0;
258       if (prep->next_buf_row >= buf_height)
259         prep->next_buf_row = 0;
260       prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor;
261     }
262   }
263 }
264
265
266 /*
267  * Create the wrapped-around downsampling input buffer needed for context mode.
268  */
269
270 LOCAL(void)
271 create_context_buffer(j_compress_ptr cinfo)
272 {
273   my_prep_ptr prep = (my_prep_ptr)cinfo->prep;
274   int rgroup_height = cinfo->max_v_samp_factor;
275   int ci, i;
276   jpeg_component_info *compptr;
277   _JSAMPARRAY true_buffer, fake_buffer;
278   int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
279
280   /* Grab enough space for fake row pointers for all the components;
281    * we need five row groups' worth of pointers for each component.
282    */
283   fake_buffer = (_JSAMPARRAY)
284     (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
285                                 (cinfo->num_components * 5 * rgroup_height) *
286                                 sizeof(_JSAMPROW));
287
288   for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
289        ci++, compptr++) {
290     /* Allocate the actual buffer space (3 row groups) for this component.
291      * We make the buffer wide enough to allow the downsampler to edge-expand
292      * horizontally within the buffer, if it so chooses.
293      */
294     true_buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
295       ((j_common_ptr)cinfo, JPOOL_IMAGE,
296        (JDIMENSION)(((long)compptr->width_in_blocks * data_unit *
297                      cinfo->max_h_samp_factor) / compptr->h_samp_factor),
298        (JDIMENSION)(3 * rgroup_height));
299     /* Copy true buffer row pointers into the middle of the fake row array */
300     memcpy(fake_buffer + rgroup_height, true_buffer,
301            3 * rgroup_height * sizeof(_JSAMPROW));
302     /* Fill in the above and below wraparound pointers */
303     for (i = 0; i < rgroup_height; i++) {
304       fake_buffer[i] = true_buffer[2 * rgroup_height + i];
305       fake_buffer[4 * rgroup_height + i] = true_buffer[i];
306     }
307     prep->color_buf[ci] = fake_buffer + rgroup_height;
308     fake_buffer += 5 * rgroup_height; /* point to space for next component */
309   }
310 }
311
312 #endif /* CONTEXT_ROWS_SUPPORTED */
313
314
315 /*
316  * Initialize preprocessing controller.
317  */
318
319 GLOBAL(void)
320 _jinit_c_prep_controller(j_compress_ptr cinfo, boolean need_full_buffer)
321 {
322   my_prep_ptr prep;
323   int ci;
324   jpeg_component_info *compptr;
325   int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
326
327   if (cinfo->data_precision != BITS_IN_JSAMPLE)
328     ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
329
330   if (need_full_buffer)         /* safety check */
331     ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
332
333   prep = (my_prep_ptr)
334     (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
335                                 sizeof(my_prep_controller));
336   cinfo->prep = (struct jpeg_c_prep_controller *)prep;
337   prep->pub.start_pass = start_pass_prep;
338
339   /* Allocate the color conversion buffer.
340    * We make the buffer wide enough to allow the downsampler to edge-expand
341    * horizontally within the buffer, if it so chooses.
342    */
343   if (cinfo->downsample->need_context_rows) {
344     /* Set up to provide context rows */
345 #ifdef CONTEXT_ROWS_SUPPORTED
346     prep->pub._pre_process_data = pre_process_context;
347     create_context_buffer(cinfo);
348 #else
349     ERREXIT(cinfo, JERR_NOT_COMPILED);
350 #endif
351   } else {
352     /* No context, just make it tall enough for one row group */
353     prep->pub._pre_process_data = pre_process_data;
354     for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
355          ci++, compptr++) {
356       prep->color_buf[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
357         ((j_common_ptr)cinfo, JPOOL_IMAGE,
358          (JDIMENSION)(((long)compptr->width_in_blocks * data_unit *
359                        cinfo->max_h_samp_factor) / compptr->h_samp_factor),
360          (JDIMENSION)cinfo->max_v_samp_factor);
361     }
362   }
363 }
364
365 #endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */