Coverage Report

Created: 2023-06-07 06:03

/src/libjpeg-turbo.main/turbojpeg.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C)2009-2023 D. R. Commander.  All Rights Reserved.
3
 * Copyright (C)2021 Alex Richardson.  All Rights Reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * - Redistributions of source code must retain the above copyright notice,
9
 *   this list of conditions and the following disclaimer.
10
 * - Redistributions in binary form must reproduce the above copyright notice,
11
 *   this list of conditions and the following disclaimer in the documentation
12
 *   and/or other materials provided with the distribution.
13
 * - Neither the name of the libjpeg-turbo Project nor the names of its
14
 *   contributors may be used to endorse or promote products derived from this
15
 *   software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
18
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
21
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
 * POSSIBILITY OF SUCH DAMAGE.
28
 */
29
30
/* TurboJPEG/LJT:  this implements the TurboJPEG API using libjpeg or
31
   libjpeg-turbo */
32
33
#include <ctype.h>
34
#include <limits.h>
35
#include <jinclude.h>
36
#define JPEG_INTERNALS
37
#include <jpeglib.h>
38
#include <jerror.h>
39
#include <setjmp.h>
40
#include <errno.h>
41
#include "./turbojpeg.h"
42
#include "./tjutil.h"
43
#include "transupp.h"
44
#include "./jpegapicomp.h"
45
#include "./cdjpeg.h"
46
47
extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, size_t *,
48
                             boolean);
49
extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *, size_t);
50
51
903k
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
52
71.5k
#define IS_POW2(x)  (((x) & (x - 1)) == 0)
53
54
55
/* Error handling (based on example in example.c) */
56
57
static THREAD_LOCAL char errStr[JMSG_LENGTH_MAX] = "No error";
58
59
struct my_error_mgr {
60
  struct jpeg_error_mgr pub;
61
  jmp_buf setjmp_buffer;
62
  void (*emit_message) (j_common_ptr, int);
63
  boolean warning, stopOnWarning;
64
};
65
typedef struct my_error_mgr *my_error_ptr;
66
67
#define JMESSAGE(code, string)  string,
68
static const char *turbojpeg_message_table[] = {
69
#include "cderror.h"
70
  NULL
71
};
72
73
static void my_error_exit(j_common_ptr cinfo)
74
135k
{
75
135k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
76
77
135k
  (*cinfo->err->output_message) (cinfo);
78
135k
  longjmp(myerr->setjmp_buffer, 1);
79
135k
}
80
81
/* Based on output_message() in jerror.c */
82
83
static void my_output_message(j_common_ptr cinfo)
84
198k
{
85
198k
  (*cinfo->err->format_message) (cinfo, errStr);
86
198k
}
87
88
static void my_emit_message(j_common_ptr cinfo, int msg_level)
89
441M
{
90
441M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
91
92
441M
  myerr->emit_message(cinfo, msg_level);
93
441M
  if (msg_level < 0) {
94
266M
    myerr->warning = TRUE;
95
266M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
96
266M
  }
97
441M
}
98
99
100
/********************** Global structures, macros, etc. **********************/
101
102
enum { COMPRESS = 1, DECOMPRESS = 2 };
103
104
typedef struct _tjinstance {
105
  struct jpeg_compress_struct cinfo;
106
  struct jpeg_decompress_struct dinfo;
107
  struct my_error_mgr jerr;
108
  int init;
109
  char errStr[JMSG_LENGTH_MAX];
110
  boolean isInstanceError;
111
  /* Parameters */
112
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
113
  int maxPixels;
114
#endif
115
  boolean bottomUp;
116
  boolean noRealloc;
117
  int quality;
118
  int subsamp;
119
  int jpegWidth;
120
  int jpegHeight;
121
  int precision;
122
  int colorspace;
123
  boolean fastUpsample;
124
  boolean fastDCT;
125
  boolean optimize;
126
  boolean progressive;
127
  int scanLimit;
128
  boolean arithmetic;
129
  boolean lossless;
130
  int losslessPSV;
131
  int losslessPt;
132
  int restartIntervalBlocks;
133
  int restartIntervalRows;
134
  int xDensity;
135
  int yDensity;
136
  int densityUnits;
137
  tjscalingfactor scalingFactor;
138
  tjregion croppingRegion;
139
} tjinstance;
140
141
static tjhandle _tjInitCompress(tjinstance *this);
142
static tjhandle _tjInitDecompress(tjinstance *this);
143
144
struct my_progress_mgr {
145
  struct jpeg_progress_mgr pub;
146
  tjinstance *this;
147
};
148
typedef struct my_progress_mgr *my_progress_ptr;
149
150
static void my_progress_monitor(j_common_ptr dinfo)
151
178M
{
152
178M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
153
178M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
154
155
178M
  if (dinfo->is_decompressor) {
156
178M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
157
158
178M
    if (scan_no > myprog->this->scanLimit) {
159
22
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
160
22
               "Progressive JPEG image has more than %d scans",
161
22
               myprog->this->scanLimit);
162
22
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
163
22
               "Progressive JPEG image has more than %d scans",
164
22
               myprog->this->scanLimit);
165
22
      myprog->this->isInstanceError = TRUE;
166
22
      myerr->warning = FALSE;
167
22
      longjmp(myerr->setjmp_buffer, 1);
168
22
    }
169
178M
  }
170
178M
}
171
172
static const JXFORM_CODE xformtypes[TJ_NUMXOP] = {
173
  JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
174
  JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
175
};
176
177
101k
#define NUMSF  16
178
static const tjscalingfactor sf[NUMSF] = {
179
  { 2, 1 },
180
  { 15, 8 },
181
  { 7, 4 },
182
  { 13, 8 },
183
  { 3, 2 },
184
  { 11, 8 },
185
  { 5, 4 },
186
  { 9, 8 },
187
  { 1, 1 },
188
  { 7, 8 },
189
  { 3, 4 },
190
  { 5, 8 },
191
  { 1, 2 },
192
  { 3, 8 },
193
  { 1, 4 },
194
  { 1, 8 }
195
};
196
197
static J_COLOR_SPACE pf2cs[TJ_NUMPF] = {
198
  JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR,
199
  JCS_EXT_XRGB, JCS_GRAYSCALE, JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ABGR,
200
  JCS_EXT_ARGB, JCS_CMYK
201
};
202
203
static int cs2pf[JPEG_NUMCS] = {
204
  TJPF_UNKNOWN, TJPF_GRAY,
205
#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
206
  TJPF_RGB,
207
#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 3
208
  TJPF_BGR,
209
#elif RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 4
210
  TJPF_RGBX,
211
#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 4
212
  TJPF_BGRX,
213
#elif RGB_RED == 3 && RGB_GREEN == 2 && RGB_BLUE == 1 && RGB_PIXELSIZE == 4
214
  TJPF_XBGR,
215
#elif RGB_RED == 1 && RGB_GREEN == 2 && RGB_BLUE == 3 && RGB_PIXELSIZE == 4
216
  TJPF_XRGB,
217
#endif
218
  TJPF_UNKNOWN, TJPF_CMYK, TJPF_UNKNOWN, TJPF_RGB, TJPF_RGBX, TJPF_BGR,
219
  TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_RGBA, TJPF_BGRA, TJPF_ABGR, TJPF_ARGB,
220
  TJPF_UNKNOWN
221
};
222
223
0
#define THROWG(m, rv) { \
224
18.4E
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME, m); \
225
0
  retval = rv;  goto bailout; \
226
18.4E
}
227
#ifdef _MSC_VER
228
#define THROW_UNIX(m) { \
229
  char strerrorBuf[80] = { 0 }; \
230
  strerror_s(strerrorBuf, 80, errno); \
231
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s\n%s", FUNCTION_NAME, m, \
232
           strerrorBuf); \
233
  this->isInstanceError = TRUE; \
234
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): %s\n%s", FUNCTION_NAME, m, \
235
           strerrorBuf); \
236
  retval = -1;  goto bailout; \
237
}
238
#else
239
0
#define THROW_UNIX(m) { \
240
0
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s\n%s", FUNCTION_NAME, m, \
241
0
           strerror(errno)); \
242
0
  this->isInstanceError = TRUE; \
243
0
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): %s\n%s", FUNCTION_NAME, m, \
244
0
           strerror(errno)); \
245
0
  retval = -1;  goto bailout; \
246
0
}
247
#endif
248
0
#define THROW(m) { \
249
18.4E
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME, m); \
250
18.4E
  this->isInstanceError = TRUE;  THROWG(m, -1) \
251
18.4E
}
252
0
#define THROWI(format, val1, val2) { \
253
0
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): " format, FUNCTION_NAME, \
254
0
           val1, val2); \
255
0
  this->isInstanceError = TRUE; \
256
0
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): " format, FUNCTION_NAME, val1, \
257
0
           val2); \
258
0
  retval = -1;  goto bailout; \
259
0
}
260
261
#define GET_INSTANCE(handle) \
262
7.99k
  tjinstance *this = (tjinstance *)handle; \
263
7.99k
  j_compress_ptr cinfo = NULL; \
264
7.99k
  j_decompress_ptr dinfo = NULL; \
265
7.99k
  \
266
7.99k
  if (!this) { \
267
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
268
0
    return -1; \
269
0
  } \
270
7.99k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
271
7.99k
  this->jerr.warning = FALSE; \
272
7.99k
  this->isInstanceError = FALSE;
273
274
#define GET_CINSTANCE(handle) \
275
71.4k
  tjinstance *this = (tjinstance *)handle; \
276
71.4k
  j_compress_ptr cinfo = NULL; \
277
71.4k
  \
278
71.4k
  if (!this) { \
279
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
280
0
    return -1; \
281
0
  } \
282
71.4k
  cinfo = &this->cinfo; \
283
71.4k
  this->jerr.warning = FALSE; \
284
71.4k
  this->isInstanceError = FALSE;
285
286
#define GET_DINSTANCE(handle) \
287
35.7k
  tjinstance *this = (tjinstance *)handle; \
288
35.7k
  j_decompress_ptr dinfo = NULL; \
289
35.7k
  \
290
35.7k
  if (!this) { \
291
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
292
0
    return -1; \
293
0
  } \
294
35.7k
  dinfo = &this->dinfo; \
295
35.7k
  this->jerr.warning = FALSE; \
296
35.7k
  this->isInstanceError = FALSE;
297
298
#define GET_TJINSTANCE(handle, errorReturn) \
299
1.12M
  tjinstance *this = (tjinstance *)handle; \
300
1.12M
  \
301
1.12M
  if (!this) { \
302
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
303
0
    return errorReturn; \
304
0
  } \
305
1.12M
  this->jerr.warning = FALSE; \
306
1.12M
  this->isInstanceError = FALSE;
307
308
static int getPixelFormat(int pixelSize, int flags)
309
0
{
310
0
  if (pixelSize == 1) return TJPF_GRAY;
311
0
  if (pixelSize == 3) {
312
0
    if (flags & TJ_BGR) return TJPF_BGR;
313
0
    else return TJPF_RGB;
314
0
  }
315
0
  if (pixelSize == 4) {
316
0
    if (flags & TJ_ALPHAFIRST) {
317
0
      if (flags & TJ_BGR) return TJPF_XBGR;
318
0
      else return TJPF_XRGB;
319
0
    } else {
320
0
      if (flags & TJ_BGR) return TJPF_BGRX;
321
0
      else return TJPF_RGBX;
322
0
    }
323
0
  }
324
0
  return -1;
325
0
}
326
327
static void setCompDefaults(tjinstance *this, int pixelFormat)
328
71.4k
{
329
71.4k
  this->cinfo.in_color_space = pf2cs[pixelFormat];
330
71.4k
  this->cinfo.input_components = tjPixelSize[pixelFormat];
331
71.4k
  jpeg_set_defaults(&this->cinfo);
332
333
71.4k
  this->cinfo.restart_interval = this->restartIntervalBlocks;
334
71.4k
  this->cinfo.restart_in_rows = this->restartIntervalRows;
335
71.4k
  this->cinfo.X_density = (UINT16)this->xDensity;
336
71.4k
  this->cinfo.Y_density = (UINT16)this->yDensity;
337
71.4k
  this->cinfo.density_unit = (UINT8)this->densityUnits;
338
339
71.4k
  if (this->lossless) {
340
9.13k
#ifdef C_LOSSLESS_SUPPORTED
341
9.13k
    jpeg_enable_lossless(&this->cinfo, this->losslessPSV, this->losslessPt);
342
9.13k
#endif
343
9.13k
    if (pixelFormat == TJPF_GRAY)
344
1.15k
      this->subsamp = TJSAMP_GRAY;
345
7.97k
    else if (this->subsamp != TJSAMP_GRAY)
346
6.81k
      this->subsamp = TJSAMP_444;
347
9.13k
    return;
348
9.13k
  }
349
350
62.3k
  jpeg_set_quality(&this->cinfo, this->quality, TRUE);
351
62.3k
  this->cinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
352
353
62.3k
  switch (this->colorspace) {
354
0
  case TJCS_RGB:
355
0
    jpeg_set_colorspace(&this->cinfo, JCS_RGB);  break;
356
0
  case TJCS_YCbCr:
357
0
    jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);  break;
358
0
  case TJCS_GRAY:
359
0
    jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);  break;
360
0
  case TJCS_CMYK:
361
0
    jpeg_set_colorspace(&this->cinfo, JCS_CMYK);  break;
362
0
  case TJCS_YCCK:
363
0
    jpeg_set_colorspace(&this->cinfo, JCS_YCCK);  break;
364
62.3k
  default:
365
62.3k
    if (this->subsamp == TJSAMP_GRAY)
366
17.8k
      jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);
367
44.5k
    else if (pixelFormat == TJPF_CMYK)
368
5.84k
      jpeg_set_colorspace(&this->cinfo, JCS_YCCK);
369
38.7k
    else
370
38.7k
      jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);
371
62.3k
  }
372
373
62.3k
  this->cinfo.optimize_coding = this->optimize;
374
62.3k
#ifdef C_PROGRESSIVE_SUPPORTED
375
62.3k
  if (this->progressive) jpeg_simple_progression(&this->cinfo);
376
62.3k
#endif
377
62.3k
  this->cinfo.arith_code = this->arithmetic;
378
379
62.3k
  this->cinfo.comp_info[0].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
380
62.3k
  this->cinfo.comp_info[1].h_samp_factor = 1;
381
62.3k
  this->cinfo.comp_info[2].h_samp_factor = 1;
382
62.3k
  if (this->cinfo.num_components > 3)
383
5.84k
    this->cinfo.comp_info[3].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
384
62.3k
  this->cinfo.comp_info[0].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
385
62.3k
  this->cinfo.comp_info[1].v_samp_factor = 1;
386
62.3k
  this->cinfo.comp_info[2].v_samp_factor = 1;
