Coverage Report

Created: 2026-05-11 07:55

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