Coverage Report

Created: 2026-08-31 07:19

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