tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

jdpostct.c (11617B)


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