Coverage Report

Created: 2025-06-13 06:18

/src/gdal/build/frmts/jpeg/libjpeg12/jdmerge12.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * jdmerge.c
3
 *
4
 * Copyright (C) 1994-1996, 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 code for merged upsampling/color conversion.
9
 *
10
 * This file combines functions from jdsample.c and jdcolor.c;
11
 * read those files first to understand what's going on.
12
 *
13
 * When the chroma components are to be upsampled by simple replication
14
 * (ie, box filtering), we can save some work in color conversion by
15
 * calculating all the output pixels corresponding to a pair of chroma
16
 * samples at one time.  In the conversion equations
17
 *  R = Y           + K1 * Cr
18
 *  G = Y + K2 * Cb + K3 * Cr
19
 *  B = Y + K4 * Cb
20
 * only the Y term varies among the group of pixels corresponding to a pair
21
 * of chroma samples, so the rest of the terms can be calculated just once.
22
 * At typical sampling ratios, this eliminates half or three-quarters of the
23
 * multiplications needed for color conversion.
24
 *
25
 * This file currently provides implementations for the following cases:
26
 *  YCbCr => RGB color conversion only.
27
 *  Sampling ratios of 2h1v or 2h2v.
28
 *  No scaling needed at upsample time.
29
 *  Corner-aligned (non-CCIR601) sampling alignment.
30
 * Other special cases could be added, but in most applications these are
31
 * the only common cases.  (For uncommon cases we fall back on the more
32
 * general code in jdsample.c and jdcolor.c.)
33
 */
34
35
#define JPEG_INTERNALS
36
#include "jinclude.h"
37
#include "jpeglib.h"
38
39
#include "cpl_port.h"
40
41
#ifdef UPSAMPLE_MERGING_SUPPORTED
42
43
44
/* Private subobject */
45
46
typedef struct {
47
  struct jpeg_upsampler pub;  /* public fields */
48
49
  /* Pointer to routine to do actual upsampling/conversion of one row group */
50
  JMETHOD(void, upmethod, (j_decompress_ptr cinfo,
51
         JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
52
         JSAMPARRAY output_buf));
53
54
  /* Private state for YCC->RGB conversion */
55
  int * Cr_r_tab;   /* => table for Cr to R conversion */
56
  int * Cb_b_tab;   /* => table for Cb to B conversion */
57
  INT32 * Cr_g_tab;   /* => table for Cr to G conversion */
58
  INT32 * Cb_g_tab;   /* => table for Cb to G conversion */
59
60
  /* For 2:1 vertical sampling, we produce two output rows at a time.
61
   * We need a "spare" row buffer to hold the second output row if the
62
   * application provides just a one-row buffer; we also use the spare
63
   * to discard the dummy last row if the image height is odd.
64
   */
65
  JSAMPROW spare_row;
66
  boolean spare_full;   /* T if spare buffer is occupied */
67
68
  JDIMENSION out_row_width; /* samples per output row */
69
  JDIMENSION rows_to_go;  /* counts rows remaining in image */
70
} my_upsampler;
71
72
typedef my_upsampler * my_upsample_ptr;
73
74
0
#define SCALEBITS 16  /* speediest right-shift on some machines */
75
0
#define ONE_HALF  ((INT32) 1 << (SCALEBITS-1))
76
0
#define FIX(x)    ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
77
78
79
/*
80
 * Initialize tables for YCC->RGB colorspace conversion.
81
 * This is taken directly from jdcolor.c; see that file for more info.
82
 */
83
84
LOCAL(void)
85
build_ycc_rgb_table (j_decompress_ptr cinfo)
86
0
{
87
0
  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
88
0
  int i;
89
0
  INT32 x;
90
0
  SHIFT_TEMPS
91
92
0
  upsample->Cr_r_tab = (int *)
93
0
    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
94
0
        (MAXJSAMPLE+1) * SIZEOF(int));
95
0
  upsample->Cb_b_tab = (int *)
96
0
    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
97
0
        (MAXJSAMPLE+1) * SIZEOF(int));
98
0
  upsample->Cr_g_tab = (INT32 *)
99
0
    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
100
0
        (MAXJSAMPLE+1) * SIZEOF(INT32));
101
0
  upsample->Cb_g_tab = (INT32 *)
102
0
    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
103
0
        (MAXJSAMPLE+1) * SIZEOF(INT32));
104
105
0
  for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
106
    /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
107
    /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