387
62.3k
  if (this->cinfo.num_components > 3)
388
5.84k
    this->cinfo.comp_info[3].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
389
62.3k
}
390
391
392
static int getSubsamp(j_decompress_ptr dinfo)
393
38.8k
{
394
38.8k
  int retval = TJSAMP_UNKNOWN, i, k;
395
396
  /* The sampling factors actually have no meaning with grayscale JPEG files,
397
     and in fact it's possible to generate grayscale JPEGs with sampling
398
     factors > 1 (even though those sampling factors are ignored by the
399
     decompressor.)  Thus, we need to treat grayscale as a special case. */
400
38.8k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
401
21.4k
    return TJSAMP_GRAY;
402
403
83.8k
  for (i = 0; i < TJ_NUMSAMP; i++) {
404
77.3k
    if (i == TJSAMP_GRAY) continue;
405
406
69.8k
    if (dinfo->num_components == 3 ||
407
69.8k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
408
1.76k
          dinfo->jpeg_color_space == JCS_CMYK) &&
409
69.7k
         dinfo->num_components == 4)) {
410
69.7k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
411
69.7k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
412
14.6k
        int match = 0;
413
414
44.3k
        for (k = 1; k < dinfo->num_components; k++) {
415
29.6k
          int href = 1, vref = 1;
416
417
29.6k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
418
29.6k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
419
318
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
420
318
          }
421
29.6k
          if (dinfo->comp_info[k].h_samp_factor == href &&
422
29.6k
              dinfo->comp_info[k].v_samp_factor == vref)
423
22.0k
            match++;
424
29.6k
        }
425
14.6k
        if (match == dinfo->num_components - 1) {
426
10.0k
          retval = i;  break;
427
10.0k
        }
428
14.6k
      }
429
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
430
         in non-standard ways. */
431
59.6k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
432
59.6k
          dinfo->comp_info[0].v_samp_factor == 2 &&
433
59.6k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
434
8.70k
        int match = 0;
435
436
26.2k
        for (k = 1; k < dinfo->num_components; k++) {
437
17.5k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
438
439
17.5k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
440
17.5k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
441
171
            href = vref = 2;
442
171
          }
443
17.5k
          if (dinfo->comp_info[k].h_samp_factor == href &&
444
17.5k
              dinfo->comp_info[k].v_samp_factor == vref)
445
1.87k
            match++;
446
17.5k
        }
447
8.70k
        if (match == dinfo->num_components - 1) {
448
746
          retval = i;  break;
449
746
        }
450
8.70k
      }
451
      /* Handle 4:4:4 images whose sampling factors are specified in
452
         non-standard ways. */
453
58.9k
      if (dinfo->comp_info[0].h_samp_factor *
454
58.9k
          dinfo->comp_info[0].v_samp_factor <=
455
58.9k
          D_MAX_BLOCKS_IN_MCU / 3 && i == TJSAMP_444) {
456
5.62k
        int match = 0;
457
16.4k
        for (k = 1; k < dinfo->num_components; k++) {
458
11.3k
          if (dinfo->comp_info[k].h_samp_factor ==
459
11.3k
              dinfo->comp_info[0].h_samp_factor &&
460
11.3k
              dinfo->comp_info[k].v_samp_factor ==
461
2.68k
              dinfo->comp_info[0].v_samp_factor)
462
1.35k
            match++;
463
11.3k
          if (match == dinfo->num_components - 1) {
464
461
            retval = i;  break;
465
461
          }
466
11.3k
        }
467
5.62k
      }
468
58.9k
    }
469
69.8k
  }
470
17.3k
  return retval;
471
38.8k
}
472
473
474
static void setDecompParameters(tjinstance *this)
475
30.8k
{
476
30.8k
  this->subsamp = getSubsamp(&this->dinfo);
477
30.8k
  this->jpegWidth = this->dinfo.image_width;
478
30.8k
  this->jpegHeight = this->dinfo.image_height;
479
30.8k
  this->precision = this->dinfo.data_precision;
480
30.8k
  switch (this->dinfo.jpeg_color_space) {
481
15.5k
  case JCS_GRAYSCALE:  this->colorspace = TJCS_GRAY;  break;
482
6.76k
  case JCS_RGB:        this->colorspace = TJCS_RGB;  break;
483
8.23k
  case JCS_YCbCr:      this->colorspace = TJCS_YCbCr;  break;
484
181
  case JCS_CMYK:       this->colorspace = TJCS_CMYK;  break;
485
29
  case JCS_YCCK:       this->colorspace = TJCS_YCCK;  break;
486
18
  default:             this->colorspace = -1;  break;
487
30.8k
  }
488
30.8k
  this->progressive = this->dinfo.progressive_mode;
489
30.8k
  this->arithmetic = this->dinfo.arith_code;
490
30.8k
  this->lossless = this->dinfo.master->lossless;
491
30.8k
  this->losslessPSV = this->dinfo.Ss;
492
30.8k
  this->losslessPt = this->dinfo.Al;
493
30.8k
  this->xDensity = this->dinfo.X_density;
494
30.8k
  this->yDensity = this->dinfo.Y_density;
495
30.8k
  this->densityUnits = this->dinfo.density_unit;
496
30.8k
}
497
498
499
static void processFlags(tjhandle handle, int flags, int operation)
500
0
{
501
0
  tjinstance *this = (tjinstance *)handle;
502
503
0
  this->bottomUp = !!(flags & TJFLAG_BOTTOMUP);
504
505
0
#ifndef NO_PUTENV
506
0
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
507
0
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
508
0
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
509
0
#endif
510
511
0
  this->fastUpsample = !!(flags & TJFLAG_FASTUPSAMPLE);
512
0
  this->noRealloc = !!(flags & TJFLAG_NOREALLOC);
513
514
0
  if (operation == COMPRESS) {
515
0
    if (this->quality >= 96 || flags & TJFLAG_ACCURATEDCT)
516
0
      this->fastDCT = FALSE;
517
0
    else
518
0
      this->fastDCT = TRUE;
519
0
  } else
520
0
    this->fastDCT = !!(flags & TJFLAG_FASTDCT);
521
522
0
  this->jerr.stopOnWarning = !!(flags & TJFLAG_STOPONWARNING);
523
0
  this->progressive = !!(flags & TJFLAG_PROGRESSIVE);
524
525
0
  if (flags & TJFLAG_LIMITSCANS) this->scanLimit = 500;
526
0
}
527
528
529
/*************************** General API functions ***************************/
530
531
/* TurboJPEG 3+ */
532
DLLEXPORT tjhandle tj3Init(int initType)
533
152k
{
534
152k
  static const char FUNCTION_NAME[] = "tj3Init";
535
152k
  tjinstance *this = NULL;
536
152k
  tjhandle retval = NULL;
537
538
152k
  if (initType < 0 || initType >= TJ_NUMINIT)
539
152k
    THROWG("Invalid argument", NULL);
540
541
152k
  if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL)
542
152k
    THROWG("Memory allocation failure", NULL);
543
152k
  memset(this, 0, sizeof(tjinstance));
544
152k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
545
546
152k
  this->quality = -1;
547
152k
  this->subsamp = TJSAMP_UNKNOWN;
548
152k
  this->jpegWidth = -1;
549
152k
  this->jpegHeight = -1;
550
152k
  this->precision = 8;
551
152k
  this->colorspace = -1;
552
152k
  this->losslessPSV = 1;
553
152k
  this->xDensity = 1;
554
152k
  this->yDensity = 1;
555
152k
  this->scalingFactor = TJUNSCALED;
556
557
152k
  switch (initType) {
558
134k
  case TJINIT_COMPRESS:  return _tjInitCompress(this);
559
12.4k
  case TJINIT_DECOMPRESS:  return _tjInitDecompress(this);
560
5.51k
  case TJINIT_TRANSFORM:
561
5.51k
    retval = _tjInitCompress(this);
562
5.51k
    if (!retval) return NULL;
563
5.51k
    retval = _tjInitDecompress(this);
564
5.51k
    return retval;
565
152k
  }
566
567
0
bailout:
568
0
  return retval;
569
152k
}
570
571
572
368k
#define SET_PARAM(field, minValue, maxValue) { \
573
368k
  if (value < minValue || (maxValue > 0 && value > maxValue)) \
574
368k
    THROW("Parameter value out of range"); \
575
368k
  this->field = value; \
576
368k
}
577
578
596k
#define SET_BOOL_PARAM(field) { \
579
596k
  if (value < 0 || value > 1) \
580
596k
    THROW("Parameter value out of range"); \
581
596k
  this->field = (boolean)value; \
582
596k
}
583
584
/* TurboJPEG 3+ */
585
DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
586
964k
{
587
964k
  static const char FUNCTION_NAME[] = "tj3Set";
588
964k
  int retval = 0;
589
590
964k
  GET_TJINSTANCE(handle, -1);
591
592
964k
  switch (param) {
593
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
594
117k
  case TJPARAM_MAXPIXELS:
595
117k
    SET_PARAM(maxPixels, 0, -1);
596
117k
    break;
597
0
#endif
598
0
  case TJPARAM_STOPONWARNING:
599
0
    SET_BOOL_PARAM(jerr.stopOnWarning);
600
0
    break;
601
128k
  case TJPARAM_BOTTOMUP:
602
128k
    SET_BOOL_PARAM(bottomUp);
603
128k
    break;
604
125k
  case TJPARAM_NOREALLOC:
605
125k
    if (!(this->init & COMPRESS))
606
125k
      THROW("TJPARAM_NOREALLOC is not applicable to decompression instances.");
607
125k
    SET_BOOL_PARAM(noRealloc);
608
125k
    break;
609
51.1k
  case TJPARAM_QUALITY:
610
51.1k
    if (!(this->init & COMPRESS))
611
51.1k
      THROW("TJPARAM_QUALITY is not applicable to decompression instances.");
612
51.1k
    SET_PARAM(quality, 1, 100);
613
51.1k
    break;
614
51.1k
  case TJPARAM_SUBSAMP:
615
51.1k
    SET_PARAM(subsamp, 0, TJ_NUMSAMP - 1);
616
51.1k
    break;
617
0
  case TJPARAM_JPEGWIDTH:
618
0
    if (!(this->init & DECOMPRESS))
619
0
      THROW("TJPARAM_JPEGWIDTH is not applicable to compression instances.");
620
0
    THROW("TJPARAM_JPEGWIDTH is read-only in decompression instances.");
621
0
    break;
622
0
  case TJPARAM_JPEGHEIGHT:
623
0
    if (!(this->init & DECOMPRESS))
624
0
      THROW("TJPARAM_JPEGHEIGHT is not applicable to compression instances.");
625
0
    THROW("TJPARAM_JPEGHEIGHT is read-only in decompression instances.");
626
0
    break;
627
0
  case TJPARAM_PRECISION:
628
0
    if (!(this->init & DECOMPRESS))
629
0
      THROW("TJPARAM_PRECISION is not applicable to compression instances.");
630
0
    THROW("TJPARAM_PRECISION is read-only in decompression instances.");
631
0
    break;
632
0
  case TJPARAM_COLORSPACE:
633
0
    if (!(this->init & COMPRESS))
634
0
      THROW("TJPARAM_COLORSPACE is read-only in decompression instances.");
635
0
    SET_PARAM(colorspace, 0, TJ_NUMCS - 1);
636
0
    break;
637
11.2k
  case TJPARAM_FASTUPSAMPLE:
638
11.2k
    if (!(this->init & DECOMPRESS))
639
11.2k
      THROW("TJPARAM_FASTUPSAMPLE is not applicable to compression instances.");
640
11.2k
    SET_BOOL_PARAM(fastUpsample);
641
11.2k
    break;
642
97.8k
  case TJPARAM_FASTDCT:
643
97.8k
    SET_BOOL_PARAM(fastDCT);
644
97.8k
    break;
645
48.3k
  case TJPARAM_OPTIMIZE:
646
48.3k
    if (!(this->init & COMPRESS))
647
48.3k
      THROW("TJPARAM_OPTIMIZE is not applicable to decompression instances.");
648
48.3k
    SET_BOOL_PARAM(optimize);
649
48.3k
    break;
650
88.0k
  case TJPARAM_PROGRESSIVE:
651
88.0k
    if (!(this->init & COMPRESS))
652
88.0k
      THROW("TJPARAM_PROGRESSIVE is read-only in decompression instances.");
653
88.0k
    SET_BOOL_PARAM(progressive);
654
88.0k
    break;
655
13.3k
  case TJPARAM_SCANLIMIT:
656
13.3k
    if (!(this->init & DECOMPRESS))
657
13.3k
      THROW("TJPARAM_SCANLIMIT is not applicable to compression instances.");
658
13.3k
    SET_PARAM(scanLimit, 0, -1);
659
13.3k
    break;
660
88.0k
  case TJPARAM_ARITHMETIC:
661
88.0k
    if (!(this->init & COMPRESS))
662
88.0k
      THROW("TJPARAM_ARITHMETIC is read-only in decompression instances.");
663
88.0k
    SET_BOOL_PARAM(arithmetic);
664
88.0k
    break;
665
9.13k
  case TJPARAM_LOSSLESS:
666
9.13k
    if (!(this->init & COMPRESS))
667
9.13k
      THROW("TJPARAM_LOSSLESS is read-only in decompression instances.");
668
9.13k
    SET_BOOL_PARAM(lossless);
669
9.13k
    break;
670
9.13k
  case TJPARAM_LOSSLESSPSV:
671
9.13k
    if (!(this->init & COMPRESS))
672
9.13k
      THROW("TJPARAM_LOSSLESSPSV is read-only in decompression instances.");
673
9.13k
    SET_PARAM(losslessPSV, 1, 7);
674
9.13k
    break;
675
9.13k
  case TJPARAM_LOSSLESSPT:
676
9.13k
    if (!(this->init & COMPRESS))
677
9.13k
      THROW("TJPARAM_LOSSLESSPT is read-only in decompression instances.");
678
9.13k
    SET_PARAM(losslessPt, 0, this->precision - 1);
679
9.13k
    break;
680
21.2k
  case TJPARAM_RESTARTBLOCKS:
681
21.2k
    if (!(this->init & COMPRESS))
682
21.2k
      THROW("TJPARAM_RESTARTBLOCKS is not applicable to decompression instances.");
683
21.2k
    SET_PARAM(restartIntervalBlocks, 0, 65535);
684
21.2k
    if (value != 0) this->restartIntervalRows = 0;
685
21.2k
    break;
686
95.9k
  case TJPARAM_RESTARTROWS:
687
95.9k
    if (!(this->init & COMPRESS))
688
95.9k
      THROW("TJPARAM_RESTARTROWS is not applicable to decompression instances.");
689
95.9k
    SET_PARAM(restartIntervalRows, 0, 65535);
690
95.9k
    if (value != 0) this->restartIntervalBlocks = 0;
691
95.9k
    break;
692
0
  case TJPARAM_XDENSITY:
693
0
    if (!(this->init & COMPRESS))
694
0
      THROW("TJPARAM_XDENSITY is read-only in decompression instances.");
695
0
    SET_PARAM(xDensity, 1, 65535);
696
0
    break;
697
0
  case TJPARAM_YDENSITY:
698
0
    if (!(this->init & COMPRESS))
699
0
      THROW("TJPARAM_YDENSITY is read-only in decompression instances.");
700
0
    SET_PARAM(yDensity, 1, 65535);
701
0
    break;
702
0
  case TJPARAM_DENSITYUNITS:
703
0
    if (!(this->init & COMPRESS))
704
0
      THROW("TJPARAM_DENSITYUNITS is read-only in decompression instances.");
705
0
    SET_PARAM(densityUnits, 0, 2);
706
0
    break;
707
0
  default:
708
0
    THROW("Invalid parameter");
709
964k
  }
710
711
964k
bailout:
712
964k
  return retval;
713
964k
}
714
715
716
/* TurboJPEG 3+ */
717
DLLEXPORT int tj3Get(tjhandle handle, int param)
718
108k
{
719
108k
  tjinstance *this = (tjinstance *)handle;
720
108k
  if (!this) return -1;
721
722
108k
  switch (param) {
723
0
  case TJPARAM_STOPONWARNING:
724
0
    return this->jerr.stopOnWarning;
725
0
  case TJPARAM_BOTTOMUP:
726
0
    return this->bottomUp;
727
49.0k
  case TJPARAM_NOREALLOC:
728
49.0k
    return this->noRealloc;
729
0
  case TJPARAM_QUALITY:
730
0
    return this->quality;
731
9.56k
  case TJPARAM_SUBSAMP:
732
9.56k
    return this->subsamp;
733
15.5k
  case TJPARAM_JPEGWIDTH:
734
15.5k
    return this->jpegWidth;
735
15.5k
  case TJPARAM_JPEGHEIGHT:
736
15.5k
    return this->jpegHeight;
737
6.02k
  case TJPARAM_PRECISION:
738
6.02k
    return this->precision;
739
0
  case TJPARAM_COLORSPACE:
740
0
    return this->colorspace;
741
0
  case TJPARAM_FASTUPSAMPLE:
742
0
    return this->fastUpsample;
743
0
  case TJPARAM_FASTDCT:
744
0
    return this->fastDCT;
745
0
  case TJPARAM_OPTIMIZE:
746
0
    return this->optimize;
747
0
  case TJPARAM_PROGRESSIVE:
748
0
    return this->progressive;
749
0
  case TJPARAM_SCANLIMIT:
750
0
    return this->scanLimit;
751
0
  case TJPARAM_ARITHMETIC:
752
0
    return this->arithmetic;
753
12.4k
  case TJPARAM_LOSSLESS:
754
12.4k
    return this->lossless;
755
0
  case TJPARAM_LOSSLESSPSV:
756
0
    return this->losslessPSV;
757
0
  case TJPARAM_LOSSLESSPT:
758
0
    return this->losslessPt;
759
0
  case TJPARAM_RESTARTBLOCKS:
760
0
    return this->restartIntervalBlocks;
761
0
  case TJPARAM_RESTARTROWS:
762
0
    return this->restartIntervalRows;
763
0
  case TJPARAM_XDENSITY:
764
0
    return this->xDensity;
765
0
  case TJPARAM_YDENSITY:
766
0
    return this->yDensity;
767
0
  case TJPARAM_DENSITYUNITS:
768
0
    return this->densityUnits;
769
108k
  }
770
771
0
  return -1;
772
108k
}
773
774
775
/* TurboJPEG 3+ */
776
DLLEXPORT char *tj3GetErrorStr(tjhandle handle)
777
0
{
778
0
  tjinstance *this = (tjinstance *)handle;
779
780
0
  if (this && this->isInstanceError) {
781
0
    this->isInstanceError = FALSE;
782
0
    return this->errStr;
783
0
  } else
784
0
    return errStr;
785
0
}
786
787
/* TurboJPEG 2.0+ */
788
DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
789
0
{
790
0
  return tj3GetErrorStr(handle);
791
0
}
792
793
/* TurboJPEG 1.0+ */
794
DLLEXPORT char *tjGetErrorStr(void)
795
0
{
796
0
  return errStr;
797
0
}
798
799
800
/* TurboJPEG 3+ */
801
DLLEXPORT int tj3GetErrorCode(tjhandle handle)
802
0
{
803
0
  tjinstance *this = (tjinstance *)handle;
804
805
0
  if (this && this->jerr.warning) return TJERR_WARNING;
806
0
  else return TJERR_FATAL;
807
0
}
808
809
/* TurboJPEG 2.0+ */
810
DLLEXPORT int tjGetErrorCode(tjhandle handle)
811
0
{
812
0
  return tj3GetErrorCode(handle);
813
0
}
814
815
816
/* TurboJPEG 3+ */
817
DLLEXPORT void tj3Destroy(tjhandle handle)
818
152k
{
819
152k
  tjinstance *this = (tjinstance *)handle;
820
152k
  j_compress_ptr cinfo = NULL;
821
152k
  j_decompress_ptr dinfo = NULL;
822
823
152k
  if (!this) return;
824
825
152k
  cinfo = &this->cinfo;  dinfo = &this->dinfo;
826
152k
  this->jerr.warning = FALSE;
827
152k
  this->isInstanceError = FALSE;
828
829
152k
  if (setjmp(this->jerr.setjmp_buffer)) return;
830
152k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
831
152k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
832
152k
  free(this);
833
152k
}
834
835
/* TurboJPEG 1.0+ */
836
DLLEXPORT int tjDestroy(tjhandle handle)
837
{
838
  static const char FUNCTION_NAME[] = "tjDestroy";
839
  int retval = 0;
840
841
  if (!handle) THROWG("Invalid handle", -1);
842
843
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "No error");
844
  tj3Destroy(handle);
