summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libjpeg/src/jclossls.c
blob: e9ba92a7dfeaf79e3178fd2eeda2aa3125c61bca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/*
 * jclossls.c
 *
 * This file was part of the Independent JPEG Group's software:
 * Copyright (C) 1998, Thomas G. Lane.
 * Lossless JPEG Modifications:
 * Copyright (C) 1999, Ken Murchison.
 * libjpeg-turbo Modifications:
 * Copyright (C) 2022, D. R. Commander.
 * For conditions of distribution and use, see the accompanying README.ijg
 * file.
 *
 * This file contains prediction, sample differencing, and point transform
 * routines for the lossless JPEG compressor.
 */

#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jlossls.h"

#ifdef C_LOSSLESS_SUPPORTED


/************************** Sample differencing **************************/

/*
 * In order to avoid a performance penalty for checking which predictor is
 * being used and which row is being processed for each call of the
 * undifferencer, and to promote optimization, we have separate differencing
 * functions for each predictor selection value.
 *
 * We are able to avoid duplicating source code by implementing the predictors
 * and differencers as macros.  Each of the differencing functions is simply a
 * wrapper around a DIFFERENCE macro with the appropriate PREDICTOR macro
 * passed as an argument.
 */

/* Forward declarations */
LOCAL(void) reset_predictor(j_compress_ptr cinfo, int ci);


/* Predictor for the first column of the first row: 2^(P-Pt-1) */
#define INITIAL_PREDICTORx  (1 << (cinfo->data_precision - cinfo->Al - 1))

/* Predictor for the first column of the remaining rows: Rb */
#define INITIAL_PREDICTOR2  prev_row[0]


/*
 * 1-Dimensional differencer routine.
 *
 * This macro implements the 1-D horizontal predictor (1).  INITIAL_PREDICTOR
 * is used as the special case predictor for the first column, which must be
 * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx.  The remaining samples
 * use PREDICTOR1.
 */

#define DIFFERENCE_1D(INITIAL_PREDICTOR) \
  lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \
  boolean restart = FALSE; \
  int samp, Ra; \
  \
  samp = *input_buf++; \
  *diff_buf++ = samp - INITIAL_PREDICTOR; \
  \
  while (--width) { \
    Ra = samp; \
    samp = *input_buf++; \
    *diff_buf++ = samp - PREDICTOR1; \
  } \
  \
  /* Account for restart interval (no-op if not using restarts) */ \
  if (cinfo->restart_interval) { \
    if (--(losslessc->restart_rows_to_go[ci]) == 0) { \
      reset_predictor(cinfo, ci); \
      restart = TRUE; \
    } \
  }


/*
 * 2-Dimensional differencer routine.
 *
 * This macro implements the 2-D horizontal predictors (#2-7).  PREDICTOR2 is
 * used as the special case predictor for the first column.  The remaining
 * samples use PREDICTOR, which is a function of Ra, Rb, and Rc.
 *
 * Because prev_row and output_buf may point to the same storage area (in an
 * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc
 * before writing the current reconstructed sample value into output_buf.
 */

#define DIFFERENCE_2D(PREDICTOR) \
  lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \
  int samp, Ra, Rb, Rc; \
  \
  Rb = *prev_row++; \
  samp = *input_buf++; \
  *diff_buf++ = samp - PREDICTOR2; \
  \
  while (--width) { \
    Rc = Rb; \
    Rb = *prev_row++; \
    Ra = samp; \
    samp = *input_buf++; \
    *diff_buf++ = samp - PREDICTOR; \
  } \
  \
  /* Account for restart interval (no-op if not using restarts) */ \
  if (cinfo->restart_interval) { \
    if (--losslessc->restart_rows_to_go[ci] == 0) \
      reset_predictor(cinfo, ci); \
  }


/*
 * Differencers for the second and subsequent rows in a scan or restart
 * interval.  The first sample in the row is differenced using the vertical
 * predictor (2).  The rest of the samples are differenced using the predictor
 * specified in the scan header.
 */

METHODDEF(void)
jpeg_difference1(j_compress_ptr cinfo, int ci,
                 _JSAMPROW input_buf, _JSAMPROW prev_row,
                 JDIFFROW diff_buf, JDIMENSION width)
{
  DIFFERENCE_1D(INITIAL_PREDICTOR2);
  (void)(restart);
}

METHODDEF(void)
jpeg_difference2(j_compress_ptr cinfo, int ci,
                 _JSAMPROW input_buf, _JSAMPROW prev_row,
                 JDIFFROW diff_buf, JDIMENSION width)
{
  DIFFERENCE_2D(PREDICTOR2);
  (void)(Ra);
  (void)(Rc);
}

METHODDEF(void)
jpeg_difference3(j_compress_ptr cinfo, int ci,
                 _JSAMPROW input_buf, _JSAMPROW prev_row,
                 JDIFFROW diff_buf, JDIMENSION width)
{
  DIFFERENCE_2D(PREDICTOR3);
  (void)(Ra);
}