108
    /* Cr=>R value is nearest int to 1.40200 * x */
109
0
    upsample->Cr_r_tab[i] = (int)
110
0
        RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
111
    /* Cb=>B value is nearest int to 1.77200 * x */
112
0
    upsample->Cb_b_tab[i] = (int)
113
0
        RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
114
    /* Cr=>G value is scaled-up -0.71414 * x */
115
0
    upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x;
116
    /* Cb=>G value is scaled-up -0.34414 * x */
117
    /* We also add in ONE_HALF so that need not do it in inner loop */
118
0
    upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
119
0
  }
120
0
}
121
122
123
/*
124
 * Initialize for an upsampling pass.
125
 */
126
127
METHODDEF(void)
128
start_pass_merged_upsample (j_decompress_ptr cinfo)
129
0
{
130
0
  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
131
132
  /* Mark the spare buffer empty */
133
0
  upsample->spare_full = FALSE;
134
  /* Initialize total-height counter for detecting bottom of image */
135
0
  upsample->rows_to_go = cinfo->output_height;
136
0
}
137
138
139
/*
140
 * Control routine to do upsampling (and color conversion).
141
 *
142
 * The control routine just handles the row buffering considerations.
143
 */
144
145
METHODDEF(void)
146
merged_2v_upsample (j_decompress_ptr cinfo,
147
        JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
148
        CPL_UNUSED JDIMENSION in_row_groups_avail,
149
        JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
150
        JDIMENSION out_rows_avail)
151
/* 2:1 vertical sampling case: may need a spare row. */
152
0
{
153
0
  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
154
0
  JSAMPROW work_ptrs[2];
155
0
  JDIMENSION num_rows;    /* number of rows returned to caller */
156
157
0
  if (upsample->spare_full) {
158
    /* If we have a spare row saved from a previous cycle, just return it. */
159
0
    jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
160
0
          1, upsample->out_row_width);
161
0
    num_rows = 1;
162
0
    upsample->spare_full = FALSE;
163
0
  } else {
164
    /* Figure number of rows to return to caller. */
165
0
    num_rows = 2;
166
    /* Not more than the distance to the end of the image. */
167
0
    if (num_rows > upsample->rows_to_go)
168
0
      num_rows = upsample->rows_to_go;
169
    /* And not more than what the client can accept: */
170
0
    out_rows_avail -= *out_row_ctr;
171
0
    if (num_rows > out_rows_avail)
172
0
      num_rows = out_rows_avail;
173
    /* Create output pointer array for upsampler. */
174
0
    work_ptrs[0] = output_buf[*out_row_ctr];
175
0
    if (num_rows > 1) {
176
0
      work_ptrs[1] = output_buf[*out_row_ctr + 1];
177
0
    } else {
178
0
      work_ptrs[1] = upsample->spare_row;
179
0
      upsample->spare_full = TRUE;
180
0
    }
181
    /* Now do the upsampling. */
182
0
    (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs);
183
0
  }
184
185
  /* Adjust counts */
186
0
  *out_row_ctr += num_rows;
187
0
  upsample->rows_to_go -= num_rows;
188
  /* When the buffer is emptied, declare this input row group consumed */
189
0
  if (! upsample->spare_full)
190
0
    (*in_row_group_ctr)++;
191
0
}
192
193
194
METHODDEF(void)
195
merged_1v_upsample (j_decompress_ptr cinfo,
196
        JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
197
        CPL_UNUSED JDIMENSION in_row_groups_avail,
198
        JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
199
        CPL_UNUSED JDIMENSION out_rows_avail)
200
/* 1:1 vertical sampling case: much easier, never need a spare row. */
201
0
{
202
0
  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
203
204
  /* Just do the upsampling. */
205
0
  (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr,
206
0
       output_buf + *out_row_ctr);
207
  /* Adjust counts */
208
0
  (*out_row_ctr)++;
209
0
  (*in_row_group_ctr)++;
210
0
}
211
212
213
/*
214
 * These are the routines invoked by the control routines to do
215
 * the actual upsampling/conversion.  One row group is processed per call.
216
 *
217
 * Note: since we may be writing directly into application-supplied buffers,
218
 * we have to be honest about the output width; we can't assume the buffer
219
 * has been rounded up to an even width.
220
 */
221
222
223
/*
224
 * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.
225
 */
226
227
METHODDEF(void)
228
h2v1_merged_upsample (j_decompress_ptr cinfo,
229
          JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
230
          JSAMPARRAY output_buf)