845
  if (strcmp(errStr, "No error")) retval = -1;
846
847
bailout:
848
  return retval;
849
}
850
851
852
/* These are exposed mainly because Windows can't malloc() and free() across
853
   DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
854
   with turbojpeg.dll for compatibility reasons.  However, these functions
855
   can potentially be used for other purposes by different implementations. */
856
857
/* TurboJPEG 3+ */
858
DLLEXPORT void tj3Free(void *buf)
859
77.5k
{
860
77.5k
  free(buf);
861
77.5k
}
862
863
/* TurboJPEG 1.2+ */
864
DLLEXPORT void tjFree(unsigned char *buf)
865
47.2k
{
866
47.2k
  tj3Free(buf);
867
47.2k
}
868
869
870
/* TurboJPEG 3+ */
871
DLLEXPORT void *tj3Alloc(size_t bytes)
872
0
{
873
0
  return malloc(bytes);
874
0
}
875
876
/* TurboJPEG 1.2+ */
877
DLLEXPORT unsigned char *tjAlloc(int bytes)
878
0
{
879
0
  return (unsigned char *)tj3Alloc((size_t)bytes);
880
0
}
881
882
883
/******************************** Compressor *********************************/
884
885
static tjhandle _tjInitCompress(tjinstance *this)
886
243k
{
887
243k
  static unsigned char buffer[1];
888
243k
  unsigned char *buf = buffer;
889
243k
  size_t size = 1;
890
891
  /* This is also straight out of example.c */
892
243k
  this->cinfo.err = jpeg_std_error(&this->jerr.pub);
893
243k
  this->jerr.pub.error_exit = my_error_exit;
894
243k
  this->jerr.pub.output_message = my_output_message;
895
243k
  this->jerr.emit_message = this->jerr.pub.emit_message;
896
243k
  this->jerr.pub.emit_message = my_emit_message;
897
243k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
898
243k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
899
243k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
900
901
243k
  if (setjmp(this->jerr.setjmp_buffer)) {
902
    /* If we get here, the JPEG code has signaled an error. */
903
0
    free(this);
904
0
    return NULL;
905
0
  }
906
907
243k
  jpeg_create_compress(&this->cinfo);
908
  /* Make an initial call so it will create the destination manager */
909
243k
  jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
910
911
243k
  this->init |= COMPRESS;
912
243k
  return (tjhandle)this;
913
243k
}
914
915
/* TurboJPEG 1.0+ */
916
DLLEXPORT tjhandle tjInitCompress(void)
917
{
918
  return tj3Init(TJINIT_COMPRESS);
919
}
920
921
922
/* TurboJPEG 3+ */
923
DLLEXPORT size_t tj3JPEGBufSize(int width, int height, int jpegSubsamp)
924
133k
{
925
133k
  static const char FUNCTION_NAME[] = "tj3JPEGBufSize";
926
133k
  unsigned long long retval = 0;
927
133k
  int mcuw, mcuh, chromasf;
928
929
133k
  if (width < 1 || height < 1 || jpegSubsamp < TJSAMP_UNKNOWN ||
930
133k
      jpegSubsamp >= TJ_NUMSAMP)
931
133k
    THROWG("Invalid argument", 0);
932
933
133k
  if (jpegSubsamp == TJSAMP_UNKNOWN)
934
0
    jpegSubsamp = TJSAMP_444;
935
936
  /* This allows for rare corner cases in which a JPEG image can actually be
937
     larger than the uncompressed input (we wouldn't mention it if it hadn't
938
     happened before.) */
939
133k
  mcuw = tjMCUWidth[jpegSubsamp];
940
133k
  mcuh = tjMCUHeight[jpegSubsamp];
941
133k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
942
133k
  retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
943
133k
  if (retval > (unsigned long long)((unsigned long)-1))
944
133k
    THROWG("Image is too large", 0);
945
946
133k
bailout:
947
133k
  return (size_t)retval;
948
133k
}
949
950
/* TurboJPEG 1.2+ */
951
DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
952
{
953
  static const char FUNCTION_NAME[] = "tjBufSize";
954
  size_t retval;
955
956
  if (jpegSubsamp < 0)
957
    THROWG("Invalid argument", 0);
958
959
  retval = tj3JPEGBufSize(width, height, jpegSubsamp);
960
961
bailout:
962
  return (retval == 0) ? (unsigned long)-1 : (unsigned long)retval;
963
}
964
965
/* TurboJPEG 1.0+ */
966
DLLEXPORT unsigned long TJBUFSIZE(int width, int height)
967
0
{
968
0
  static const char FUNCTION_NAME[] = "TJBUFSIZE";
969
0
  unsigned long long retval = 0;
970
971
0
  if (width < 1 || height < 1)
972
0
    THROWG("Invalid argument", (unsigned long)-1);
973
974
  /* This allows for rare corner cases in which a JPEG image can actually be
975
     larger than the uncompressed input (we wouldn't mention it if it hadn't
976
     happened before.) */
977
0
  retval = PAD(width, 16) * PAD(height, 16) * 6ULL + 2048ULL;
978
0
  if (retval > (unsigned long long)((unsigned long)-1))
979
0
    THROWG("Image is too large", (unsigned long)-1);
980
981
0
bailout:
982
0
  return (unsigned long)retval;
983
0
}
984
985
986
/* TurboJPEG 3+ */
987
DLLEXPORT size_t tj3YUVBufSize(int width, int align, int height, int subsamp)
988
15.8k
{
989
15.8k
  static const char FUNCTION_NAME[] = "tj3YUVBufSize";
990
15.8k
  unsigned long long retval = 0;
991
15.8k
  int nc, i;
992
993
15.8k
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
994
15.8k
    THROWG("Invalid argument", 0);
995
996
15.8k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
997
51.6k
  for (i = 0; i < nc; i++) {
998
35.7k
    int pw = tj3YUVPlaneWidth(i, width, subsamp);
999
35.7k
    int stride = PAD(pw, align);
1000
35.7k
    int ph = tj3YUVPlaneHeight(i, height, subsamp);
1001
1002
35.7k
    if (pw == 0 || ph == 0) return 0;
1003
35.7k
    else retval += (unsigned long long)stride * ph;
1004
35.7k
  }
1005
15.8k
  if (retval > (unsigned long long)((unsigned long)-1))
1006
15.8k
    THROWG("Image is too large", 0);
1007
1008
15.8k
bailout:
1009
15.8k
  return (size_t)retval;
1010
15.8k
}
1011
1012
/* TurboJPEG 1.4+ */
1013
DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
1014
                                      int subsamp)
1015
{
1016
  size_t retval = tj3YUVBufSize(width, align, height, subsamp);
1017
  return (retval == 0) ? (unsigned long)-1 : (unsigned long)retval;
1018
}
1019
1020
/* TurboJPEG 1.2+ */
1021
DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
1022
0
{
1023
0
  return tjBufSizeYUV2(width, 4, height, subsamp);
1024
0
}
1025
1026
/* TurboJPEG 1.1+ */
1027
DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
1028
0
{
1029
0
  return tjBufSizeYUV(width, height, subsamp);
1030
0
}
1031
1032
1033
/* TurboJPEG 3+ */
1034
DLLEXPORT int tj3YUVPlaneWidth(int componentID, int width, int subsamp)
1035
90.6k
{
1036
90.6k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneWidth";
1037
90.6k
  unsigned long long pw, retval = 0;
1038
90.6k
  int nc;
1039
1040
90.6k
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1041
90.6k
    THROWG("Invalid argument", 0);
1042
90.6k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1043
90.6k
  if (componentID < 0 || componentID >= nc)
1044
90.6k
    THROWG("Invalid argument", 0);
1045
1046
90.6k
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
1047
90.6k
  if (componentID == 0)
1048
48.3k
    retval = pw;
1049
42.3k
  else
1050
42.3k
    retval = pw * 8 / tjMCUWidth[subsamp];
1051
1052
90.6k
  if (retval > (unsigned long long)INT_MAX)
1053
90.6k
    THROWG("Width is too large", 0);
1054
1055
90.6k
bailout:
1056
90.6k
  return (int)retval;
1057
90.6k
}
1058
1059
/* TurboJPEG 1.4+ */
1060
DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
1061
7.64k
{
1062
7.64k
  int retval = tj3YUVPlaneWidth(componentID, width, subsamp);
1063
7.64k
  return (retval == 0) ? -1 : retval;
1064
7.64k
}
1065
1066
1067
/* TurboJPEG 3+ */
1068
DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp)
1069
90.6k
{
1070
90.6k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneHeight";
1071
90.6k
  unsigned long long ph, retval = 0;
1072
90.6k
  int nc;
1073
1074
90.6k
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1075
90.6k
    THROWG("Invalid argument", 0);
1076
90.6k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1077
90.6k
  if (componentID < 0 || componentID >= nc)
1078
90.6k
    THROWG("Invalid argument", 0);
1079
1080
90.6k
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
1081
90.6k
  if (componentID == 0)
1082
48.3k
    retval = ph;
1083
42.3k
  else
1084
42.3k
    retval = ph * 8 / tjMCUHeight[subsamp];
1085
1086
90.6k
  if (retval > (unsigned long long)INT_MAX)
1087
90.6k
    THROWG("Height is too large", 0);
1088
1089
90.6k
bailout:
1090
90.6k
  return (int)retval;
1091
90.6k
}
1092
1093
/* TurboJPEG 1.4+ */
1094
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
1095
7.64k
{
1096
7.64k
  int retval = tj3YUVPlaneHeight(componentID, height, subsamp);
1097
7.64k
  return (retval == 0) ? -1 : retval;
1098
7.64k
}
1099
1100
1101
/* TurboJPEG 3+ */
1102
DLLEXPORT size_t tj3YUVPlaneSize(int componentID, int width, int stride,
1103
                                 int height, int subsamp)
