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