tor-browser

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

jcdiffct.c (14840B)


      1 /*
      2 * jcdiffct.c
      3 *
      4 * This file was part of the Independent JPEG Group's software:
      5 * Copyright (C) 1994-1997, Thomas G. Lane.
      6 * Lossless JPEG Modifications:
      7 * Copyright (C) 1999, Ken Murchison.
      8 * libjpeg-turbo Modifications:
      9 * Copyright (C) 2022, D. R. Commander.
     10 * For conditions of distribution and use, see the accompanying README.ijg
     11 * file.
     12 *
     13 * This file contains the difference buffer controller for compression.
     14 * This controller is the top level of the lossless JPEG compressor proper.
     15 * The difference buffer lies between the prediction/differencing and entropy
     16 * encoding steps.
     17 */
     18 
     19 #define JPEG_INTERNALS
     20 #include "jinclude.h"
     21 #include "jpeglib.h"
     22 #include "jlossls.h"            /* Private declarations for lossless codec */
     23 
     24 
     25 #ifdef C_LOSSLESS_SUPPORTED
     26 
     27 /* We use a full-image sample buffer when doing Huffman optimization,
     28 * and also for writing multiple-scan JPEG files.  In all cases, the
     29 * full-image buffer is filled during the first pass, and the scaling,
     30 * prediction and differencing steps are run during subsequent passes.
     31 */
     32 #ifdef ENTROPY_OPT_SUPPORTED
     33 #define FULL_SAMP_BUFFER_SUPPORTED
     34 #else
     35 #ifdef C_MULTISCAN_FILES_SUPPORTED
     36 #define FULL_SAMP_BUFFER_SUPPORTED
     37 #endif
     38 #endif
     39 
     40 
     41 /* Private buffer controller object */
     42 
     43 typedef struct {
     44  struct jpeg_c_coef_controller pub; /* public fields */
     45 
     46  JDIMENSION iMCU_row_num;      /* iMCU row # within image */
     47  JDIMENSION mcu_ctr;           /* counts MCUs processed in current row */
     48  int MCU_vert_offset;          /* counts MCU rows within iMCU row */
     49  int MCU_rows_per_iMCU_row;    /* number of such rows needed */
     50 
     51  _JSAMPROW cur_row[MAX_COMPONENTS];    /* row of point-transformed samples */
     52  _JSAMPROW prev_row[MAX_COMPONENTS];   /* previous row of Pt'd samples */
     53  JDIFFARRAY diff_buf[MAX_COMPONENTS];  /* iMCU row of differences */
     54 
     55  /* In multi-pass modes, we need a virtual sample array for each component. */
     56  jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
     57 } my_diff_controller;
     58 
     59 typedef my_diff_controller *my_diff_ptr;
     60 
     61 
     62 /* Forward declarations */
     63 METHODDEF(boolean) compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf);
     64 #ifdef FULL_SAMP_BUFFER_SUPPORTED
     65 METHODDEF(boolean) compress_first_pass(j_compress_ptr cinfo,
     66                                       _JSAMPIMAGE input_buf);
     67 METHODDEF(boolean) compress_output(j_compress_ptr cinfo,
     68                                   _JSAMPIMAGE input_buf);
     69 #endif
     70 
     71 
     72 LOCAL(void)
     73 start_iMCU_row(j_compress_ptr cinfo)
     74 /* Reset within-iMCU-row counters for a new row */
     75 {
     76  my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
     77 
     78  /* In an interleaved scan, an MCU row is the same as an iMCU row.
     79   * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
     80   * But at the bottom of the image, process only what's left.
     81   */
     82  if (cinfo->comps_in_scan > 1) {
     83    diff->MCU_rows_per_iMCU_row = 1;
     84  } else {
     85    if (diff->iMCU_row_num < (cinfo->total_iMCU_rows-1))
     86      diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
     87    else
     88      diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
     89  }
     90 
     91  diff->mcu_ctr = 0;
     92  diff->MCU_vert_offset = 0;
     93 }
     94 
     95 
     96 /*
     97 * Initialize for a processing pass.
     98 */
     99 
    100 METHODDEF(void)
    101 start_pass_diff(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
    102 {
    103  my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
    104 
    105  /* Because it is hitching a ride on the jpeg_forward_dct struct,
    106   * start_pass_lossless() will be called at the start of the initial pass.
    107   * This ensures that it will be called at the start of the Huffman
    108   * optimization and output passes as well.
    109   */
    110  if (pass_mode == JBUF_CRANK_DEST)
    111    (*cinfo->fdct->start_pass) (cinfo);
    112 
    113  diff->iMCU_row_num = 0;
    114  start_iMCU_row(cinfo);
    115 
    116  switch (pass_mode) {
    117  case JBUF_PASS_THRU:
    118    if (diff->whole_image[0] != NULL)
    119      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
    120    diff->pub._compress_data = compress_data;
    121    break;
    122 #ifdef FULL_SAMP_BUFFER_SUPPORTED
    123  case JBUF_SAVE_AND_PASS:
    124    if (diff->whole_image[0] == NULL)
    125      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
    126    diff->pub._compress_data = compress_first_pass;
    127    break;
    128  case JBUF_CRANK_DEST:
    129    if (diff->whole_image[0] == NULL)
    130      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
    131    diff->pub._compress_data = compress_output;
    132    break;
    133 #endif
    134  default:
    135    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
    136    break;
    137  }
    138 }
    139 
    140 
    141 #define SWAP_ROWS(rowa, rowb) { \
    142  _JSAMPROW temp = rowa; \
    143  rowa = rowb;  rowb = temp; \
    144 }
    145 
    146 /*
    147 * Process some data in the single-pass case.
    148 * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
    149 * per call, ie, v_samp_factor rows for each component in the image.
    150 * Returns TRUE if the iMCU row is completed, FALSE if suspended.
    151 *
    152 * NB: input_buf contains a plane for each component in image,
    153 * which we index according to the component's SOF position.
    154 */
    155 
    156 METHODDEF(boolean)
    157 compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
    158 {
    159  my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
    160  lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;
    161  JDIMENSION MCU_col_num;       /* index of current MCU within row */
    162  JDIMENSION MCU_count;         /* number of MCUs encoded */
    163  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
    164  int ci, compi, yoffset, samp_row, samp_rows, samps_across;
    165  jpeg_component_info *compptr;
    166 
    167  /* Loop to write as much as one whole iMCU row */
    168  for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row;
    169       yoffset++) {
    170 
    171    MCU_col_num = diff->mcu_ctr;
    172 
    173    /* Scale and predict each scanline of the MCU row separately.
    174     *
    175     * Note: We only do this if we are at the start of an MCU row, ie,
    176     * we don't want to reprocess a row suspended by the output.
    177     */
    178    if (MCU_col_num == 0) {
    179      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
    180        compptr = cinfo->cur_comp_info[ci];
    181        compi = compptr->component_index;
    182        if (diff->iMCU_row_num < last_iMCU_row)
    183          samp_rows = compptr->v_samp_factor;
    184        else {
    185          /* NB: can't use last_row_height here, since may not be set! */
    186          samp_rows =
    187            (int)(compptr->height_in_blocks % compptr->v_samp_factor);
    188          if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
    189          else {
    190            /* Fill dummy difference rows at the bottom edge with zeros, which
    191             * will encode to the smallest amount of data.
    192             */
    193            for (samp_row = samp_rows; samp_row < compptr->v_samp_factor;
    194                 samp_row++)
    195              memset(diff->diff_buf[compi][samp_row], 0,
    196                     jround_up((long)compptr->width_in_blocks,
    197                               (long)compptr->h_samp_factor) * sizeof(JDIFF));
    198          }
    199        }
    200        samps_across = compptr->width_in_blocks;
    201 
    202        for (samp_row = 0; samp_row < samp_rows; samp_row++) {
    203          (*losslessc->scaler_scale) (cinfo,
    204                                      input_buf[compi][samp_row],
    205                                      diff->cur_row[compi],
    206                                      samps_across);
    207          (*losslessc->predict_difference[compi])
    208            (cinfo, compi, diff->cur_row[compi], diff->prev_row[compi],
    209             diff->diff_buf[compi][samp_row], samps_across);
    210          SWAP_ROWS(diff->cur_row[compi], diff->prev_row[compi]);
    211        }
    212      }
    213    }
    214    /* Try to write the MCU row (or remaining portion of suspended MCU row). */
    215    MCU_count =
    216      (*cinfo->entropy->encode_mcus) (cinfo,
    217                                      diff->diff_buf, yoffset, MCU_col_num,
    218                                      cinfo->MCUs_per_row - MCU_col_num);
    219    if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) {
    220      /* Suspension forced; update state counters and exit */
    221      diff->MCU_vert_offset = yoffset;
    222      diff->mcu_ctr += MCU_col_num;
    223      return FALSE;
    224    }
    225    /* Completed an MCU row, but perhaps not an iMCU row */
    226    diff->mcu_ctr = 0;
    227  }
    228  /* Completed the iMCU row, advance counters for next one */
    229  diff->iMCU_row_num++;
    230  start_iMCU_row(cinfo);
    231  return TRUE;
    232 }
    233 
    234 
    235 #ifdef FULL_SAMP_BUFFER_SUPPORTED
    236 
    237 /*
    238 * Process some data in the first pass of a multi-pass case.
    239 * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
    240 * per call, ie, v_samp_factor rows for each component in the image.
    241 * This amount of data is read from the source buffer and saved into the
    242 * virtual arrays.
    243 *
    244 * We must also emit the data to the compressor.  This is conveniently
    245 * done by calling compress_output() after we've loaded the current strip
    246 * of the virtual arrays.
    247 *
    248 * NB: input_buf contains a plane for each component in image.  All components
    249 * are loaded into the virtual arrays in this pass.  However, it may be that
    250 * only a subset of the components are emitted to the compressor during
    251 * this first pass; be careful about looking at the scan-dependent variables
    252 * (MCU dimensions, etc).
    253 */
    254 
    255 METHODDEF(boolean)
    256 compress_first_pass(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
    257 {
    258  my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
    259  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
    260  JDIMENSION samps_across;
    261  int ci, samp_row, samp_rows;
    262  _JSAMPARRAY buffer;
    263  jpeg_component_info *compptr;
    264 
    265  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
    266       ci++, compptr++) {
    267    /* Align the virtual buffer for this component. */
    268    buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
    269      ((j_common_ptr)cinfo, diff->whole_image[ci],
    270       diff->iMCU_row_num * compptr->v_samp_factor,
    271       (JDIMENSION)compptr->v_samp_factor, TRUE);
    272 
    273    /* Count non-dummy sample rows in this iMCU row. */
    274    if (diff->iMCU_row_num < last_iMCU_row)
    275      samp_rows = compptr->v_samp_factor;
    276    else {
    277      /* NB: can't use last_row_height here, since may not be set! */
    278      samp_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
    279      if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
    280    }
    281    samps_across = compptr->width_in_blocks;
    282 
    283    /* Perform point transform scaling and prediction/differencing for all
    284     * non-dummy rows in this iMCU row.  Each call on these functions
    285     * processes a complete row of samples.
    286     */
    287    for (samp_row = 0; samp_row < samp_rows; samp_row++) {
    288      memcpy(buffer[samp_row], input_buf[ci][samp_row],
    289             samps_across * sizeof(_JSAMPLE));
    290    }
    291  }
    292  /* NB: compress_output will increment iMCU_row_num if successful.
    293   * A suspension return will result in redoing all the work above next time.
    294   */
    295 
    296  /* Emit data to the compressor, sharing code with subsequent passes */
    297  return compress_output(cinfo, input_buf);
    298 }
    299 
    300 
    301 /*
    302 * Process some data in subsequent passes of a multi-pass case.
    303 * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
    304 * per call, ie, v_samp_factor rows for each component in the scan.
    305 * The data is obtained from the virtual arrays and fed to the compressor.
    306 * Returns TRUE if the iMCU row is completed, FALSE if suspended.
    307 *
    308 * NB: input_buf is ignored; it is likely to be a NULL pointer.
    309 */
    310 
    311 METHODDEF(boolean)
    312 compress_output(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
    313 {
    314  my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
    315  int ci, compi;
    316  _JSAMPARRAY buffer[MAX_COMPS_IN_SCAN];
    317  jpeg_component_info *compptr;
    318 
    319  /* Align the virtual buffers for the components used in this scan.
    320   * NB: during first pass, this is safe only because the buffers will
    321   * already be aligned properly, so jmemmgr.c won't need to do any I/O.
    322   */
    323  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
    324    compptr = cinfo->cur_comp_info[ci];
    325    compi = compptr->component_index;
    326    buffer[compi] = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
    327      ((j_common_ptr)cinfo, diff->whole_image[compi],
    328       diff->iMCU_row_num * compptr->v_samp_factor,
    329       (JDIMENSION)compptr->v_samp_factor, FALSE);
    330  }
    331 
    332  return compress_data(cinfo, buffer);
    333 }
    334 
    335 #endif /* FULL_SAMP_BUFFER_SUPPORTED */
    336 
    337 
    338 /*
    339 * Initialize difference buffer controller.
    340 */
    341 
    342 GLOBAL(void)
    343 _jinit_c_diff_controller(j_compress_ptr cinfo, boolean need_full_buffer)
    344 {
    345  my_diff_ptr diff;
    346  int ci, row;
    347  jpeg_component_info *compptr;
    348 
    349  diff = (my_diff_ptr)
    350    (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
    351                                sizeof(my_diff_controller));
    352  cinfo->coef = (struct jpeg_c_coef_controller *)diff;
    353  diff->pub.start_pass = start_pass_diff;
    354 
    355  /* Create the prediction row buffers. */
    356  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
    357       ci++, compptr++) {
    358    diff->cur_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
    359      ((j_common_ptr)cinfo, JPOOL_IMAGE,
    360       (JDIMENSION)jround_up((long)compptr->width_in_blocks,
    361                             (long)compptr->h_samp_factor),
    362       (JDIMENSION)1);
    363    diff->prev_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
    364      ((j_common_ptr)cinfo, JPOOL_IMAGE,
    365       (JDIMENSION)jround_up((long)compptr->width_in_blocks,
    366                             (long)compptr->h_samp_factor),
    367       (JDIMENSION)1);
    368  }
    369 
    370  /* Create the difference buffer. */
    371  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
    372       ci++, compptr++) {
    373    diff->diff_buf[ci] =
    374      ALLOC_DARRAY(JPOOL_IMAGE,
    375                   (JDIMENSION)jround_up((long)compptr->width_in_blocks,
    376                                         (long)compptr->h_samp_factor),
    377                   (JDIMENSION)compptr->v_samp_factor);
    378    /* Prefill difference rows with zeros.  We do this because only actual
    379     * data is placed in the buffers during prediction/differencing, leaving
    380     * any dummy differences at the right edge as zeros, which will encode
    381     * to the smallest amount of data.
    382     */
    383    for (row = 0; row < compptr->v_samp_factor; row++)
    384      memset(diff->diff_buf[ci][row], 0,
    385             jround_up((long)compptr->width_in_blocks,
    386                       (long)compptr->h_samp_factor) * sizeof(JDIFF));
    387  }
    388 
    389  /* Create the sample buffer. */
    390  if (need_full_buffer) {
    391 #ifdef FULL_SAMP_BUFFER_SUPPORTED
    392    /* Allocate a full-image virtual array for each component, */
    393    /* padded to a multiple of samp_factor differences in each direction. */
    394    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
    395         ci++, compptr++) {
    396      diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
    397        ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
    398         (JDIMENSION)jround_up((long)compptr->width_in_blocks,
    399                               (long)compptr->h_samp_factor),
    400         (JDIMENSION)jround_up((long)compptr->height_in_blocks,
    401                               (long)compptr->v_samp_factor),
    402         (JDIMENSION)compptr->v_samp_factor);
    403    }
    404 #else
    405    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
    406 #endif
    407  } else
    408    diff->whole_image[0] = NULL; /* flag for no virtual arrays */
    409 }
    410 
    411 #endif /* C_LOSSLESS_SUPPORTED */