1104
0
{
1105
0
  static const char FUNCTION_NAME[] = "tj3YUVPlaneSize";
1106
0
  unsigned long long retval = 0;
1107
0
  int pw, ph;
1108
1109
0
  if (width < 1 || height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1110
0
    THROWG("Invalid argument", 0);
1111
1112
0
  pw = tj3YUVPlaneWidth(componentID, width, subsamp);
1113
0
  ph = tj3YUVPlaneHeight(componentID, height, subsamp);
1114
0
  if (pw == 0 || ph == 0) return 0;
1115
1116
0
  if (stride == 0) stride = pw;
1117
0
  else stride = abs(stride);
1118
1119
0
  retval = (unsigned long long)stride * (ph - 1) + pw;
1120
0
  if (retval > (unsigned long long)((unsigned long)-1))
1121
0
    THROWG("Image is too large", 0);
1122
1123
0
bailout:
1124
0
  return (size_t)retval;
1125
0
}
1126
1127
/* TurboJPEG 1.4+ */
1128
DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
1129
                                       int height, int subsamp)
1130
0
{
1131
0
  size_t retval = tj3YUVPlaneSize(componentID, width, stride, height, subsamp);
1132
0
  return (retval == 0) ? -1 : (unsigned long)retval;
1133
0
}
1134
1135
1136
/* tj3Compress*() is implemented in turbojpeg-mp.c */
1137
65.9k
#define BITS_IN_JSAMPLE  8
1138
#include "turbojpeg-mp.c"
1139
#undef BITS_IN_JSAMPLE
1140
61.3k
#define BITS_IN_JSAMPLE  12
1141
#include "turbojpeg-mp.c"
1142
#undef BITS_IN_JSAMPLE
1143
14.1k
#define BITS_IN_JSAMPLE  16
1144
#include "turbojpeg-mp.c"
1145
#undef BITS_IN_JSAMPLE
1146
1147
/* TurboJPEG 1.2+ */
1148
DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
1149
                          int width, int pitch, int height, int pixelFormat,
1150
                          unsigned char **jpegBuf, unsigned long *jpegSize,
1151
                          int jpegSubsamp, int jpegQual, int flags)
1152
{
1153
  static const char FUNCTION_NAME[] = "tjCompress2";
1154
  int retval = 0;
1155
  size_t size;
1156
1157
  GET_TJINSTANCE(handle, -1);
1158
1159
  if (jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP ||
1160
      jpegQual < 0 || jpegQual > 100)
1161
    THROW("Invalid argument");
1162
1163
  this->quality = jpegQual;
1164
  this->subsamp = jpegSubsamp;
1165
  processFlags(handle, flags, COMPRESS);
1166
1167
  size = (size_t)(*jpegSize);
1168
  retval = tj3Compress8(handle, srcBuf, width, pitch, height, pixelFormat,
1169
                        jpegBuf, &size);
1170
  *jpegSize = (unsigned long)size;
1171
1172
bailout:
1173
  return retval;
1174
}
1175
1176
/* TurboJPEG 1.0+ */
1177
DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
1178
                         int pitch, int height, int pixelSize,
1179
                         unsigned char *jpegBuf, unsigned long *jpegSize,
1180
                         int jpegSubsamp, int jpegQual, int flags)
1181
0
{
1182
0
  int retval = 0;
1183
0
  unsigned long size = jpegSize ? *jpegSize : 0;
1184
1185
0
  if (flags & TJ_YUV) {
1186
0
    size = tjBufSizeYUV(width, height, jpegSubsamp);
1187
0
    retval = tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1188
0
                          getPixelFormat(pixelSize, flags), jpegBuf,
1189
0
                          jpegSubsamp, flags);
1190
0
  } else {
1191
0
    retval = tjCompress2(handle, srcBuf, width, pitch, height,
1192
0
                         getPixelFormat(pixelSize, flags), &jpegBuf, &size,
1193
0
                         jpegSubsamp, jpegQual, flags | TJFLAG_NOREALLOC);
1194
0
  }
1195
0
  *jpegSize = size;
1196
0
  return retval;
1197
0
}
1198
1199
1200
/* TurboJPEG 3+ */
1201
DLLEXPORT int tj3EncodeYUVPlanes8(tjhandle handle, const unsigned char *srcBuf,
1202
                                  int width, int pitch, int height,
1203
                                  int pixelFormat, unsigned char **dstPlanes,
1204
                                  int *strides)
1205
11.2k
{
1206
11.2k
  static const char FUNCTION_NAME[] = "tj3EncodeYUVPlanes8";
1207
11.2k
  JSAMPROW *row_pointer = NULL;
1208
11.2k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
1209
11.2k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
1210
11.2k
  JSAMPROW *outbuf[MAX_COMPONENTS];
1211
11.2k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1212
11.2k
  JSAMPLE *ptr;
1213
11.2k
  jpeg_component_info *compptr;
1214
1215
11.2k
  GET_CINSTANCE(handle)
1216
1217
123k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1218
112k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
1219
112k
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
1220
112k
  }
1221
1222
11.2k
  if ((this->init & COMPRESS) == 0)
1223
11.2k
    THROW("Instance has not been initialized for compression");
1224
1225
11.2k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1226
11.2k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
1227
11.2k
      !dstPlanes[0])
1228
11.2k
    THROW("Invalid argument");
1229
11.2k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1230
11.2k
    THROW("Invalid argument");
1231
1232
11.2k
  if (this->subsamp == TJSAMP_UNKNOWN)
1233
11.2k
    THROW("TJPARAM_SUBSAMP must be specified");
1234
11.2k
  if (pixelFormat == TJPF_CMYK)
1235
11.2k
    THROW("Cannot generate YUV images from packed-pixel CMYK images");
1236
1237
11.2k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1238
1239
11.2k
  if (setjmp(this->jerr.setjmp_buffer)) {
1240
    /* If we get here, the JPEG code has signaled an error. */
1241
62
    retval = -1;  goto bailout;
1242
62
  }
1243
1244
11.2k
  cinfo->image_width = width;
1245
11.2k
  cinfo->image_height = height;
1246
11.2k
  cinfo->data_precision = 8;
1247
1248
11.2k
  setCompDefaults(this, pixelFormat);
1249
1250
  /* Execute only the parts of jpeg_start_compress() that we need.  If we
1251
     were to call the whole jpeg_start_compress() function, then it would try
1252
     to write the file headers, which could overflow the output buffer if the
1253
     YUV image were very small. */
1254
11.2k
  if (cinfo->global_state != CSTATE_START)
1255
11.2k
    THROW("libjpeg API is in the wrong state");
1256
11.2k
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
1257
11.2k
  jinit_c_master_control(cinfo, FALSE);
1258
11.2k
  jinit_color_converter(cinfo);
1259
11.2k
  jinit_downsampler(cinfo);
1260
11.2k
  (*cinfo->cconvert->start_pass) (cinfo);
1261
1262
11.2k
  pw0 = PAD(width, cinfo->max_h_samp_factor);
1263
11.2k
  ph0 = PAD(height, cinfo->max_v_samp_factor);
1264
1265
11.2k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1266
11.2k
    THROW("Memory allocation failure");
1267
32.1M
  for (i = 0; i < height; i++) {
1268
32.1M
    if (this->bottomUp)
1269
5.36M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
1270
26.7M
    else
1271
26.7M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
1272
32.1M
  }
1273
11.2k
  if (height < ph0)
1274
2.12k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1275
1276
37.7k
  for (i = 0; i < cinfo->num_components; i++) {
1277
26.4k
    compptr = &cinfo->comp_info[i];
1278
26.4k
    _tmpbuf[i] = (JSAMPLE *)malloc(
1279
26.4k
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1280
26.4k
          compptr->h_samp_factor, 32) *
1281
26.4k
      cinfo->max_v_samp_factor + 32);
1282
26.4k
    if (!_tmpbuf[i])
1283
26.4k
      THROW("Memory allocation failure");
1284
26.4k
    tmpbuf[i] =
1285
26.4k
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
1286
26.4k
    if (!tmpbuf[i])
1287
26.4k
      THROW("Memory allocation failure");
1288
58.7k
    for (row = 0; row < cinfo->max_v_samp_factor; row++) {
1289
32.2k
      unsigned char *_tmpbuf_aligned =
1290
32.2k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
1291
1292
32.2k
      tmpbuf[i][row] = &_tmpbuf_aligned[
1293
32.2k
        PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1294
32.2k
            compptr->h_samp_factor, 32) * row];
1295
32.2k
    }
1296
26.4k
    _tmpbuf2[i] =
1297
26.4k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1298
26.4k
                        compptr->v_samp_factor + 32);
1299
26.4k
    if (!_tmpbuf2[i])
1300
26.4k
      THROW("Memory allocation failure");
1301
26.4k
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1302
26.4k
    if (!tmpbuf2[i])
1303
26.4k
      THROW("Memory allocation failure");
1304
54.8k
    for (row = 0; row < compptr->v_samp_factor; row++) {
1305
28.4k
      unsigned char *_tmpbuf2_aligned =
1306
28.4k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
1307
1308
28.4k
      tmpbuf2[i][row] =
1309
28.4k
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1310
28.4k
    }
1311
26.4k
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
1312
26.4k
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1313
26.4k
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1314
26.4k
    if (!outbuf[i])
1315
26.4k
      THROW("Memory allocation failure");
1316
26.4k
    ptr = dstPlanes[i];
1317
69.7M
    for (row = 0; row < ph[i]; row++) {
1318
69.7M
      outbuf[i][row] = ptr;
1319
69.7M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1320
69.7M
    }
1321
26.4k
  }
1322
1323
11.2k
  if (setjmp(this->jerr.setjmp_buffer)) {
1324
    /* If we get here, the JPEG code has signaled an error. */
1325
0
    retval = -1;  goto bailout;
1326
0
  }
1327
1328
29.4M
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
1329
29.4M
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
1330
29.4M
                                       cinfo->max_v_samp_factor);
1331
29.4M
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
1332
96.5M
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
1333
67.0M
         i++, compptr++)
1334
67.0M
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
1335
67.0M
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
1336
67.0M
        compptr->v_samp_factor, pw[i]);
1337
29.4M
  }
1338
11.2k
  cinfo->next_scanline += height;
1339
11.2k
  jpeg_abort_compress(cinfo);
1340
1341
11.2k
bailout:
1342
11.2k
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1343
11.2k
  free(row_pointer);
1344
123k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1345
112k
    free(tmpbuf[i]);
1346
112k
    free(_tmpbuf[i]);
1347
112k
    free(tmpbuf2[i]);
1348
112k
    free(_tmpbuf2[i]);
1349
112k
    free(outbuf[i]);
1350
112k
  }
1351
11.2k
  if (this->jerr.warning) retval = -1;
1352
11.2k
  return retval;
1353
11.2k
}
1354
1355
/* TurboJPEG 1.4+ */
1356
DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
1357
                                int width, int pitch, int height,
1358
                                int pixelFormat, unsigned char **dstPlanes,
1359
                                int *strides, int subsamp, int flags)
1360
{
1361
  static const char FUNCTION_NAME[] = "tjEncodeYUVPlanes";
1362
  int retval = 0;
1363
1364
  GET_TJINSTANCE(handle, -1);
1365
1366
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
1367
    THROW("Invalid argument");
1368
1369
  this->subsamp = subsamp;
1370
  processFlags(handle, flags, COMPRESS);
1371
1372
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1373
                             dstPlanes, strides);
1374
1375
bailout:
1376
  return retval;
1377
}
1378
1379
1380
/* TurboJPEG 3+ */
1381
DLLEXPORT int tj3EncodeYUV8(tjhandle handle, const unsigned char *srcBuf,
1382
                            int width, int pitch, int height, int pixelFormat,
1383
                            unsigned char *dstBuf, int align)
1384
11.2k
{
1385
11.2k
  static const char FUNCTION_NAME[] = "tj3EncodeYUV8";
1386
11.2k
  unsigned char *dstPlanes[3];
1387
11.2k
  int pw0, ph0, strides[3], retval = -1;
1388
1389
11.2k
  GET_TJINSTANCE(handle, -1);
1390
1391
11.2k
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
1392
11.2k
      !IS_POW2(align))
1393
11.2k
    THROW("Invalid argument");
1394
1395
11.2k
  if (this->subsamp == TJSAMP_UNKNOWN)
1396
11.2k
    THROW("TJPARAM_SUBSAMP must be specified");
1397
1398
11.2k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1399
11.2k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1400
11.2k
  dstPlanes[0] = dstBuf;
1401
11.2k
  strides[0] = PAD(pw0, align);
1402
11.2k
  if (this->subsamp == TJSAMP_GRAY) {
1403
3.58k
    strides[1] = strides[2] = 0;
1404
3.58k
    dstPlanes[1] = dstPlanes[2] = NULL;
1405
7.68k
  } else {
1406
7.68k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
1407
7.68k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
1408
1409
7.68k
    strides[1] = strides[2] = PAD(pw1, align);
1410
7.68k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1411
7.68k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1412
7.68k
  }
1413
1414
11.2k
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1415
11.2k
                             dstPlanes, strides);
1416
1417
0
bailout:
1418
0
  return retval;
1419
11.2k
}
1420
1421
/* TurboJPEG 1.4+ */
1422
DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
1423
                           int width, int pitch, int height, int pixelFormat,
1424
                           unsigned char *dstBuf, int align, int subsamp,
1425
                           int flags)
1426
{
1427
  static const char FUNCTION_NAME[] = "tjEncodeYUV3";
1428
  int retval = 0;
1429
1430
  GET_TJINSTANCE(handle, -1);
1431
1432
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
1433
    THROW("Invalid argument");
1434
1435
  this->subsamp = subsamp;
1436
  processFlags(handle, flags, COMPRESS);
1437
1438
  return tj3EncodeYUV8(handle, srcBuf, width, pitch, height, pixelFormat,
1439
                       dstBuf, align);
1440
1441
bailout:
1442
  return retval;
1443
}
1444
1445
/* TurboJPEG 1.2+ */
1446
DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
1447
                           int pitch, int height, int pixelFormat,
