Coverage Report

Created: 2026-10-28 06:08

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