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