1448
                           unsigned char *dstBuf, int subsamp, int flags)
1449
0
{
1450
0
  return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1451
0
                      dstBuf, 4, subsamp, flags);
1452
0
}
1453
1454
/* TurboJPEG 1.1+ */
1455
DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
1456
                          int pitch, int height, int pixelSize,
1457
                          unsigned char *dstBuf, int subsamp, int flags)
1458
0
{
1459
0
  return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1460
0
                      getPixelFormat(pixelSize, flags), dstBuf, subsamp,
1461
0
                      flags);
1462
0
}
1463
1464
1465
/* TurboJPEG 3+ */
1466
DLLEXPORT int tj3CompressFromYUVPlanes8(tjhandle handle,
1467
                                        const unsigned char * const *srcPlanes,
1468
                                        int width, const int *strides,
1469
                                        int height, unsigned char **jpegBuf,
1470
                                        size_t *jpegSize)
1471
11.2k
{
1472
11.2k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUVPlanes8";
1473
11.2k
  int i, row, retval = 0;
1474
11.2k
  boolean alloc = TRUE;
1475
11.2k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1476
11.2k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1477
11.2k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1478
11.2k
  JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1479
1480
11.2k
  GET_CINSTANCE(handle)
1481
1482
123k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1483
112k
    tmpbuf[i] = NULL;  inbuf[i] = NULL;
1484
112k
  }
1485
1486
11.2k
  if ((this->init & COMPRESS) == 0)
1487
11.2k
    THROW("Instance has not been initialized for compression");
1488
1489
11.2k
  if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
1490
11.2k
      jpegBuf == NULL || jpegSize == NULL)
1491
11.2k
    THROW("Invalid argument");
1492
11.2k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1493
11.2k
    THROW("Invalid argument");
1494
1495
11.2k
  if (this->quality == -1)
1496
11.2k
    THROW("TJPARAM_QUALITY must be specified");
1497
11.2k
  if (this->subsamp == TJSAMP_UNKNOWN)
1498
11.2k
    THROW("TJPARAM_SUBSAMP must be specified");
1499
1500
11.2k
  if (setjmp(this->jerr.setjmp_buffer)) {
1501
    /* If we get here, the JPEG code has signaled an error. */
1502
0
    retval = -1;  goto bailout;
1503
0
  }
1504
1505
11.2k
  cinfo->image_width = width;
1506
11.2k
  cinfo->image_height = height;
1507
11.2k
  cinfo->data_precision = 8;
1508
1509
11.2k
  if (this->noRealloc) {
1510
11.2k
    alloc = FALSE;  *jpegSize = tj3JPEGBufSize(width, height, this->subsamp);
1511
11.2k
  }
1512
11.2k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1513
11.2k
  setCompDefaults(this, TJPF_RGB);
1514
11.2k
  cinfo->raw_data_in = TRUE;
1515
1516
11.2k
  jpeg_start_compress(cinfo, TRUE);
1517
37.7k
  for (i = 0; i < cinfo->num_components; i++) {
1518
26.4k
    jpeg_component_info *compptr = &cinfo->comp_info[i];
1519
26.4k
    int ih;
1520
1521
26.4k
    iw[i] = compptr->width_in_blocks * DCTSIZE;
1522
26.4k
    ih = compptr->height_in_blocks * DCTSIZE;
1523
26.4k
    pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
1524
26.4k
            compptr->h_samp_factor / cinfo->max_h_samp_factor;
1525
26.4k
    ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
1526
26.4k
            compptr->v_samp_factor / cinfo->max_v_samp_factor;
1527
26.4k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1528
26.4k
    th[i] = compptr->v_samp_factor * DCTSIZE;
1529
26.4k
    tmpbufsize += iw[i] * th[i];
1530
26.4k
    if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1531
26.4k
      THROW("Memory allocation failure");
1532
26.4k
    ptr = (JSAMPLE *)srcPlanes[i];
1533
69.7M
    for (row = 0; row < ph[i]; row++) {
1534
69.7M
      inbuf[i][row] = ptr;
1535
69.7M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1536
69.7M
    }
1537
26.4k
  }
1538
11.2k
  if (usetmpbuf) {
1539
11.1k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1540
11.1k
      THROW("Memory allocation failure");
1541
11.1k
    ptr = _tmpbuf;
1542
37.4k
    for (i = 0; i < cinfo->num_components; i++) {
1543
26.2k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1544
26.2k
        THROW("Memory allocation failure");
1545
251k
      for (row = 0; row < th[i]; row++) {
1546
225k
        tmpbuf[i][row] = ptr;
1547
225k
        ptr += iw[i];
1548
225k
      }
1549
26.2k
    }
1550
11.1k
  }
1551
1552
11.2k
  if (setjmp(this->jerr.setjmp_buffer)) {
1553
    /* If we get here, the JPEG code has signaled an error. */
1554
0
    retval = -1;  goto bailout;
1555
0
  }
1556
1557
3.70M
  for (row = 0; row < (int)cinfo->image_height;
1558
3.69M
       row += cinfo->max_v_samp_factor * DCTSIZE) {
1559
3.69M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1560
3.69M
    int crow[MAX_COMPONENTS];
1561
1562
12.0M
    for (i = 0; i < cinfo->num_components; i++) {
1563
8.39M
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1564
1565
8.39M
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1566
8.39M
      if (usetmpbuf) {
1567
8.39M
        int j, k;
1568
1569
78.1M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1570
69.7M
          memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1571
          /* Duplicate last sample in row to fill out MCU */
1572
529M
          for (k = pw[i]; k < iw[i]; k++)
1573
459M
            tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1574
69.7M
        }
1575
        /* Duplicate last row to fill out MCU */
1576
8.54M
        for (j = ph[i] - crow[i]; j < th[i]; j++)
1577
146k
          memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1578
8.39M
        yuvptr[i] = tmpbuf[i];
1579
8.39M
      } else
1580
627
        yuvptr[i] = &inbuf[i][crow[i]];
1581
8.39M
    }
1582
3.69M
    jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1583
3.69M
  }
1584
11.2k
  jpeg_finish_compress(cinfo);
1585
1586
11.2k
bailout:
1587
11.2k
  if (cinfo->global_state > CSTATE_START) {
1588
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
1589
0
    jpeg_abort_compress(cinfo);
1590
0
  }
1591
123k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1592
112k
    free(tmpbuf[i]);
1593
112k
    free(inbuf[i]);
1594
112k
  }
1595
11.2k
  free(_tmpbuf);
1596
11.2k
  if (this->jerr.warning) retval = -1;
1597
11.2k
  return retval;
1598
11.2k
}
1599
1600
/* TurboJPEG 1.4+ */
1601
DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
1602
                                      const unsigned char **srcPlanes,
1603
                                      int width, const int *strides,
1604
                                      int height, int subsamp,
1605
                                      unsigned char **jpegBuf,
1606
                                      unsigned long *jpegSize, int jpegQual,
1607
                                      int flags)
1608
{
1609
  static const char FUNCTION_NAME[] = "tjCompressFromYUVPlanes";
1610
  int retval = 0;
1611
  size_t size;
1612
1613
  GET_TJINSTANCE(handle, -1);
1614
1615
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP || jpegSize == NULL ||
1616
      jpegQual < 0 || jpegQual > 100)
1617
    THROW("Invalid argument");
1618
1619
  this->quality = jpegQual;
1620
  this->subsamp = subsamp;
1621
  processFlags(handle, flags, COMPRESS);
1622
1623
  size = (size_t)(*jpegSize);
1624
  retval = tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
1625
                                     jpegBuf, &size);
1626
  *jpegSize = (unsigned long)size;
1627
1628
bailout:
1629
  return retval;
1630
}
1631
1632
1633
/* TurboJPEG 3+ */
1634
DLLEXPORT int tj3CompressFromYUV8(tjhandle handle,
1635
                                  const unsigned char *srcBuf, int width,
1636
                                  int align, int height,
1637
                                  unsigned char **jpegBuf, size_t *jpegSize)
1638
11.2k
{
1639
11.2k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUV8";
1640
11.2k
  const unsigned char *srcPlanes[3];
1641
11.2k
  int pw0, ph0, strides[3], retval = -1;
1642
1643
11.2k
  GET_TJINSTANCE(handle, -1);
1644
1645
11.2k
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1646
11.2k
      height <= 0)
1647
11.2k
    THROW("Invalid argument");
1648
1649
11.2k
  if (this->subsamp == TJSAMP_UNKNOWN)
1650
11.2k
    THROW("TJPARAM_SUBSAMP must be specified");
1651
1652
11.2k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1653
11.2k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1654
11.2k
  srcPlanes[0] = srcBuf;
1655
11.2k
  strides[0] = PAD(pw0, align);
1656
11.2k
  if (this->subsamp == TJSAMP_GRAY) {
1657
3.57k
    strides[1] = strides[2] = 0;
1658
3.57k
    srcPlanes[1] = srcPlanes[2] = NULL;
1659
7.64k
  } else {
1660
7.64k
    int pw1 = tjPlaneWidth(1, width, this->subsamp);
1661
7.64k
    int ph1 = tjPlaneHeight(1, height, this->subsamp);
1662
1663
7.64k
    strides[1] = strides[2] = PAD(pw1, align);
1664
7.64k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1665
7.64k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1666
7.64k
  }
1667
1668
11.2k
  return tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
1669
11.2k
                                   jpegBuf, jpegSize);
1670
1671
0
bailout:
1672
0
  return retval;
1673
11.2k
}
1674
1675
/* TurboJPEG 1.4+ */
1676
DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
1677
                                int width, int align, int height, int subsamp,
1678
                                unsigned char **jpegBuf,
1679
                                unsigned long *jpegSize, int jpegQual,
1680
                                int flags)
1681
{
1682
  static const char FUNCTION_NAME[] = "tjCompressFromYUV";
1683
  int retval = -1;
1684
  size_t size;
1685
1686
  GET_TJINSTANCE(handle, -1);
1687
1688
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
1689
    THROW("Invalid argument");
1690
1691
  this->quality = jpegQual;
1692
  this->subsamp = subsamp;
1693
  processFlags(handle, flags, COMPRESS);
1694
1695
  size = (size_t)(*jpegSize);
1696
  retval = tj3CompressFromYUV8(handle, srcBuf, width, align, height, jpegBuf,
1697
                               &size);
1698
  *jpegSize = (unsigned long)size;
1699
1700
bailout:
1701
  return retval;
1702
}
1703
1704
1705
/******************************* Decompressor ********************************/
1706
1707
static tjhandle _tjInitDecompress(tjinstance *this)
1708
48.8k
{
1709
48.8k
  static unsigned char buffer[1];
1710
1711
  /* This is also straight out of example.c */
1712
48.8k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1713
48.8k
  this->jerr.pub.error_exit = my_error_exit;
1714
48.8k
  this->jerr.pub.output_message = my_output_message;
1715
48.8k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1716
48.8k
  this->jerr.pub.emit_message = my_emit_message;
1717
48.8k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1718
48.8k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1719
48.8k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1720
1721
48.8k
  if (setjmp(this->jerr.setjmp_buffer)) {
1722
    /* If we get here, the JPEG code has signaled an error. */
1723
0
    free(this);
1724
0
    return NULL;
1725
0
  }
1726
1727
48.8k
  jpeg_create_decompress(&this->dinfo);
1728
  /* Make an initial call so it will create the source manager */
1729
48.8k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1730
1731
48.8k
  this->init |= DECOMPRESS;
1732
48.8k
  return (tjhandle)this;
1733
48.8k
}
1734
1735
/* TurboJPEG 1.0+ */
1736
DLLEXPORT tjhandle tjInitDecompress(void)
1737
{
1738
  return tj3Init(TJINIT_DECOMPRESS);
1739
}
1740
1741
1742
/* TurboJPEG 3+ */
1743
DLLEXPORT int tj3DecompressHeader(tjhandle handle,
1744
                                  const unsigned char *jpegBuf,
1745
                                  size_t jpegSize)
1746
18.0k
{
1747
18.0k
  static const char FUNCTION_NAME[] = "tj3DecompressHeader";
1748
18.0k
  int retval = 0;
1749
1750
18.0k
  GET_DINSTANCE(handle);
1751
18.0k
  if ((this->init & DECOMPRESS) == 0)
1752
18.0k
    THROW("Instance has not been initialized for decompression");
1753
1754
18.0k
  if (jpegBuf == NULL || jpegSize <= 0)
1755
18.0k
    THROW("Invalid argument");
1756
1757
18.0k
  if (setjmp(this->jerr.setjmp_buffer)) {
1758
    /* If we get here, the JPEG code has signaled an error. */
1759
1.98k
    return -1;
1760
1.98k
  }
1761
1762
16.0k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1763
1764
  /* jpeg_read_header() calls jpeg_abort() and returns JPEG_HEADER_TABLES_ONLY
1765
     if the datastream is a tables-only datastream.  Since we aren't using a
1766
     suspending data source, the only other value it can return is
1767
     JPEG_HEADER_OK. */
1768
16.0k
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1769
2.22k
    return 0;
1770
1771
13.7k
  setDecompParameters(this);
1772
1773
13.7k
  jpeg_abort_decompress(dinfo);
1774
1775
13.7k
  if (this->colorspace < 0)
1776
13.7k
    THROW("Could not determine colorspace of JPEG image");
1777
13.7k
  if (this->jpegWidth < 1 || this->jpegHeight < 1)
1778
13.7k
    THROW("Invalid data returned in header");
1779
1780
13.7k
bailout:
1781
13.7k
  if (this->jerr.warning) retval = -1;
1782
13.7k
  return retval;
1783
13.7k
}
1784
1785
/* TurboJPEG 1.4+ */
1786
DLLEXPORT int tjDecompressHeader3(tjhandle handle,
1787
                                  const unsigned char *jpegBuf,
1788
                                  unsigned long jpegSize, int *width,
1789
                                  int *height, int *jpegSubsamp,
1790
                                  int *jpegColorspace)
1791
{
1792
  static const char FUNCTION_NAME[] = "tjDecompressHeader3";
1793
  int retval = 0;
1794
1795
  GET_TJINSTANCE(handle, -1);
1796
1797
  if (width == NULL || height == NULL || jpegSubsamp == NULL ||
1798
      jpegColorspace == NULL)
1799
    THROW("Invalid argument");
1800
1801
  retval = tj3DecompressHeader(handle, jpegBuf, jpegSize);
1802
1803
  *width = tj3Get(handle, TJPARAM_JPEGWIDTH);
1804
  *height = tj3Get(handle, TJPARAM_JPEGHEIGHT);
1805
  *jpegSubsamp = tj3Get(handle, TJPARAM_SUBSAMP);
1806
  if (*jpegSubsamp == TJSAMP_UNKNOWN)
1807
    THROW("Could not determine subsampling level of JPEG image");
1808
  *jpegColorspace = tj3Get(handle, TJPARAM_COLORSPACE);
1809
1810
bailout:
1811
  return retval;
1812
}
1813
1814
/* TurboJPEG 1.1+ */
1815
DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
1816
                                  unsigned long jpegSize, int *width,