231
0
{
232
0
  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
233
0
  register int y, cred, cgreen, cblue;
234
0
  int cb, cr;
235
0
  register JSAMPROW outptr;
236
0
  JSAMPROW inptr0, inptr1, inptr2;
237
0
  JDIMENSION col;
238
  /* copy these pointers into registers if possible */
239
0
  register JSAMPLE * range_limit = cinfo->sample_range_limit;
240
0
  int * Crrtab = upsample->Cr_r_tab;
241
0
  int * Cbbtab = upsample->Cb_b_tab;
242
0
  INT32 * Crgtab = upsample->Cr_g_tab;
243
0
  INT32 * Cbgtab = upsample->Cb_g_tab;
244
0
  SHIFT_TEMPS
245
246
0
  inptr0 = input_buf[0][in_row_group_ctr];
247
0
  inptr1 = input_buf[1][in_row_group_ctr];
248
0
  inptr2 = input_buf[2][in_row_group_ctr];
249
0
  outptr = output_buf[0];
250
  /* Loop for each pair of output pixels */
251
0
  for (col = cinfo->output_width >> 1; col > 0; col--) {
252
    /* Do the chroma part of the calculation */
253
0
    cb = GETJSAMPLE(*inptr1++);
254
0
    cr = GETJSAMPLE(*inptr2++);
255
0
    cred = Crrtab[cr];
256
0
    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
257
0
    cblue = Cbbtab[cb];
258
    /* Fetch 2 Y values and emit 2 pixels */
259
0
    y  = GETJSAMPLE(*inptr0++);
260
0
    outptr[RGB_RED] =   range_limit[y + cred];
261
0
    outptr[RGB_GREEN] = range_limit[y + cgreen];
262
0
    outptr[RGB_BLUE] =  range_limit[y + cblue];
263
0
    outptr += RGB_PIXELSIZE;
264
0
    y  = GETJSAMPLE(*inptr0++);
265
0
    outptr[RGB_RED] =   range_limit[y + cred];
266
0
    outptr[RGB_GREEN] = range_limit[y + cgreen];
267
0
    outptr[RGB_BLUE] =  range_limit[y + cblue];
268
0
    outptr += RGB_PIXELSIZE;
269
0
  }
270
  /* If image width is odd, do the last output column separately */
271
0
  if (cinfo->output_width & 1) {
272
0
    cb = GETJSAMPLE(*inptr1);
273
0
    cr = GETJSAMPLE(*inptr2);
274
0
    cred = Crrtab[cr];
275
0
    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
276
0
    cblue = Cbbtab[cb];
277
0
    y  = GETJSAMPLE(*inptr0);
278
0
    outptr[RGB_RED] =   range_limit[y + cred];
279
0
    outptr[RGB_GREEN] = range_limit[y + cgreen];
280
0
    outptr[RGB_BLUE] =  range_limit[y + cblue];
281
0
  }
282
0
}
283
284
285
/*
286
 * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.
287
 */
288
289
METHODDEF(void)
290
h2v2_merged_upsample (j_decompress_ptr cinfo,
291
          JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
292
          JSAMPARRAY output_buf)
