Coverage Report

Created: 2026-11-12 07:19

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