1817
                                  int *height, int *jpegSubsamp)
1818
0
{
1819
0
  int jpegColorspace;
1820
1821
0
  return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1822
0
                             jpegSubsamp, &jpegColorspace);
1823
0
}
1824
1825
/* TurboJPEG 1.0+ */
1826
DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
1827
                                 unsigned long jpegSize, int *width,
1828
                                 int *height)
1829
0
{
1830
0
  int jpegSubsamp;
1831
1832
0
  return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1833
0
                             &jpegSubsamp);
1834
0
}
1835
1836
1837
/* TurboJPEG 3+ */
1838
DLLEXPORT tjscalingfactor *tj3GetScalingFactors(int *numScalingFactors)
1839
0
{
1840
0
  static const char FUNCTION_NAME[] = "tj3GetScalingFactors";
1841
0
  tjscalingfactor *retval = (tjscalingfactor *)sf;
1842
1843
0
  if (numScalingFactors == NULL)
1844
0
    THROWG("Invalid argument", NULL);
1845
1846
0
  *numScalingFactors = NUMSF;
1847
1848
0
bailout:
1849
0
  return retval;
1850
0
}
1851
1852
/* TurboJPEG 1.2+ */
1853
DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numScalingFactors)
1854
0
{
1855
0
  return tj3GetScalingFactors(numScalingFactors);
1856
0
}
1857
1858
1859
/* TurboJPEG 3+ */
1860
DLLEXPORT int tj3SetScalingFactor(tjhandle handle,
1861
                                  tjscalingfactor scalingFactor)
1862
9.80k
{
1863
9.80k
  static const char FUNCTION_NAME[] = "tj3SetScalingFactor";
1864
9.80k
  int i, retval = 0;
1865
1866
9.80k
  GET_TJINSTANCE(handle, -1);
1867
9.80k
  if ((this->init & DECOMPRESS) == 0)
1868
9.80k
    THROW("Instance has not been initialized for decompression");
1869
1870
92.0k
  for (i = 0; i < NUMSF; i++) {
1871
92.0k
    if (scalingFactor.num == sf[i].num && scalingFactor.denom == sf[i].denom)
1872
9.80k
      break;
1873
92.0k
  }
1874
9.80k
  if (i >= NUMSF)
1875
9.80k
    THROW("Unsupported scaling factor");
1876
1877
9.80k
  this->scalingFactor = scalingFactor;
1878
1879
9.80k
bailout:
1880
9.80k
  return retval;
1881
9.80k
}
1882
1883
1884
/* TurboJPEG 3+ */
1885
DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion)
1886
6.34k
{
1887
6.34k
  static const char FUNCTION_NAME[] = "tj3SetCroppingRegion";
1888
6.34k
  int retval = 0, scaledWidth, scaledHeight;
1889
1890
6.34k
  GET_TJINSTANCE(handle, -1);
1891
6.34k
  if ((this->init & DECOMPRESS) == 0)
1892
6.34k
    THROW("Instance has not been initialized for decompression");
1893
1894
6.34k
  if (croppingRegion.x == 0 && croppingRegion.y == 0 &&
1895
6.34k
      croppingRegion.w == 0 && croppingRegion.h == 0) {
1896
6.22k
    this->croppingRegion = croppingRegion;
1897
6.22k
    return 0;
1898
6.22k
  }
1899
1900
117
  if (croppingRegion.x < 0 || croppingRegion.y < 0 || croppingRegion.w < 0 ||
1901
117
      croppingRegion.h < 0)
1902
117
    THROW("Invalid cropping region");
1903
117
  if (this->jpegWidth < 0 || this->jpegHeight < 0)
1904
117
    THROW("JPEG header has not yet been read");
1905
117
  if (this->precision == 16 || this->lossless)
1906
117
    THROW("Cannot partially decompress lossless JPEG images");
1907
117
  if (this->subsamp == TJSAMP_UNKNOWN)
1908
96
    THROW("Could not determine subsampling level of JPEG image");
1909
1910
96
  scaledWidth = TJSCALED(this->jpegWidth, this->scalingFactor);
1911
96
  scaledHeight = TJSCALED(this->jpegHeight, this->scalingFactor);
1912
1913
96
  if (croppingRegion.x %
1914
96
      TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor) != 0)
1915
0
    THROWI("The left boundary of the cropping region (%d) is not\n"
1916
96
           "divisible by the scaled MCU width (%d)",
1917
96
           croppingRegion.x,
1918
96
           TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor));
1919
96
  if (croppingRegion.w == 0)
1920
0
    croppingRegion.w = scaledWidth - croppingRegion.x;
1921
96
  if (croppingRegion.h == 0)
1922
0
    croppingRegion.h = scaledHeight - croppingRegion.y;
1923
96
  if (croppingRegion.w < 0 || croppingRegion.h < 0 ||
1924
96
      croppingRegion.x + croppingRegion.w > scaledWidth ||
1925
96
      croppingRegion.y + croppingRegion.h > scaledHeight)
1926
96
    THROW("The cropping region exceeds the scaled image dimensions");
1927
1928
96
  this->croppingRegion = croppingRegion;
1929
1930
117
bailout:
1931
117
  return retval;
1932
96
}
1933
1934
1935
/* tj3Decompress*() is implemented in turbojpeg-mp.c */
1936
1937
/* TurboJPEG 1.2+ */
1938
DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
1939
                            unsigned long jpegSize, unsigned char *dstBuf,
1940
                            int width, int pitch, int height, int pixelFormat,
1941
                            int flags)
1942
{
1943
  static const char FUNCTION_NAME[] = "tjDecompress2";
1944
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
1945
1946
  GET_DINSTANCE(handle);
1947
  if ((this->init & DECOMPRESS) == 0)
1948
    THROW("Instance has not been initialized for decompression");
1949
1950
  if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
1951
    THROW("Invalid argument");
1952
1953
  if (setjmp(this->jerr.setjmp_buffer)) {
1954
    /* If we get here, the JPEG code has signaled an error. */
1955
    retval = -1;  goto bailout;
1956
  }
1957
1958
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1959
  jpeg_read_header(dinfo, TRUE);
1960
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1961
  if (width == 0) width = jpegwidth;
1962
  if (height == 0) height = jpegheight;
1963
  for (i = 0; i < NUMSF; i++) {
1964
    scaledw = TJSCALED(jpegwidth, sf[i]);
1965
    scaledh = TJSCALED(jpegheight, sf[i]);
1966
    if (scaledw <= width && scaledh <= height)
1967
      break;
1968
  }
1969
  if (i >= NUMSF)
1970
    THROW("Could not scale down to desired image dimensions");
1971
1972
  processFlags(handle, flags, DECOMPRESS);
1973
1974
  if (tj3SetScalingFactor(handle, sf[i]) == -1)
1975
    return -1;
1976
  if (tj3SetCroppingRegion(handle, TJUNCROPPED) == -1)
1977
    return -1;
1978
  return tj3Decompress8(handle, jpegBuf, jpegSize, dstBuf, pitch, pixelFormat);
1979
1980
bailout:
1981
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1982
  if (this->jerr.warning) retval = -1;
1983
  return retval;
1984
}
1985
1986
/* TurboJPEG 1.0+ */
1987
DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1988
                           unsigned long jpegSize, unsigned char *dstBuf,
1989
                           int width, int pitch, int height, int pixelSize,
1990
                           int flags)
1991
0
{
1992
0
  if (flags & TJ_YUV)
1993
0
    return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1994
0
  else
1995
0
    return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1996
0
                         height, getPixelFormat(pixelSize, flags), flags);
1997
0
}
1998
1999
2000
static void setDecodeDefaults(tjinstance *this, int pixelFormat)
2001
2.41k
{
2002
2.41k
  int i;
2003
2004
2.41k
  this->dinfo.scale_num = this->dinfo.scale_denom = 1;
2005
2006
2.41k
  if (this->subsamp == TJSAMP_GRAY) {
2007
1.09k
    this->dinfo.num_components = this->dinfo.comps_in_scan = 1;
2008
1.09k
    this->dinfo.jpeg_color_space = JCS_GRAYSCALE;
2009
1.32k
  } else {
2010
1.32k
    this->dinfo.num_components = this->dinfo.comps_in_scan = 3;
2011
1.32k
    this->dinfo.jpeg_color_space = JCS_YCbCr;
2012
1.32k
  }
2013
2014
2.41k
  this->dinfo.comp_info = (jpeg_component_info *)
2015
2.41k
    (*this->dinfo.mem->alloc_small) ((j_common_ptr)&this->dinfo, JPOOL_IMAGE,
2016
2.41k
                                     this->dinfo.num_components *
2017
2.41k
                                     sizeof(jpeg_component_info));
2018
2019
7.47k
  for (i = 0; i < this->dinfo.num_components; i++) {
2020
5.06k
    jpeg_component_info *compptr = &this->dinfo.comp_info[i];
2021
2022
5.06k
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[this->subsamp] / 8 : 1;
2023
5.06k
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[this->subsamp] / 8 : 1;
2024
5.06k
    compptr->component_index = i;
2025
5.06k
    compptr->component_id = i + 1;
2026
5.06k
    compptr->quant_tbl_no = compptr->dc_tbl_no =
2027
5.06k
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
2028
5.06k
    this->dinfo.cur_comp_info[i] = compptr;
2029
5.06k
  }
2030
2.41k
  this->dinfo.data_precision = 8;
2031
7.24k
  for (i = 0; i < 2; i++) {
2032
4.83k
    if (this->dinfo.quant_tbl_ptrs[i] == NULL)
2033
760
      this->dinfo.quant_tbl_ptrs[i] =
2034
760
        jpeg_alloc_quant_table((j_common_ptr)&this->dinfo);
2035
4.83k
  }
2036
2.41k
}
2037
2038
2039
static int my_read_markers(j_decompress_ptr dinfo)
2040
2.41k
{
2041
2.41k
  return JPEG_REACHED_SOS;
2042
2.41k
}
2043
2044
static void my_reset_marker_reader(j_decompress_ptr dinfo)
2045
2.41k
{
2046
2.41k
}
2047
2048
/* TurboJPEG 3+ */
2049
DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle,
2050
                                  const unsigned char * const *srcPlanes,
2051
                                  const int *strides, unsigned char *dstBuf,
2052
                                  int width, int pitch, int height,
2053
                                  int pixelFormat)
2054
754
{
2055
754
  static const char FUNCTION_NAME[] = "tj3DecodeYUVPlanes8";
2056
754
  JSAMPROW *row_pointer = NULL;
2057
754
  JSAMPLE *_tmpbuf[MAX_COMPONENTS];
2058
754
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
2059
754
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
2060
754
  JSAMPLE *ptr;
2061
754
  jpeg_component_info *compptr;
2062
754
  int (*old_read_markers) (j_decompress_ptr);
2063
754
  void (*old_reset_marker_reader) (j_decompress_ptr);
2064
2065
754
  GET_DINSTANCE(handle);
2066
2067
8.29k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2068
7.54k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;  inbuf[i] = NULL;
2069
7.54k
  }
2070
2071
754
  if ((this->init & DECOMPRESS) == 0)
2072
754
    THROW("Instance has not been initialized for decompression");
2073
2074
754
  if (!srcPlanes || !srcPlanes[0] || dstBuf == NULL || width <= 0 ||
2075
754
      pitch < 0 || height <= 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
2076
754
    THROW("Invalid argument");
2077
754
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
2078
754
    THROW("Invalid argument");
2079
2080
754
  if (setjmp(this->jerr.setjmp_buffer)) {
2081
    /* If we get here, the JPEG code has signaled an error. */
2082
2
    retval = -1;  goto bailout;
2083
2
  }
2084
2085
752
  if (this->subsamp == TJSAMP_UNKNOWN)
2086
752
    THROW("TJPARAM_SUBSAMP must be specified");
2087
752
  if (pixelFormat == TJPF_CMYK)
2088
752
    THROW("Cannot decode YUV images into packed-pixel CMYK images.");
2089
2090
754
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
2091
752
  dinfo->image_width = width;
2092
752
  dinfo->image_height = height;
2093
2094
752
  dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
2095
752
  dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
2096
752
  dinfo->Se = DCTSIZE2 - 1;
2097
752
  setDecodeDefaults(this, pixelFormat);
2098
752
  old_read_markers = dinfo->marker->read_markers;
2099
752
  dinfo->marker->read_markers = my_read_markers;
2100
752
  old_reset_marker_reader = dinfo->marker->reset_marker_reader;
2101
752
  dinfo->marker->reset_marker_reader = my_reset_marker_reader;
2102
752
  jpeg_read_header(dinfo, TRUE);
2103
752
  dinfo->marker->read_markers = old_read_markers;
2104
752
  dinfo->marker->reset_marker_reader = old_reset_marker_reader;
2105
2106
752
  this->dinfo.out_color_space = pf2cs[pixelFormat];
2107
752
  this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2108
752
  dinfo->do_fancy_upsampling = FALSE;
2109
752
  dinfo->Se = DCTSIZE2 - 1;
2110
752
  jinit_master_decompress(dinfo);
2111
752
  (*dinfo->upsample->start_pass) (dinfo);
2112
2113
752
  pw0 = PAD(width, dinfo->max_h_samp_factor);
2114
752
  ph0 = PAD(height, dinfo->max_v_samp_factor);
2115
2116
752
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
2117
2118
752
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
2119
752
    THROW("Memory allocation failure");
2120
2.25M
  for (i = 0; i < height; i++) {
2121
2.25M
    if (this->bottomUp)
2122
821k
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
2123
1.43M
    else
2124
1.43M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
2125
2.25M
  }
2126
752
  if (height < ph0)
2127
238
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
2128
2129
2.32k
  for (i = 0; i < dinfo->num_components; i++) {
2130
1.57k
    compptr = &dinfo->comp_info[i];
2131
1.57k
    _tmpbuf[i] =
2132
1.57k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
2133
1.57k
                        compptr->v_samp_factor + 32);
2134
1.57k
    if (!_tmpbuf[i])
2135
1.57k
      THROW("Memory allocation failure");
2136
1.57k
    tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
2137
1.57k
    if (!tmpbuf[i])
2138
1.57k
      THROW("Memory allocation failure");
2139
3.45k
    for (row = 0; row < compptr->v_samp_factor; row++) {
2140
1.88k
      unsigned char *_tmpbuf_aligned =
2141
1.88k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
2142
2143
1.88k
      tmpbuf[i][row] =
2144
1.88k
        &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
2145
1.88k
    }
2146
1.57k
    pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
2147
1.57k
    ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2148
1.57k
    inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
2149
1.57k
    if (!inbuf[i])
2150
1.57k
      THROW("Memory allocation failure");
2151
1.57k
    ptr = (JSAMPLE *)srcPlanes[i];
2152
4.02M
    for (row = 0; row < ph[i]; row++) {
2153
4.02M
      inbuf[i][row] = ptr;
2154
4.02M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2155
4.02M
    }
2156
1.57k
  }