METHODDEF(void)
jpeg_difference4(j_compress_ptr cinfo, int ci,
                 _JSAMPROW input_buf, _JSAMPROW prev_row,
                 JDIFFROW diff_buf, JDIMENSION width)
{
  DIFFERENCE_2D(PREDICTOR4);
}

METHODDEF(void)
jpeg_difference5(j_compress_ptr cinfo, int ci,
                 _JSAMPROW input_buf, _JSAMPROW prev_row,
                 JDIFFROW diff_buf, JDIMENSION width)
{
  DIFFERENCE_2D(PREDICTOR5);
}

METHODDEF(void)
jpeg_difference6(j_compress_ptr cinfo, int ci,
                 _JSAMPROW input_buf, _JSAMPROW prev_row,
                 JDIFFROW diff_buf, JDIMENSION width)
{
  DIFFERENCE_2D(PREDICTOR6);
}

METHODDEF(void)
jpeg_difference7(j_compress_ptr cinfo, int ci,
                 _JSAMPROW input_buf, _JSAMPROW prev_row,
                 JDIFFROW diff_buf, JDIMENSION width)
{
  DIFFERENCE_2D(PREDICTOR7);
  (void)(Rc);
}


/*
 * Differencer for the first row in a scan or restart interval.  The first
 * sample in the row is differenced using the special predictor constant
 * x = 2 ^ (P-Pt-1).  The rest of the samples are differenced using the
 * 1-D horizontal predictor (1).
 */

METHODDEF(void)
jpeg_difference_first_row(j_compress_ptr cinfo, int ci,
                          _JSAMPROW input_buf, _JSAMPROW prev_row,
                          JDIFFROW diff_buf, JDIMENSION width)
{
  DIFFERENCE_1D(INITIAL_PREDICTORx);

  /*
   * Now that we have differenced the first row, we want to use the
   * differencer that corresponds to the predictor specified in the
   * scan header.
   *
   * Note that we don't do this if we have just reset the predictor
   * for a new restart interval.
   */
  if (!restart) {
    switch (cinfo->Ss) {
    case 1:
      losslessc->predict_difference[ci] = jpeg_difference1;
      break;
    case 2:
      losslessc->predict_difference[ci] = jpeg_difference2;
      break;
    case 3:
      losslessc->predict_difference[ci] = jpeg_difference3;
      break;
    case 4:
      losslessc->predict_difference[ci] = jpeg_difference4;
      break;
    case 5:
      losslessc->predict_difference[ci] = jpeg_difference5;
      break;
    case 6:
      losslessc->predict_difference[ci] = jpeg_difference6;
      break;
    case 7:
      losslessc->predict_difference[ci] = jpeg_difference7;
      break;
    }
  }
}

/*
 * Reset predictor at the start of a pass or restart interval.
 */

LOCAL(void)
reset_predictor(j_compress_ptr cinfo, int ci)
{
  lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;

  /* Initialize restart counter */
  losslessc->restart_rows_to_go[ci] =
    cinfo->restart_interval / cinfo->MCUs_per_row;

  /* Set difference function to first row function */
  losslessc->predict_difference[ci] = jpeg_difference_first_row;
}


/********************** Sample downscaling by 2^Pt ***********************/

METHODDEF(void)
simple_downscale(j_compress_ptr cinfo,
                 _JSAMPROW input_buf, _JSAMPROW output_buf, JDIMENSION width)
{
  do {
    *output_buf++ = (_JSAMPLE)RIGHT_SHIFT(*input_buf++, cinfo->Al);
  } while (--width);
}


METHODDEF(void)
noscale(j_compress_ptr cinfo,
        _JSAMPROW input_buf, _JSAMPROW output_buf, JDIMENSION width)
{
  memcpy(output_buf, input_buf, width * sizeof(_JSAMPLE));
}


/*
 * Initialize for a processing pass.
 */

METHODDEF(void)
start_pass_lossless(j_compress_ptr cinfo)
{
  lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;
  int ci;

  /* Set scaler function based on Pt */
  if (cinfo->Al)
    losslessc->scaler_scale = simple_downscale;
  else
    losslessc->scaler_scale = noscale;

  /* Check that the restart interval is an integer multiple of the number
   * of MCUs in an MCU row.
   */
  if (cinfo->restart_interval % cinfo->MCUs_per_row != 0)
    ERREXIT2(cinfo, JERR_BAD_RESTART,
             cinfo->restart_interval, cinfo->MCUs_per_row);

  /* Set predictors for start of pass */
  for (ci = 0; ci < cinfo->num_components; ci++)
    reset_predictor(cinfo, ci);
}


/*
 * Initialize the lossless compressor.
 */

GLOBAL(void)
_jinit_lossless_compressor(j_compress_ptr cinfo)
{
  lossless_comp_ptr losslessc;

  /* Create subobject in permanent pool */
  losslessc = (lossless_comp_ptr)
    (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
                                sizeof(jpeg_lossless_compressor));
  cinfo->fdct = (struct jpeg_forward_dct *)losslessc;
  losslessc->pub.start_pass = start_pass_lossless;
}

#endif /* C_LOSSLESS_SUPPORTED */