source: trunk/third/jpeg/jcprepct.c @ 15227

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