2157
2158
752
  if (setjmp(this->jerr.setjmp_buffer)) {
2159
    /* If we get here, the JPEG code has signaled an error. */
2160
0
    retval = -1;  goto bailout;
2161
0
  }
2162
2163
1.79M
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
2164
1.79M
    JDIMENSION inrow = 0, outrow = 0;
2165
2166
5.36M
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
2167
3.56M
         i++, compptr++)
2168
3.56M
      jcopy_sample_rows(inbuf[i],
2169
3.56M
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
2170
3.56M
        compptr->v_samp_factor, pw[i]);
2171
1.79M
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
2172
1.79M
                                 dinfo->max_v_samp_factor, &row_pointer[row],
2173
1.79M
                                 &outrow, dinfo->max_v_samp_factor);
2174
1.79M
  }
2175
752
  jpeg_abort_decompress(dinfo);
2176
2177
754
bailout:
2178
754
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2179
754
  free(row_pointer);
2180
8.29k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2181
7.54k
    free(tmpbuf[i]);
2182
7.54k
    free(_tmpbuf[i]);
2183
7.54k
    free(inbuf[i]);
2184
7.54k
  }
2185
754
  if (this->jerr.warning) retval = -1;
2186
754
  return retval;
2187
752
}
2188
2189
/* TurboJPEG 1.4+ */
2190
DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
2191
                                const unsigned char **srcPlanes,
2192
                                const int *strides, int subsamp,
2193
                                unsigned char *dstBuf, int width, int pitch,
2194
                                int height, int pixelFormat, int flags)
2195
{
2196
  static const char FUNCTION_NAME[] = "tjDecodeYUVPlanes";
2197
  int retval = 0;
2198
2199
  GET_TJINSTANCE(handle, -1);
2200
2201
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
2202
    THROW("Invalid argument");
2203
2204
  this->subsamp = subsamp;
2205
  processFlags(handle, flags, DECOMPRESS);
2206
2207
  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
2208
                             height, pixelFormat);
2209
2210
bailout:
2211
  return retval;
2212
}
2213
2214
2215
/* TurboJPEG 3+ */
2216
DLLEXPORT int tj3DecodeYUV8(tjhandle handle, const unsigned char *srcBuf,
2217
                            int align, unsigned char *dstBuf, int width,
2218
                            int pitch, int height, int pixelFormat)
2219
754
{
2220
754
  static const char FUNCTION_NAME[] = "tj3DecodeYUV8";
2221
754
  const unsigned char *srcPlanes[3];
2222
754
  int pw0, ph0, strides[3], retval = -1;
2223
2224
754
  GET_TJINSTANCE(handle, -1);
2225
2226
754
  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || width <= 0 ||
2227
754
      height <= 0)
2228
754
    THROW("Invalid argument");
2229
2230
754
  if (this->subsamp == TJSAMP_UNKNOWN)
2231
754
    THROW("TJPARAM_SUBSAMP must be specified");
2232
2233
754
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2234
754
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2235
754
  srcPlanes[0] = srcBuf;
2236
754
  strides[0] = PAD(pw0, align);
2237
754
  if (this->subsamp == TJSAMP_GRAY) {
2238
341
    strides[1] = strides[2] = 0;
2239
341
    srcPlanes[1] = srcPlanes[2] = NULL;
2240
413
  } else {
2241
413
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2242
413
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2243
2244
413
    strides[1] = strides[2] = PAD(pw1, align);
2245
413
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
2246
413
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
2247
413
  }
2248
2249
754
  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
2250
754
                             height, pixelFormat);
2251
2252
0
bailout:
2253
0
  return retval;
2254
754
}
2255
2256
/* TurboJPEG 1.4+ */
2257
DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
2258
                          int align, int subsamp, unsigned char *dstBuf,
2259
                          int width, int pitch, int height, int pixelFormat,
2260
                          int flags)
2261
{
2262
  static const char FUNCTION_NAME[] = "tjDecodeYUV";
2263
  int retval = -1;
2264
2265
  GET_TJINSTANCE(handle, -1);
2266
2267
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
2268
    THROW("Invalid argument");
2269
2270
  this->subsamp = subsamp;
2271
  processFlags(handle, flags, DECOMPRESS);
2272
2273
  return tj3DecodeYUV8(handle, srcBuf, align, dstBuf, width, pitch, height,
2274
                       pixelFormat);
2275
2276
bailout:
2277
  return retval;
2278
}
2279
2280
2281
/* TurboJPEG 3+ */
2282
DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle,
2283
                                        const unsigned char *jpegBuf,
2284
                                        size_t jpegSize,
2285
                                        unsigned char **dstPlanes,
2286
                                        int *strides)
2287
4.60k
{
2288
4.60k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUVPlanes8";
2289
4.60k
  int i, row, retval = 0;
2290
4.60k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
2291
4.60k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
2292
4.60k
  JSAMPLE *_tmpbuf = NULL, *ptr;
2293
4.60k
  JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
2294
4.60k
  int dctsize;
2295
4.60k
  struct my_progress_mgr progress;
2296
2297
4.60k
  GET_DINSTANCE(handle);
2298
2299
50.6k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2300
46.0k
    tmpbuf[i] = NULL;  outbuf[i] = NULL;
2301
46.0k
  }
2302
2303
4.60k
  if ((this->init & DECOMPRESS) == 0)
2304
4.60k
    THROW("Instance has not been initialized for decompression");
2305
2306
4.60k
  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0])
2307
4.60k
    THROW("Invalid argument");
2308
2309
4.60k
  if (this->scanLimit) {
2310
4.60k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2311
4.60k
    progress.pub.progress_monitor = my_progress_monitor;
2312
4.60k
    progress.this = this;
2313
4.60k
    dinfo->progress = &progress.pub;
2314
4.60k
  } else
2315
0
    dinfo->progress = NULL;
2316
2317
4.60k
  if (setjmp(this->jerr.setjmp_buffer)) {
2318
    /* If we get here, the JPEG code has signaled an error. */
2319
0
    retval = -1;  goto bailout;
2320
0
  }
2321
2322
4.60k
  if (dinfo->global_state <= DSTATE_START) {
2323
0
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2324
0
    jpeg_read_header(dinfo, TRUE);
2325
0
  }
2326
4.60k
  setDecompParameters(this);
2327
4.60k
  if (this->subsamp == TJSAMP_UNKNOWN)
2328
4.60k
    THROW("Could not determine subsampling level of JPEG image");
2329
2330
4.60k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
2331
4.60k
    THROW("Invalid argument");
2332
2333
4.60k
  if (dinfo->num_components > 3)
2334
4.59k
    THROW("JPEG image must have 3 or fewer components");
2335
2336
4.59k
  dinfo->scale_num = this->scalingFactor.num;
2337
4.59k
  dinfo->scale_denom = this->scalingFactor.denom;
2338
4.59k
  jpeg_calc_output_dimensions(dinfo);
2339
2340
4.59k
  dctsize = DCTSIZE * this->scalingFactor.num / this->scalingFactor.denom;
2341
2342
13.6k
  for (i = 0; i < dinfo->num_components; i++) {
2343
9.07k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
2344
9.07k
    int ih;
2345
2346
9.07k
    iw[i] = compptr->width_in_blocks * dctsize;
2347
9.07k
    ih = compptr->height_in_blocks * dctsize;
2348
9.07k
    pw[i] = tj3YUVPlaneWidth(i, dinfo->output_width, this->subsamp);
2349
9.07k
    ph[i] = tj3YUVPlaneHeight(i, dinfo->output_height, this->subsamp);
2350
9.07k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
2351
9.07k
    th[i] = compptr->v_samp_factor * dctsize;
2352
9.07k
    tmpbufsize += iw[i] * th[i];
2353
9.07k
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
2354
9.07k
      THROW("Memory allocation failure");
2355
9.07k
    ptr = dstPlanes[i];
2356
54.7M
    for (row = 0; row < ph[i]; row++) {
2357
54.7M
      outbuf[i][row] = ptr;
2358
54.7M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2359
54.7M
    }
2360
9.07k
  }
2361
4.59k
  if (usetmpbuf) {
2362
4.35k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
2363
4.35k
      THROW("Memory allocation failure");
2364
4.35k
    ptr = _tmpbuf;
2365
12.8k
    for (i = 0; i < dinfo->num_components; i++) {
2366
8.49k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
2367
8.49k
        THROW("Memory allocation failure");
2368
104k
      for (row = 0; row < th[i]; row++) {
2369
96.0k
        tmpbuf[i][row] = ptr;
2370
96.0k
        ptr += iw[i];
2371
96.0k
      }
2372
8.49k
    }
2373
4.35k
  }
2374
2375
4.59k
  if (setjmp(this->jerr.setjmp_buffer)) {
2376
    /* If we get here, the JPEG code has signaled an error. */
2377
2.28k
    retval = -1;  goto bailout;
2378
2.28k
  }
2379
2380
2.30k
  dinfo->do_fancy_upsampling = !this->fastUpsample;
2381
18.4E
  dinfo->dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2382
2.30k
  dinfo->raw_data_out = TRUE;
2383
2384
2.30k
  jpeg_start_decompress(dinfo);
2385
1.11M
  for (row = 0; row < (int)dinfo->output_height;
2386
1.10M
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
2387
1.10M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
2388
1.10M
    int crow[MAX_COMPONENTS];
2389
2390
3.18M
    for (i = 0; i < dinfo->num_components; i++) {
2391
2.07M
      jpeg_component_info *compptr = &dinfo->comp_info[i];
2392
2393
2.07M
      if (this->subsamp == TJSAMP_420) {
2394
        /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
2395
           to be clever and use the IDCT to perform upsampling on the U and V
2396
           planes.  For instance, if the output image is to be scaled by 1/2
2397
           relative to the JPEG image, then the scaling factor and upsampling
2398
           effectively cancel each other, so a normal 8x8 IDCT can be used.
2399
           However, this is not desirable when using the decompress-to-YUV
2400
           functionality in TurboJPEG, since we want to output the U and V
2401
           planes in their subsampled form.  Thus, we have to override some
2402
           internal libjpeg parameters to force it to use the "scaled" IDCT
2403
           functions on the U and V planes. */
2404
263k
        compptr->_DCT_scaled_size = dctsize;
2405
263k
        compptr->MCU_sample_width = tjMCUWidth[this->subsamp] *
2406
263k
          this->scalingFactor.num / this->scalingFactor.denom *
2407
263k
          compptr->v_samp_factor / dinfo->max_v_samp_factor;
2408
263k
        dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
2409
263k
      }
2410
2.07M
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2411
2.07M
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
2412
72.2k
      else yuvptr[i] = &outbuf[i][crow[i]];
2413
2.07M
    }
2414
1.10M
    jpeg_read_raw_data(dinfo, yuvptr,
2415
1.10M
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
2416
1.10M
    if (usetmpbuf) {
2417
1.07M
      int j;
2418
2419
3.07M
      for (i = 0; i < dinfo->num_components; i++) {
2420
20.8M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
2421
18.8M
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
2422
18.8M
        }
2423
2.00M
      }
2424
1.07M
    }
2425
1.10M
  }
2426
2.30k
  jpeg_finish_decompress(dinfo);
2427
2428
4.60k
bailout:
2429
4.60k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2430
50.6k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2431
46.0k
    free(tmpbuf[i]);
2432
46.0k
    free(outbuf[i]);
2433
46.0k
  }
2434
4.60k
  free(_tmpbuf);
2435
4.60k
  if (this->jerr.warning) retval = -1;
2436
4.60k
  return retval;
2437
2.30k
}
2438
2439
/* TurboJPEG 1.4+ */
2440
DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
2441
                                      const unsigned char *jpegBuf,
2442
                                      unsigned long jpegSize,
2443
                                      unsigned char **dstPlanes, int width,
2444
                                      int *strides, int height, int flags)
2445
{
2446
  static const char FUNCTION_NAME[] = "tjDecompressToYUVPlanes";
2447
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
2448
2449
  GET_DINSTANCE(handle);
2450
  if ((this->init & DECOMPRESS) == 0)
2451
    THROW("Instance has not been initialized for decompression");
2452
2453
  if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
2454
    THROW("Invalid argument");
2455
2456
  if (setjmp(this->jerr.setjmp_buffer)) {
2457
    /* If we get here, the JPEG code has signaled an error. */
2458
    retval = -1;  goto bailout;
2459
  }
2460
2461
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2462
  jpeg_read_header(dinfo, TRUE);
2463
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
2464
  if (width == 0) width = jpegwidth;
2465
  if (height == 0) height = jpegheight;
2466
  for (i = 0; i < NUMSF; i++) {
2467
    scaledw = TJSCALED(jpegwidth, sf[i]);
2468
    scaledh = TJSCALED(jpegheight, sf[i]);
2469
    if (scaledw <= width && scaledh <= height)
2470
      break;
2471
  }
2472
  if (i >= NUMSF)
2473
    THROW("Could not scale down to desired image dimensions");
2474
2475
  processFlags(handle, flags, DECOMPRESS);
2476
2477
  if (tj3SetScalingFactor(handle, sf[i]) == -1)
2478
    return -1;
2479
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2480
                                   strides);
2481
2482
bailout:
2483
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2484
  if (this->jerr.warning) retval = -1;
2485
  return retval;
2486
}
2487
2488
2489
/* TurboJPEG 3+ */
2490
DLLEXPORT int tj3DecompressToYUV8(tjhandle handle,
2491
                                  const unsigned char *jpegBuf,
2492
                                  size_t jpegSize,
2493
                                  unsigned char *dstBuf, int align)
2494
4.60k
{
2495
4.60k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUV8";
2496
4.60k
  unsigned char *dstPlanes[3];
2497
4.60k
  int pw0, ph0, strides[3], retval = -1;
2498
4.60k
  int width, height;
2499
2500
4.60k
  GET_DINSTANCE(handle);
2501
2502
4.60k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || align < 1 ||
2503
4.60k
      !IS_POW2(align))
2504
4.60k
    THROW("Invalid argument");
