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