293
0
{
294
0
  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
295
0
  register int y, cred, cgreen, cblue;
296
0
  int cb, cr;
297
0
  register JSAMPROW outptr0, outptr1;
298
0
  JSAMPROW inptr00, inptr01, inptr1, inptr2;
299
0
  JDIMENSION col;
300
  /* copy these pointers into registers if possible */
301
0
  register JSAMPLE * range_limit = cinfo->sample_range_limit;
302
0
  int * Crrtab = upsample->Cr_r_tab;
303
0
  int * Cbbtab = upsample->Cb_b_tab;
304
0
  INT32 * Crgtab = upsample->Cr_g_tab;
305
0
  INT32 * Cbgtab = upsample->Cb_g_tab;
306
0
  SHIFT_TEMPS
307
308
0
  inptr00 = input_buf[0][in_row_group_ctr*2];
309
0
  inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
310
0
  inptr1 = input_buf[1][in_row_group_ctr];
311
0
  inptr2 = input_buf[2][in_row_group_ctr];
312
0
  outptr0 = output_buf[0];
313
0
  outptr1 = output_buf[1];
314
  /* Loop for each group of output pixels */
315
0
  for (col = cinfo->output_width >> 1; col > 0; col--) {
316
    /* Do the chroma part of the calculation */
317
0
    cb = GETJSAMPLE(*inptr1++);
318
0
    cr = GETJSAMPLE(*inptr2++);
319
0
    cred = Crrtab[cr];
320
0
    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
321
0
    cblue = Cbbtab[cb];
322
    /* Fetch 4 Y values and emit 4 pixels */
323
0
    y  = GETJSAMPLE(*inptr00++);
324
0
    outptr0[RGB_RED] =   range_limit[y + cred];
325
0
    outptr0[RGB_GREEN] = range_limit[y + cgreen];
326
0
    outptr0[RGB_BLUE] =  range_limit[y + cblue];
327
0
    outptr0 += RGB_PIXELSIZE;
328
0
    y  = GETJSAMPLE(*inptr00++);
329
0
    outptr0[RGB_RED] =   range_limit[y + cred];
330
0
    outptr0[RGB_GREEN] = range_limit[y + cgreen];
331
0
    outptr0[RGB_BLUE] =  range_limit[y + cblue];
332
0
    outptr0 += RGB_PIXELSIZE;
333
0
    y  = GETJSAMPLE(*inptr01++);
334
0
    outptr1[RGB_RED] =   range_limit[y + cred];
335
0
    outptr1[RGB_GREEN] = range_limit[y + cgreen];
336
0
    outptr1[RGB_BLUE] =  range_limit[y + cblue];
337
0
    outptr1 += RGB_PIXELSIZE;
338
0
    y  = GETJSAMPLE(*inptr01++);
339
0
    outptr1[RGB_RED] =   range_limit[y + cred];
340
0
    outptr1[RGB_GREEN] = range_limit[y + cgreen];
341
0
    outptr1[RGB_BLUE] =  range_limit[y + cblue];
342
0
    outptr1 += RGB_PIXELSIZE;
343
0
  }
344
  /* If image width is odd, do the last output column separately */
345
0
  if (cinfo->output_width & 1) {
346
0
    cb = GETJSAMPLE(*inptr1);
347
0
    cr = GETJSAMPLE(*inptr2);
348
0
    cred = Crrtab[cr];
349
0
    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
350
0
    cblue = Cbbtab[cb];
351
0
    y  = GETJSAMPLE(*inptr00);
352
0
    outptr0[RGB_RED] =   range_limit[y + cred];
353
0
    outptr0[RGB_GREEN] = range_limit[y + cgreen];
354
0
    outptr0[RGB_BLUE] =  range_limit[y + cblue];
355
0
    y  = GETJSAMPLE(*inptr01);
356
0
    outptr1[RGB_RED] =   range_limit[y + cred];
357
0
    outptr1[RGB_GREEN] = range_limit[y + cgreen];
358
0
    outptr1[RGB_BLUE] =  range_limit[y + cblue];
359
0
  }
360
0
}
361
362
363
/*
364
 * Module initialization routine for merged upsampling/color conversion.
365
 *
366
 * NB: this is called under the conditions determined by use_merged_upsample()
367
 * in jdmaster.c.  That routine MUST correspond to the actual capabilities
368
 * of this module; no safety checks are made here.
369
 */
370
371
GLOBAL(void)
372
jinit_merged_upsampler (j_decompress_ptr cinfo)
373
0
{
374
0
  my_upsample_ptr upsample;
375
376
0
  upsample = (my_upsample_ptr)
377
0
    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
378
0
        SIZEOF(my_upsampler));
379
0
  cinfo->upsample = (struct jpeg_upsampler *) upsample;
380
0
  upsample->pub.start_pass = start_pass_merged_upsample;
381
0
  upsample->pub.need_context_rows = FALSE;
382
383
0
  upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;
384
385
0
  if (cinfo->max_v_samp_factor == 2) {
386
0
    upsample->pub.upsample = merged_2v_upsample;
387
0
    upsample->upmethod = h2v2_merged_upsample;
388
    /* Allocate a spare row buffer */
389
0
    upsample->spare_row = (JSAMPROW)
390
0
      (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
391
0
    (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE)));
392
0
  } else {
393
0
    upsample->pub.upsample = merged_1v_upsample;
394
0
    upsample->upmethod = h2v1_merged_upsample;
395
    /* No spare row needed */
396
0
    upsample->spare_row = NULL;
397
0
  }
398
399
0
  build_ycc_rgb_table(cinfo);
400
0
}
401
402
#endif /* UPSAMPLE_MERGING_SUPPORTED */