2505
2506
4.60k
  if (setjmp(this->jerr.setjmp_buffer)) {
2507
    /* If we get here, the JPEG code has signaled an error. */
2508
0
    retval = -1;  goto bailout;
2509
0
  }
2510
2511
4.60k
  if (dinfo->global_state <= DSTATE_START) {
2512
4.60k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2513
4.60k
    jpeg_read_header(dinfo, TRUE);
2514
4.60k
  }
2515
4.60k
  setDecompParameters(this);
2516
4.60k
  if (this->subsamp == TJSAMP_UNKNOWN)
2517
4.60k
    THROW("Could not determine subsampling level of JPEG image");
2518
2519
4.60k
  width = TJSCALED(dinfo->image_width, this->scalingFactor);
2520
4.60k
  height = TJSCALED(dinfo->image_height, this->scalingFactor);
2521
2522
4.60k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2523
4.60k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2524
4.60k
  dstPlanes[0] = dstBuf;
2525
4.60k
  strides[0] = PAD(pw0, align);
2526
4.60k
  if (this->subsamp == TJSAMP_GRAY) {
2527
2.35k
    strides[1] = strides[2] = 0;
2528
2.35k
    dstPlanes[1] = dstPlanes[2] = NULL;
2529
2.35k
  } else {
2530
2.24k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2531
2.24k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2532
2533
2.24k
    strides[1] = strides[2] = PAD(pw1, align);
2534
2.24k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
2535
2.24k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
2536
2.24k
  }
2537
2538
4.60k
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2539
4.60k
                                   strides);
2540
2541
9
bailout:
2542
9
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2543
9
  if (this->jerr.warning) retval = -1;
2544
9
  return retval;
2545
4.60k
}
2546
2547
/* TurboJPEG 1.4+ */
2548
DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
2549
                                 unsigned long jpegSize, unsigned char *dstBuf,
2550
                                 int width, int align, int height, int flags)
2551
{
2552
  static const char FUNCTION_NAME[] = "tjDecompressToYUV2";
2553
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
2554
2555
  GET_DINSTANCE(handle);
2556
  if ((this->init & DECOMPRESS) == 0)
2557
    THROW("Instance has not been initialized for decompression");
2558
2559
  if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
2560
    THROW("Invalid argument");
2561
2562
  if (setjmp(this->jerr.setjmp_buffer)) {
2563
    /* If we get here, the JPEG code has signaled an error. */
2564
    retval = -1;  goto bailout;
2565
  }
2566
2567
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2568
  jpeg_read_header(dinfo, TRUE);
2569
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
2570
  if (width == 0) width = jpegwidth;
2571
  if (height == 0) height = jpegheight;
2572
  for (i = 0; i < NUMSF; i++) {
2573
    scaledw = TJSCALED(jpegwidth, sf[i]);
2574
    scaledh = TJSCALED(jpegheight, sf[i]);
2575
    if (scaledw <= width && scaledh <= height)
2576
      break;
2577
  }
2578
  if (i >= NUMSF)
2579
    THROW("Could not scale down to desired image dimensions");
2580
2581
  width = scaledw;  height = scaledh;
2582
2583
  processFlags(handle, flags, DECOMPRESS);
2584
2585
  if (tj3SetScalingFactor(handle, sf[i]) == -1)
2586
    return -1;
2587
  return tj3DecompressToYUV8(handle, jpegBuf, (size_t)jpegSize, dstBuf, align);
2588
2589
bailout:
2590
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2591
  if (this->jerr.warning) retval = -1;
2592
  return retval;
2593
}
2594
2595
/* TurboJPEG 1.1+ */
2596
DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
2597
                                unsigned long jpegSize, unsigned char *dstBuf,
2598
                                int flags)
2599
0
{
2600
0
  return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
2601
0
}
2602
2603
2604
/******************************** Transformer ********************************/
2605
2606
/* TurboJPEG 1.2+ */
2607
DLLEXPORT tjhandle tjInitTransform(void)
2608
{
2609
  return tj3Init(TJINIT_TRANSFORM);
2610
}
2611
2612
2613
/* TurboJPEG 3+ */
2614
DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
2615
                           size_t jpegSize, int n, unsigned char **dstBufs,
2616
                           size_t *dstSizes, const tjtransform *t)
2617
7.99k
{
2618
7.99k
  static const char FUNCTION_NAME[] = "tj3Transform";
2619
7.99k
  jpeg_transform_info *xinfo = NULL;
2620
7.99k
  jvirt_barray_ptr *srccoefs, *dstcoefs;
2621
7.99k
  int retval = 0, i, saveMarkers = 0;
2622
7.99k
  boolean alloc = TRUE;
2623
7.99k
  struct my_progress_mgr progress;
2624
2625
7.99k
  GET_INSTANCE(handle);
2626
7.99k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2627
7.99k
    THROW("Instance has not been initialized for transformation");
2628
2629
7.99k
  if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
2630
7.99k
      dstSizes == NULL || t == NULL)
2631
7.99k
    THROW("Invalid argument");
2632
2633
7.99k
  if (this->scanLimit) {
2634
7.99k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2635
7.99k
    progress.pub.progress_monitor = my_progress_monitor;
2636
7.99k
    progress.this = this;
2637
7.99k
    dinfo->progress = &progress.pub;
2638
7.99k
  } else
2639
0
    dinfo->progress = NULL;
2640
2641
7.99k
  if ((xinfo =
2642
7.99k
       (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
2643
7.99k
    THROW("Memory allocation failure");
2644
7.99k
  memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
2645
2646
7.99k
  if (setjmp(this->jerr.setjmp_buffer)) {
2647
    /* If we get here, the JPEG code has signaled an error. */
2648
4.04k
    retval = -1;  goto bailout;
2649
4.04k
  }
2650
2651
3.94k
  if (dinfo->global_state <= DSTATE_START)
2652
7.99k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2653
2654
19.9k
  for (i = 0; i < n; i++) {
2655
15.9k
    xinfo[i].transform = xformtypes[t[i].op];
2656
15.9k
    xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
2657
15.9k
    xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
2658
15.9k
    xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
2659
15.9k
    xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
2660
15.9k
    if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
2661
15.9k
    else xinfo[i].slow_hflip = 0;
2662
2663
15.9k
    if (xinfo[i].crop) {
2664
3.99k
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
2665
3.99k
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
2666
3.99k
      if (t[i].r.w != 0) {
2667
3.99k
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
2668
3.99k
      } else
2669
0
        xinfo[i].crop_width = JCROP_UNSET;
2670
3.99k
      if (t[i].r.h != 0) {
2671
3.99k
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
2672
3.99k
      } else
2673
0
        xinfo[i].crop_height = JCROP_UNSET;
2674
3.99k
    }
2675
15.9k
    if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
2676
15.9k
  }
2677
2678
18.4E
  jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
2679
3.94k
  if (dinfo->global_state <= DSTATE_START)
2680
7.99k
    jpeg_read_header(dinfo, TRUE);
2681
3.94k
  this->subsamp = getSubsamp(&this->dinfo);
2682
2683
18.2k
  for (i = 0; i < n; i++) {
2684
14.3k
    if (!jtransform_request_workspace(dinfo, &xinfo[i]))
2685
14.3k
      THROW("Transform is not perfect");
2686
2687
14.3k
    if (xinfo[i].crop) {
2688
2.40k
      if (this->subsamp == TJSAMP_UNKNOWN)
2689
2.34k
        THROW("Could not determine subsampling level of JPEG image");
2690
2.34k
      if ((t[i].r.x % tjMCUWidth[this->subsamp]) != 0 ||
2691
2.34k
          (t[i].r.y % tjMCUHeight[this->subsamp]) != 0)
2692
0
        THROWI("To crop this JPEG image, x must be a multiple of %d\n"
2693
2.34k
               "and y must be a multiple of %d.", tjMCUWidth[this->subsamp],
2694
2.34k
               tjMCUHeight[this->subsamp]);
2695
2.34k
    }
2696
14.3k
  }
2697
2698
3.88k
  srccoefs = jpeg_read_coefficients(dinfo);
2699
2700
11.4k
  for (i = 0; i < n; i++) {
2701
7.52k
    int w, h;
2702
2703
7.52k
    if (!xinfo[i].crop) {
2704
6.04k
      w = dinfo->image_width;  h = dinfo->image_height;
2705
6.04k
    } else {
2706
1.47k
      w = xinfo[i].crop_width;  h = xinfo[i].crop_height;
2707
1.47k
    }
2708
7.52k
    if (this->noRealloc) {
2709
4.55k
      alloc = FALSE;  dstSizes[i] = tj3JPEGBufSize(w, h, this->subsamp);
2710
4.55k
    }
2711
7.52k
    if (!(t[i].options & TJXOPT_NOOUTPUT))
2712
7.52k
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2713
7.52k
    jpeg_copy_critical_parameters(dinfo, cinfo);
2714
7.52k
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
2715
7.52k
    if (this->optimize || t[i].options & TJXOPT_OPTIMIZE)
2716
2.69k
      cinfo->optimize_coding = TRUE;
2717
7.52k
#ifdef C_PROGRESSIVE_SUPPORTED
2718
7.52k
    if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE)
2719
5.41k
      jpeg_simple_progression(cinfo);
2720
7.52k
#endif
2721
7.52k
    if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) {
2722
3.55k
      cinfo->arith_code = TRUE;
2723
3.55k
      cinfo->optimize_coding = FALSE;
2724
3.55k
    }
2725
7.52k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
2726
7.03k
      jpeg_write_coefficients(cinfo, dstcoefs);
2727
7.03k
      jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
2728
4.33k
                                          JCOPYOPT_NONE : JCOPYOPT_ALL);
2729
7.03k
    } else
2730
488
      jinit_c_master_control(cinfo, TRUE);
2731
7.52k
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
2732
7.52k
    if (t[i].customFilter) {
2733
0
      int ci, y;
2734
0
      JDIMENSION by;
2735
2736
0
      for (ci = 0; ci < cinfo->num_components; ci++) {
2737
0
        jpeg_component_info *compptr = &cinfo->comp_info[ci];
2738
0
        tjregion arrayRegion = { 0, 0, 0, 0 };
2739
0
        tjregion planeRegion = { 0, 0, 0, 0 };
2740
2741
0
        arrayRegion.w = compptr->width_in_blocks * DCTSIZE;
2742
0
        arrayRegion.h = DCTSIZE;
2743
0
        planeRegion.w = compptr->width_in_blocks * DCTSIZE;
2744
0
        planeRegion.h = compptr->height_in_blocks * DCTSIZE;
2745
2746
0
        for (by = 0; by < compptr->height_in_blocks;
2747
0
             by += compptr->v_samp_factor) {
2748
0
          JBLOCKARRAY barray = (dinfo->mem->access_virt_barray)
2749
0
            ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2750
0
             TRUE);
2751
2752
0
          for (y = 0; y < compptr->v_samp_factor; y++) {
2753
0
            if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
2754
0
                                  i, (tjtransform *)&t[i]) == -1)
2755
0
              THROW("Error in custom filter");
2756
0
            arrayRegion.y += DCTSIZE;
2757
0
          }
2758
0
        }
2759
0
      }
2760
0
    }
2761
7.52k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2762
7.52k
  }
2763
2764
3.88k
  jpeg_finish_decompress(dinfo);
2765
2766
7.99k
bailout:
2767
7.99k
  if (cinfo->global_state > CSTATE_START) {
2768
274
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
2769
274
    jpeg_abort_compress(cinfo);
2770
274
  }
2771
7.99k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2772
7.99k
  free(xinfo);
2773
7.99k
  if (this->jerr.warning) retval = -1;
2774
7.99k
  return retval;
2775
3.88k
}
2776
2777
/* TurboJPEG 1.2+ */
2778
DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
2779
                          unsigned long jpegSize, int n,
2780
                          unsigned char **dstBufs, unsigned long *dstSizes,
2781
                          tjtransform *t, int flags)
2782
{
2783
  static const char FUNCTION_NAME[] = "tjTransform";
2784
  int i, retval = 0;
2785
  size_t *sizes = NULL;
2786
2787
  GET_DINSTANCE(handle);
2788
  if ((this->init & DECOMPRESS) == 0)
2789
    THROW("Instance has not been initialized for decompression");
2790
2791
  if (n < 1 || dstSizes == NULL)
2792
    THROW("Invalid argument");
2793
2794
  if (setjmp(this->jerr.setjmp_buffer)) {
2795
    /* If we get here, the JPEG code has signaled an error. */
2796
    retval = -1;  goto bailout;
2797
  }
2798
2799
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2800
  jpeg_read_header(dinfo, TRUE);
2801
  if (getSubsamp(dinfo) == TJSAMP_UNKNOWN)
2802
    THROW("Could not determine subsampling level of JPEG image");
2803
  processFlags(handle, flags, COMPRESS);
2804
2805
  if ((sizes = (size_t *)malloc(n * sizeof(size_t))) == NULL)
2806
    THROW("Memory allocation failure");
2807
  for (i = 0; i < n; i++)
2808
    sizes[i] = (size_t)dstSizes[i];
2809
  retval = tj3Transform(handle, jpegBuf, (size_t)jpegSize, n, dstBufs, sizes,
2810
                        t);
2811
  for (i = 0; i < n; i++)
2812
    dstSizes[i] = (unsigned long)sizes[i];
2813
2814
bailout:
2815
  free(sizes);
2816
  return retval;
2817
}
2818
2819
2820
/*************************** Packed-Pixel Image I/O **************************/
2821
2822
/* tj3LoadImage*() is implemented in turbojpeg-mp.c */
2823
2824
/* TurboJPEG 2.0+ */
2825
DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
2826
                                     int align, int *height,
2827
                                     int *pixelFormat, int flags)
2828
{
2829
  tjhandle handle = NULL;
2830
  unsigned char *dstBuf = NULL;
2831
2832
  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) return NULL;
2833
2834
  processFlags(handle, flags, COMPRESS);
2835
2836
  dstBuf = tj3LoadImage8(handle, filename, width, align, height, pixelFormat);
2837
2838
  tj3Destroy(handle);
2839
  return dstBuf;
2840
}
2841
2842
2843
/* tj3SaveImage*() is implemented in turbojpeg-mp.c */
2844
2845
/* TurboJPEG 2.0+ */
2846
DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
2847
                          int width, int pitch, int height, int pixelFormat,
2848
                          int flags)
2849
0
{
2850
0
  tjhandle handle = NULL;
2851
0
  int retval = -1;
2852
2853
0
  if ((handle = tj3Init(TJINIT_DECOMPRESS)) == NULL) return -1;
2854
2855
0
  processFlags(handle, flags, DECOMPRESS);
2856
2857
0
  retval = tj3SaveImage8(handle, filename, buffer, width, pitch, height,
2858
0
                         pixelFormat);
2859
2860
0
  tj3Destroy(handle);
2861
0
  return retval;
2862
0
}