Coverage Report

Created: 2026-04-12 06:05

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.65M
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
58
320k
#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
400k
{
82
400k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
83
84
400k
  (*cinfo->err->output_message) (cinfo);
85
400k
  longjmp(myerr->setjmp_buffer, 1);
86
400k
}
87
88
static void my_emit_message(j_common_ptr cinfo, int msg_level)
89
885M
{
90
885M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
91
92
885M
  myerr->emit_message(cinfo, msg_level);
93
885M
  if (msg_level < 0) {
94
576M
    myerr->warning = TRUE;
95
576M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
96
576M
  }
97
885M
}
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
275k
{
150
275k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
151
275k
  tjinstance *this = (tjinstance *)myerr->tjHandle;
152
153
275k
  if (this) {
154
275k
    this->isInstanceError = TRUE;
155
275k
    (*cinfo->err->format_message) (cinfo, this->errStr);
156
275k
  } else
157
0
    (*cinfo->err->format_message) (cinfo, errStr);
158
275k
}
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
1.19G
{
168
1.19G
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
169
1.19G
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
170
171
1.19G
  if (dinfo->is_decompressor) {
172
1.19G
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
173
174
1.19G
    if (scan_no > myprog->this->scanLimit) {
175
3.99k
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
176
3.99k
               "Progressive JPEG image has more than %d scans",
177
3.99k
               myprog->this->scanLimit);
178
3.99k
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
179
3.99k
               "Progressive JPEG image has more than %d scans",
180
3.99k
               myprog->this->scanLimit);
181
3.99k
      myprog->this->isInstanceError = TRUE;
182
3.99k
      myerr->warning = FALSE;
183
3.99k
      longjmp(myerr->setjmp_buffer, 1);
184
3.99k
    }
185
1.19G
  }
186
1.19G
}
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.08M
#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.56k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME, m); \
281
4.56k
  this->isInstanceError = TRUE;  THROWG(m, rv) \
282
4.56k
}
283
4.56k
#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
796k
#define CATCH_LIBJPEG(this) { \
294
796k
  if (setjmp(this->jerr.setjmp_buffer)) { \
295
117k
    /* If we get here, the JPEG code has signaled an error. */ \
296
117k
    retval = -1;  goto bailout; \
297
117k
  } \
298
796k
}
299
300
#define GET_INSTANCE(handle) \
301
30.9k
  tjinstance *this = (tjinstance *)handle; \
302
30.9k
  j_compress_ptr cinfo = NULL; \
303
30.9k
  j_decompress_ptr dinfo = NULL; \
304
30.9k
  \
305
30.9k
  if (!this) { \
306
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
307
0
    return -1; \
308
0
  } \
309
30.9k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
310
30.9k
  this->jerr.warning = FALSE; \
311
30.9k
  this->isInstanceError = FALSE;
312
313
#define GET_CINSTANCE(handle) \
314
195k
  tjinstance *this = (tjinstance *)handle; \
315
195k
  j_compress_ptr cinfo = NULL; \
316
195k
  \
317
195k
  if (!this) { \
318
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
319
0
    return -1; \
320
0
  } \
321
195k
  cinfo = &this->cinfo; \
322
195k
  this->jerr.warning = FALSE; \
323
195k
  this->isInstanceError = FALSE;
324
325
#define GET_DINSTANCE(handle) \
326
144k
  tjinstance *this = (tjinstance *)handle; \
327
144k
  j_decompress_ptr dinfo = NULL; \
328
144k
  \
329
144k
  if (!this) { \
330
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
331
0
    return -1; \
332
0
  } \
333
144k
  dinfo = &this->dinfo; \
334
144k
  this->jerr.warning = FALSE; \
335
144k
  this->isInstanceError = FALSE;
336
337
#define GET_TJINSTANCE(handle, errorReturn) \
338
2.57M
  tjinstance *this = (tjinstance *)handle; \
339
2.57M
  \
340
2.57M
  if (!this) { \
341
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
342
0
    return errorReturn; \
343
0
  } \
344
2.57M
  this->jerr.warning = FALSE; \
345
2.57M
  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
247k
{
368
247k
  int colorspace = yuv ? TJCS_DEFAULT : this->colorspace;
369
370
247k
  this->cinfo.in_color_space = pf2cs[pixelFormat];
371
247k
  this->cinfo.input_components = tjPixelSize[pixelFormat];
372
247k
  jpeg_set_defaults(&this->cinfo);
373
374
247k
  this->cinfo.restart_interval = this->restartIntervalBlocks;
375
247k
  this->cinfo.restart_in_rows = this->restartIntervalRows;
376
247k
  this->cinfo.X_density = (UINT16)this->xDensity;
377
247k
  this->cinfo.Y_density = (UINT16)this->yDensity;
378
247k
  this->cinfo.density_unit = (UINT8)this->densityUnits;
379
247k
  this->cinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
380
381
247k
  if (this->lossless && !yuv) {
382
77.5k
#ifdef C_LOSSLESS_SUPPORTED
383
77.5k
    jpeg_enable_lossless(&this->cinfo, this->losslessPSV, this->losslessPt);
384
77.5k
#endif
385
77.5k
    return;
386
77.5k
  }
387
388
169k
  jpeg_set_quality(&this->cinfo, this->quality, TRUE);
389
169k
  this->cinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
390
391
169k
  switch (colorspace) {
392
10.0k
  case TJCS_RGB:
393
10.0k
    jpeg_set_colorspace(&this->cinfo, JCS_RGB);  break;
394
17.5k
  case TJCS_YCbCr:
395
17.5k
    jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);  break;
396
13.5k
  case TJCS_GRAY:
397
13.5k
    jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);  break;
398
0
  case TJCS_CMYK:
399
0
    jpeg_set_colorspace(&this->cinfo, JCS_CMYK);  break;
400
9.72k
  case TJCS_YCCK:
401
9.72k
    jpeg_set_colorspace(&this->cinfo, JCS_YCCK);  break;
402
118k
  default:
403
118k
    if (this->subsamp == TJSAMP_GRAY)
404
38.4k
      jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);
405
80.2k
    else if (pixelFormat == TJPF_CMYK)
406
4.00k
      jpeg_set_colorspace(&this->cinfo, JCS_YCCK);
407
76.2k
    else
408
76.2k
      jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);
409
169k
  }
410
411
169k
  if (this->cinfo.data_precision == 8)
412
123k
    this->cinfo.optimize_coding = this->optimize;
413
169k
#ifdef C_PROGRESSIVE_SUPPORTED
414
169k
  if (this->progressive) jpeg_simple_progression(&this->cinfo);
415
169k
#endif
416
169k
  this->cinfo.arith_code = this->arithmetic;
417
418
169k
  this->cinfo.comp_info[0].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
419
169k
  this->cinfo.comp_info[1].h_samp_factor = 1;
420
169k
  this->cinfo.comp_info[2].h_samp_factor = 1;
421
169k
  if (this->cinfo.num_components > 3)
422
13.7k
    this->cinfo.comp_info[3].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
423
169k
  this->cinfo.comp_info[0].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
424
169k
  this->cinfo.comp_info[1].v_samp_factor = 1;
425
169k
  this->cinfo.comp_info[2].v_samp_factor = 1;
426
169k
  if (this->cinfo.num_components > 3)
427
13.7k
    this->cinfo.comp_info[3].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
428
169k
}
429
430
431
static int getSubsamp(tjinstance *this)
432
264k
{
433
264k
  int retval = TJSAMP_UNKNOWN, i, k;
434
264k
  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
264k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
441
111k
    return TJSAMP_GRAY;
442
443
833k
  for (i = 0; i < this->numSamp; i++) {
444
769k
    if (i == TJSAMP_GRAY) continue;
445
446
691k
    if (dinfo->num_components == 3 ||
447
73.8k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
448
66.7k
          dinfo->jpeg_color_space == JCS_CMYK) &&
449
681k
         dinfo->num_components == 4)) {
450
681k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
451
292k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
452
137k
        int match = 0;
453
454
421k
        for (k = 1; k < dinfo->num_components; k++) {
455
284k
          int href = 1, vref = 1;
456
457
284k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
458
280k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
459
9.48k
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
460
9.48k
          }
461
284k
          if (dinfo->comp_info[k].h_samp_factor == href &&
462
245k
              dinfo->comp_info[k].v_samp_factor == vref)
463
200k
            match++;
464
284k
        }
465
137k
        if (match == dinfo->num_components - 1) {
466
83.3k
          retval = i;  break;
467
83.3k
        }
468
137k
      }
469
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
470
         in non-standard ways. */
471
598k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
472
352k
          dinfo->comp_info[0].v_samp_factor == 2 &&
473
167k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
474
74.8k
        int match = 0;
475
476
226k
        for (k = 1; k < dinfo->num_components; k++) {
477
151k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
478
479
151k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
480
150k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
481
1.85k
            href = vref = 2;
482
1.85k
          }
483
151k
          if (dinfo->comp_info[k].h_samp_factor == href &&
484
129k
              dinfo->comp_info[k].v_samp_factor == vref)
485
13.5k
            match++;
486
151k
        }
487
74.8k
        if (match == dinfo->num_components - 1) {
488
4.75k
          retval = i;  break;
489
4.75k
        }
490
74.8k
      }
491
      /* Handle 4:4:4 images whose sampling factors are specified in
492
         non-standard ways. */
493
593k
      if (dinfo->comp_info[0].h_samp_factor *
494
593k
          dinfo->comp_info[0].v_samp_factor <=
495
593k
          D_MAX_BLOCKS_IN_MCU / 3 && i == TJSAMP_444) {
496
55.6k
        int match = 0;
497
171k
        for (k = 1; k < dinfo->num_components; k++) {
498
117k
          if (dinfo->comp_info[k].h_samp_factor ==
499
117k
              dinfo->comp_info[0].h_samp_factor &&
500
28.7k
              dinfo->comp_info[k].v_samp_factor ==
501
28.7k
              dinfo->comp_info[0].v_samp_factor)
502
10.0k
            match++;
503
117k
          if (match == dinfo->num_components - 1) {
504
2.06k
            retval = i;  break;
505
2.06k
          }
506
117k
        }
507
55.6k
      }
508
593k
    }
509
691k
  }
510
152k
  return retval;
511
264k
}
512
513
514
static void setDecompParameters(tjinstance *this)
515
216k
{
516
216k
  this->subsamp = getSubsamp(this);
517
216k
  this->jpegWidth = this->dinfo.image_width;
518
216k
  this->jpegHeight = this->dinfo.image_height;
519
216k
  this->precision = this->dinfo.data_precision;
520
216k
  switch (this->dinfo.jpeg_color_space) {
521
86.1k
  case JCS_GRAYSCALE:  this->colorspace = TJCS_GRAY;  break;
522
48.7k
  case JCS_RGB:        this->colorspace = TJCS_RGB;  break;
523
73.9k
  case JCS_YCbCr:      this->colorspace = TJCS_YCbCr;  break;
524
6.33k
  case JCS_CMYK:       this->colorspace = TJCS_CMYK;  break;
525
1.03k
  case JCS_YCCK:       this->colorspace = TJCS_YCCK;  break;
526
568
  default:             this->colorspace = TJCS_DEFAULT;  break;
527
216k
  }
528
216k
  this->progressive = this->dinfo.progressive_mode;
529
216k
  this->arithmetic = this->dinfo.arith_code;
530
216k
  this->lossless = this->dinfo.master->lossless;
531
216k
  this->losslessPSV = this->dinfo.Ss;
532
216k
  this->losslessPt = this->dinfo.Al;
533
216k
  this->xDensity = this->dinfo.X_density;
534
216k
  this->yDensity = this->dinfo.Y_density;
535
216k
  this->densityUnits = this->dinfo.density_unit;
536
216k
}
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
276k
{
585
276k
  static const char FUNCTION_NAME[] = "tj3Init";
586
276k
  tjinstance *this = NULL;
587
276k
  tjhandle retval = NULL;
588
589
276k
  if (initType < 0 || initType >= TJ_NUMINIT || apiVersion < 1000000 ||
590
276k
      apiVersion > 999999999)
591
276k
    THROWG("Invalid argument", NULL);
592
593
276k
  if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL)
594
276k
    THROWG("Memory allocation failure", NULL);
595
276k
  memset(this, 0, sizeof(tjinstance));
596
276k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
597
598
276k
  this->quality = -1;
599
276k
  this->subsamp = TJSAMP_UNKNOWN;
600
276k
  this->jpegWidth = -1;
601
276k
  this->jpegHeight = -1;
602
276k
  this->precision = 8;
603
276k
  this->colorspace = TJCS_DEFAULT;
604
276k
  this->losslessPSV = 1;
605
276k
  this->xDensity = 1;
606
276k
  this->yDensity = 1;
607
276k
  this->scalingFactor = TJUNSCALED;
608
276k
  this->saveMarkers = 2;
609
610
276k
  this->apiVersion = apiVersion;
611
276k
  this->numSamp = apiVersion >= 3002000 ? TJ_NUMSAMP : 7;
612
613
276k
  switch (initType) {
614
256k
  case TJINIT_COMPRESS:  return _tjInitCompress(this);
615
13.5k
  case TJINIT_DECOMPRESS:  return _tjInitDecompress(this);
616
5.93k
  case TJINIT_TRANSFORM:
617
5.93k
    retval = _tjInitCompress(this);
618
5.93k
    if (!retval) return NULL;
619
5.93k
    retval = _tjInitDecompress(this);
620
5.93k
    return retval;
621
276k
  }
622
623
0
bailout:
624
0
  return retval;
625
276k
}
626
627
/* TurboJPEG 3.0+ */
628
DLLEXPORT tjhandle tj3Init(int initType)
629
223k
{
630
223k
  return tj3InitVersion(initType, 3001000);
631
223k
}
632
633
634
/* TurboJPEG 3.0+ */
635
DLLEXPORT void tj3Destroy(tjhandle handle)
636
559k
{
637
559k
  tjinstance *this = (tjinstance *)handle;
638
559k
  j_compress_ptr cinfo = NULL;
639
559k
  j_decompress_ptr dinfo = NULL;
640
641
559k
  if (!this) return;
642
643
559k
  cinfo = &this->cinfo;  dinfo = &this->dinfo;
644
559k
  this->jerr.warning = FALSE;
645
559k
  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
559k
  if (setjmp(this->jerr.setjmp_buffer)) goto destroy_decompress;
650
559k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
651
559k
destroy_decompress:
652
559k
  if (setjmp(this->jerr.setjmp_buffer)) goto bailout;
653
559k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
654
559k
bailout:
655
559k
  free(this->iccBuf);
656
559k
  free(this->decompICCBuf);
657
559k
  free(this);
658
559k
}
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
169k
{
680
169k
  tjinstance *this = (tjinstance *)handle;
681
682
169k
  if (this && this->isInstanceError) {
683
63.9k
    this->isInstanceError = FALSE;
684
63.9k
    return this->errStr;
685
63.9k
  } else
686
105k
    return errStr;
687
169k
}
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
905k
#define SET_PARAM(field, minValue, maxValue) { \
719
905k
  if (value < minValue || (maxValue > 0 && value > maxValue)) \
720
905k
    THROW("Parameter value out of range"); \
721
905k
  this->field = value; \
722
905k
}
723
724
1.06M
#define SET_BOOL_PARAM(field) { \
725
1.06M
  if (value < 0 || value > 1) \
726
1.06M
    THROW("Parameter value out of range"); \
727
1.06M
  this->field = (boolean)value; \
728
1.06M
}
729
730
/* TurboJPEG 3.0+ */
731
DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
732
1.97M
{
733
1.97M
  static const char FUNCTION_NAME[] = "tj3Set";
734
1.97M
  int retval = 0;
735
736
1.97M
  GET_TJINSTANCE(handle, -1);
737
738
1.97M
  switch (param) {
739
0
  case TJPARAM_STOPONWARNING:
740
0
    SET_BOOL_PARAM(jerr.stopOnWarning);
741
0
    break;
742
266k
  case TJPARAM_BOTTOMUP:
743
266k
    SET_BOOL_PARAM(bottomUp);
744
266k
    break;
745
232k
  case TJPARAM_NOREALLOC:
746
232k
    if (!(this->init & COMPRESS))
747
232k
      THROW("TJPARAM_NOREALLOC is not applicable to decompression instances.");
748
232k
    SET_BOOL_PARAM(noRealloc);
749
232k
    break;
750
60.0k
  case TJPARAM_QUALITY:
751
60.0k
    if (!(this->init & COMPRESS))
752
60.0k
      THROW("TJPARAM_QUALITY is not applicable to decompression instances.");
753
60.0k
    SET_PARAM(quality, 1, 100);
754
60.0k
    break;
755
60.0k
  case TJPARAM_SUBSAMP:
756
60.0k
    SET_PARAM(subsamp, 0, this->numSamp - 1);
757
60.0k
    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
107k
  case TJPARAM_PRECISION:
769
107k
    SET_PARAM(precision, 2, 16);
770
107k
    break;
771
82.2k
  case TJPARAM_COLORSPACE:
772
82.2k
    if (!(this->init & COMPRESS))
773
82.2k
      THROW("TJPARAM_COLORSPACE is read-only in decompression instances.");
774
82.2k
    SET_PARAM(colorspace, TJCS_DEFAULT, TJ_NUMCS - 1);
775
82.2k
    break;
776
42.1k
  case TJPARAM_FASTUPSAMPLE:
777
42.1k
    if (!(this->init & DECOMPRESS))
778
42.1k
      THROW("TJPARAM_FASTUPSAMPLE is not applicable to compression instances.");
779
42.1k
    SET_BOOL_PARAM(fastUpsample);
780
42.1k
    break;
781
150k
  case TJPARAM_FASTDCT:
782
150k
    SET_BOOL_PARAM(fastDCT);
783
150k
    break;
784
83.5k
  case TJPARAM_OPTIMIZE:
785
83.5k
    if (!(this->init & COMPRESS))
786
83.5k
      THROW("TJPARAM_OPTIMIZE is not applicable to decompression instances.");
787
83.5k
    SET_BOOL_PARAM(optimize);
788
83.5k
    break;
789
121k
  case TJPARAM_PROGRESSIVE:
790
121k
    if (!(this->init & COMPRESS))
791
121k
      THROW("TJPARAM_PROGRESSIVE is read-only in decompression instances.");
792
121k
    SET_BOOL_PARAM(progressive);
793
121k
    break;
794
51.5k
  case TJPARAM_SCANLIMIT:
795
51.5k
    if (!(this->init & DECOMPRESS))
796
51.5k
      THROW("TJPARAM_SCANLIMIT is not applicable to compression instances.");
797
51.5k
    SET_PARAM(scanLimit, 0, -1);
798
51.5k
    break;
799
121k
  case TJPARAM_ARITHMETIC:
800
121k
    if (!(this->init & COMPRESS))
801
121k
      THROW("TJPARAM_ARITHMETIC is read-only in decompression instances.");
802
121k
    SET_BOOL_PARAM(arithmetic);
803
121k
    break;
804
47.8k
  case TJPARAM_LOSSLESS:
805
47.8k
    if (!(this->init & COMPRESS))
806
47.8k
      THROW("TJPARAM_LOSSLESS is read-only in decompression instances.");
807
47.8k
    SET_BOOL_PARAM(lossless);
808
47.8k
    break;
809
47.8k
  case TJPARAM_LOSSLESSPSV:
810
47.8k
    if (!(this->init & COMPRESS))
811
47.8k
      THROW("TJPARAM_LOSSLESSPSV is read-only in decompression instances.");
812
47.8k
    SET_PARAM(losslessPSV, 1, 7);
813
47.8k
    break;
814
47.8k
  case TJPARAM_LOSSLESSPT:
815
47.8k
    if (!(this->init & COMPRESS))
816
47.8k
      THROW("TJPARAM_LOSSLESSPT is read-only in decompression instances.");
817
47.8k
    SET_PARAM(losslessPt, 0, 15);
818
47.8k
    break;
819
33.7k
  case TJPARAM_RESTARTBLOCKS:
820
33.7k
    if (!(this->init & COMPRESS))
821
33.7k
      THROW("TJPARAM_RESTARTBLOCKS is not applicable to decompression instances.");
822
33.7k
    SET_PARAM(restartIntervalBlocks, 0, 65535);
823
33.7k
    if (value != 0) this->restartIntervalRows = 0;
824
33.7k
    break;
825
190k
  case TJPARAM_RESTARTROWS:
826
190k
    if (!(this->init & COMPRESS))
827
190k
      THROW("TJPARAM_RESTARTROWS is not applicable to decompression instances.");
828
190k
    SET_PARAM(restartIntervalRows, 0, 65535);
829
190k
    if (value != 0) this->restartIntervalBlocks = 0;
830
190k
    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
223k
  case TJPARAM_MAXPIXELS:
850
223k
    SET_PARAM(maxPixels, 0, -1);
851
223k
    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
1.97M
  }
858
859
1.97M
bailout:
860
1.97M
  return retval;
861
1.97M
}
862
863
864
/* TurboJPEG 3.0+ */
865
DLLEXPORT int tj3Get(tjhandle handle, int param)
866
335k
{
867
335k
  tjinstance *this = (tjinstance *)handle;
868
335k
  if (!this) return -1;
869
870
335k
  switch (param) {
871
0
  case TJPARAM_STOPONWARNING:
872
0
    return this->jerr.stopOnWarning;
873
0
  case TJPARAM_BOTTOMUP:
874
0
    return this->bottomUp;
875
135k
  case TJPARAM_NOREALLOC:
876
135k
    return this->noRealloc;
877
0
  case TJPARAM_QUALITY:
878
0
    return this->quality;
879
22.5k
  case TJPARAM_SUBSAMP:
880
22.5k
    return this->subsamp;
881
36.6k
  case TJPARAM_JPEGWIDTH:
882
36.6k
    return this->jpegWidth;
883
36.6k
  case TJPARAM_JPEGHEIGHT:
884
36.6k
    return this->jpegHeight;
885
14.1k
  case TJPARAM_PRECISION:
886
14.1k
    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
89.9k
  case TJPARAM_LOSSLESS:
902
89.9k
    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
335k
  }
924
925
0
  return -1;
926
335k
}
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
401k
{
937
401k
  return MALLOC(bytes);
938
401k
}
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
845k
{
950
845k
  free(buf);
951
845k
}
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
311k
{
963
311k
  static const char FUNCTION_NAME[] = "tj3JPEGBufSize";
964
311k
  unsigned long long retval = 0;
965
311k
  int mcuw, mcuh, chromasf;
966
967
311k
  if (width < 1 || height < 1 || jpegSubsamp < TJSAMP_UNKNOWN ||
968
311k
      jpegSubsamp >= TJ_NUMSAMP)
969
311k
    THROWG("Invalid argument", 0);
970
971
311k
  if (jpegSubsamp == TJSAMP_UNKNOWN)
972
16.5k
    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
311k
  mcuw = tjMCUWidth[jpegSubsamp];
978
311k
  mcuh = tjMCUHeight[jpegSubsamp];
979
311k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
980
311k
  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
311k
bailout:
987
311k
  return (size_t)retval;
988
311k
}
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
81.4k
{
1031
81.4k
  static const char FUNCTION_NAME[] = "tj3YUVBufSize";
1032
81.4k
  unsigned long long retval = 0;
1033
81.4k
  int nc, i;
1034
1035
81.4k
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1036
80.8k
    THROWG("Invalid argument", 0);
1037
1038
80.8k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1039
265k
  for (i = 0; i < nc; i++) {
1040
185k
    int pw = tj3YUVPlaneWidth(i, width, subsamp);
1041
185k
    int stride = PAD(pw, align);
1042
185k
    int ph = tj3YUVPlaneHeight(i, height, subsamp);
1043
1044
185k
    if (pw == 0 || ph == 0) return 0;
1045
185k
    else retval += (unsigned long long)stride * ph;
1046
185k
  }
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
81.4k
bailout:
1053
81.4k
  return (size_t)retval;
1054
80.8k
}
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
482k
{
1117
482k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneWidth";
1118
482k
  unsigned long long pw, retval = 0;
1119
482k
  int nc;
1120
1121
482k
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1122
482k
    THROWG("Invalid argument", 0);
1123
482k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1124
482k
  if (componentID < 0 || componentID >= nc)
1125
482k
    THROWG("Invalid argument", 0);
1126
1127
482k
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
1128
482k
  if (componentID == 0)
1129
244k
    retval = pw;
1130
237k
  else
1131
237k
    retval = pw * 8 / tjMCUWidth[subsamp];
1132
1133
482k
  if (retval > (unsigned long long)INT_MAX)
1134
482k
    THROWG("Width is too large", 0);
1135
1136
482k
bailout:
1137
482k
  return (int)retval;
1138
482k
}
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
482k
{
1151
482k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneHeight";
1152
482k
  unsigned long long ph, retval = 0;
1153
482k
  int nc;
1154
1155
482k
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1156
482k
    THROWG("Invalid argument", 0);
1157
482k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1158
482k
  if (componentID < 0 || componentID >= nc)
1159
482k
    THROWG("Invalid argument", 0);
1160
1161
482k
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
1162
482k
  if (componentID == 0)
1163
244k
    retval = ph;
1164
237k
  else
1165
237k
    retval = ph * 8 / tjMCUHeight[subsamp];
1166
1167
482k
  if (retval > (unsigned long long)INT_MAX)
1168
482k
    THROWG("Height is too large", 0);
1169
1170
482k
bailout:
1171
482k
  return (int)retval;
1172
482k
}
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
520k
{
1186
520k
  static unsigned char buffer[1];
1187
520k
  unsigned char *buf = buffer;
1188
520k
  size_t size = 1;
1189
1190
  /* This is also straight out of example.c */
1191
520k
  this->cinfo.err = jpeg_std_error(&this->jerr.pub);
1192
520k
  this->jerr.pub.error_exit = my_error_exit;
1193
520k
  this->jerr.pub.output_message = my_output_message;
1194
520k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1195
520k
  this->jerr.pub.emit_message = my_emit_message;
1196
520k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1197
520k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1198
520k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1199
520k
  this->jerr.tjHandle = (tjhandle)this;
1200
1201
520k
  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
520k
  jpeg_create_compress(&this->cinfo);
1208
  /* Make an initial call so it will create the destination manager */
1209
520k
  jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
1210
1211
520k
  this->init |= COMPRESS;
1212
520k
  return (tjhandle)this;
1213
520k
}
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
125k
{
1226
125k
  static const char FUNCTION_NAME[] = "tj3SetICCProfile";
1227
125k
  int retval = 0;
1228
1229
125k
  GET_TJINSTANCE(handle, -1)
1230
125k
  if ((this->init & COMPRESS) == 0)
1231
125k
    THROW("Instance has not been initialized for compression");
1232
1233
125k
  if (iccBuf == this->iccBuf && iccSize == this->iccSize)
1234
0
    return 0;
1235
1236
125k
  free(this->iccBuf);
1237
125k
  this->iccBuf = NULL;
1238
125k
  this->iccSize = 0;
1239
125k
  if (iccBuf && iccSize) {
1240
125k
    if ((this->iccBuf = (unsigned char *)malloc(iccSize)) == NULL)
1241
125k
      THROW("Memory allocation failure");
1242
125k
    memcpy(this->iccBuf, iccBuf, iccSize);
1243
125k
    this->iccSize = iccSize;
1244
125k
  }
1245
1246
125k
bailout:
1247
125k
  return retval;
1248
125k
}
1249
1250
1251
/* tj3Compress*() is implemented in turbojpeg-mp.c */
1252
306k
#define BITS_IN_JSAMPLE  8
1253
#include "turbojpeg-mp.c"
1254
#undef BITS_IN_JSAMPLE
1255
270k
#define BITS_IN_JSAMPLE  12
1256
#include "turbojpeg-mp.c"
1257
#undef BITS_IN_JSAMPLE
1258
155k
#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.6k
{
1324
24.6k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUVPlanes8";
1325
24.6k
  int i, row, retval = 0;
1326
24.6k
  boolean alloc = TRUE;
1327
24.6k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1328
24.6k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1329
24.6k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1330
24.6k
  JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1331
1332
24.6k
  GET_CINSTANCE(handle)
1333
1334
271k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1335
246k
    tmpbuf[i] = NULL;  inbuf[i] = NULL;
1336
246k
  }
1337
1338
24.6k
  if ((this->init & COMPRESS) == 0)
1339
24.6k
    THROW("Instance has not been initialized for compression");
1340
1341
24.6k
  if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
1342
24.6k
      jpegBuf == NULL || jpegSize == NULL)
1343
24.6k
    THROW("Invalid argument");
1344
24.6k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1345
24.6k
    THROW("Invalid argument");
1346
1347
24.6k
  if (this->quality == -1)
1348
24.6k
    THROW("TJPARAM_QUALITY must be specified");
1349
24.6k
  if (this->subsamp == TJSAMP_UNKNOWN)
1350
24.6k
    THROW("TJPARAM_SUBSAMP must be specified");
1351
1352
24.6k
  CATCH_LIBJPEG(this);
1353
1354
24.6k
  cinfo->image_width = width;
1355
24.6k
  cinfo->image_height = height;
1356
24.6k
  cinfo->data_precision = 8;
1357
1358
24.6k
  if (this->noRealloc) alloc = FALSE;
1359
24.6k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1360
24.6k
  setCompDefaults(this, TJPF_RGB, TRUE);
1361
24.6k
  cinfo->raw_data_in = TRUE;
1362
1363
24.6k
  jpeg_start_compress(cinfo, TRUE);
1364
24.6k
  if (this->iccBuf != NULL && this->iccSize != 0)
1365
78
    jpeg_write_icc_profile(cinfo, this->iccBuf, (unsigned int)this->iccSize);
1366
81.9k
  for (i = 0; i < cinfo->num_components; i++) {
1367
57.3k
    jpeg_component_info *compptr = &cinfo->comp_info[i];
1368
57.3k
    int ih;
1369
1370
57.3k
    iw[i] = compptr->width_in_blocks * DCTSIZE;
1371
57.3k
    ih = compptr->height_in_blocks * DCTSIZE;
1372
57.3k
    pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
1373
57.3k
            compptr->h_samp_factor / cinfo->max_h_samp_factor;
1374
57.3k
    ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
1375
57.3k
            compptr->v_samp_factor / cinfo->max_v_samp_factor;
1376
57.3k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1377
57.3k
    th[i] = compptr->v_samp_factor * DCTSIZE;
1378
57.3k
    tmpbufsize += iw[i] * th[i];
1379
57.3k
    if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1380
57.3k
      THROW("Memory allocation failure");
1381
57.3k
    ptr = (JSAMPLE *)srcPlanes[i];
1382
113M
    for (row = 0; row < ph[i]; row++) {
1383
113M
      inbuf[i][row] = ptr;
1384
113M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1385
113M
    }
1386
57.3k
  }
1387
24.6k
  if (usetmpbuf) {
1388
18.6k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1389
18.6k
      THROW("Memory allocation failure");
1390
18.6k
    ptr = _tmpbuf;
1391
62.5k
    for (i = 0; i < cinfo->num_components; i++) {
1392
43.9k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1393
43.9k
        THROW("Memory allocation failure");
1394
421k
      for (row = 0; row < th[i]; row++) {
1395
377k
        tmpbuf[i][row] = ptr;
1396
377k
        ptr += iw[i];
1397
377k
      }
1398
43.9k
    }
1399
18.6k
  }
1400
1401
24.6k
  CATCH_LIBJPEG(this);
1402
1403
6.00M
  for (row = 0; row < (int)cinfo->image_height;
1404
5.97M
       row += cinfo->max_v_samp_factor * DCTSIZE) {
1405
5.97M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1406
5.97M
    int crow[MAX_COMPONENTS];
1407
1408
19.6M
    for (i = 0; i < cinfo->num_components; i++) {
1409
13.6M
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1410
1411
13.6M
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1412
13.6M
      if (usetmpbuf) {
1413
13.6M
        int j, k;
1414
1415
126M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1416
113M
          memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1417
          /* Duplicate last sample in row to fill out MCU */
1418
852M
          for (k = pw[i]; k < iw[i]; k++)
1419
739M
            tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1420
113M
        }
1421
        /* Duplicate last row to fill out MCU */
1422
13.8M
        for (j = ph[i] - crow[i]; j < th[i]; j++)
1423
230k
          memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1424
13.6M
        yuvptr[i] = tmpbuf[i];
1425
13.6M
      } else
1426
28.7k
        yuvptr[i] = &inbuf[i][crow[i]];
1427
13.6M
    }
1428
5.97M
    jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1429
5.97M
  }
1430
24.6k
  jpeg_finish_compress(cinfo);
1431
1432
24.6k
bailout:
1433
24.6k
  if (cinfo->global_state > CSTATE_START && alloc)
1434
0
    (*cinfo->dest->term_destination) (cinfo);
1435
24.6k
  if (cinfo->global_state > CSTATE_START || retval == -1)
1436
0
    jpeg_abort_compress(cinfo);
1437
271k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1438
246k
    free(tmpbuf[i]);
1439
246k
    free(inbuf[i]);
1440
246k
  }
1441
24.6k
  free(_tmpbuf);
1442
24.6k
  if (this->jerr.warning) retval = -1;
1443
24.6k
  return retval;
1444
24.6k
}
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
35.8k
{
1487
35.8k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUV8";
1488
35.8k
  const unsigned char *srcPlanes[3];
1489
35.8k
  int pw0, ph0, strides[3], retval = -1;
1490
1491
35.8k
  GET_TJINSTANCE(handle, -1);
1492
1493
35.8k
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1494
35.8k
      height <= 0)
1495
35.8k
    THROW("Invalid argument");
1496
1497
35.8k
  if (this->subsamp == TJSAMP_UNKNOWN)
1498
35.8k
    THROW("TJPARAM_SUBSAMP must be specified");
1499
1500
35.8k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1501
35.8k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1502
35.8k
  srcPlanes[0] = srcBuf;
1503
35.8k
  strides[0] = PAD(pw0, align);
1504
35.8k
  if (this->subsamp == TJSAMP_GRAY) {
1505
11.8k
    strides[1] = strides[2] = 0;
1506
11.8k
    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
35.8k
  return tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
1522
35.8k
                                   jpegBuf, jpegSize);
1523
1524
0
bailout:
1525
0
  return retval;
1526
35.8k
}
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
35.8k
{
1566
35.8k
  static const char FUNCTION_NAME[] = "tj3EncodeYUVPlanes8";
1567
35.8k
  JSAMPROW *row_pointer = NULL;
1568
35.8k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
1569
35.8k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
1570
35.8k
  JSAMPROW *outbuf[MAX_COMPONENTS];
1571
35.8k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1572
35.8k
  JSAMPLE *ptr;
1573
35.8k
  jpeg_component_info *compptr;
1574
1575
35.8k
  GET_CINSTANCE(handle)
1576
1577
394k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1578
358k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
1579
358k
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
1580
358k
  }
1581
1582
35.8k
  if ((this->init & COMPRESS) == 0)
1583
35.8k
    THROW("Instance has not been initialized for compression");
1584
1585
35.8k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1586
35.8k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
1587
35.8k
      !dstPlanes[0])
1588
35.8k
    THROW("Invalid argument");
1589
35.8k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1590
35.8k
    THROW("Invalid argument");
1591
1592
35.8k
  if (this->subsamp == TJSAMP_UNKNOWN)
1593
35.8k
    THROW("TJPARAM_SUBSAMP must be specified");
1594
35.8k
  if (pixelFormat == TJPF_CMYK)
1595
35.8k
    THROW("Cannot generate YUV images from packed-pixel CMYK images");
1596
1597
35.8k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1598
1599
35.8k
  CATCH_LIBJPEG(this);
1600
1601
35.8k
  cinfo->image_width = width;
1602
35.8k
  cinfo->image_height = height;
1603
35.8k
  cinfo->data_precision = 8;
1604
1605
35.8k
  setCompDefaults(this, pixelFormat, TRUE);
1606
1607
  /* Execute only the parts of jpeg_start_compress() that we need.  If we
1608
     were to call the whole jpeg_start_compress() function, then it would try
1609
     to write the file headers, which could overflow the output buffer if the
1610
     YUV image were very small. */
1611
35.8k
  if (cinfo->global_state != CSTATE_START)
1612
35.8k
    THROW("libjpeg API is in the wrong state");
1613
35.8k
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
1614
35.8k
  jinit_c_master_control(cinfo, FALSE);
1615
35.8k
  jinit_color_converter(cinfo);
1616
35.8k
  jinit_downsampler(cinfo);
1617
35.8k
  (*cinfo->cconvert->start_pass) (cinfo);
1618
1619
35.8k
  pw0 = PAD(width, cinfo->max_h_samp_factor);
1620
35.8k
  ph0 = PAD(height, cinfo->max_v_samp_factor);
1621
1622
35.8k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1623
35.8k
    THROW("Memory allocation failure");
1624
88.7M
  for (i = 0; i < height; i++) {
1625
88.6M
    if (this->bottomUp)
1626
14.5M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
1627
74.1M
    else
1628
74.1M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
1629
88.6M
  }
1630
35.8k
  if (height < ph0)
1631
5.79k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1632
1633
119k
  for (i = 0; i < cinfo->num_components; i++) {
1634
83.8k
    compptr = &cinfo->comp_info[i];
1635
83.8k
    _tmpbuf[i] = (JSAMPLE *)MALLOC(
1636
83.8k
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1637
83.8k
          compptr->h_samp_factor, 32) *
1638
83.8k
      cinfo->max_v_samp_factor + 32);
1639
83.8k
    if (!_tmpbuf[i])
1640
83.8k
      THROW("Memory allocation failure");
1641
83.8k
    tmpbuf[i] =
1642
83.8k
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
1643
83.8k
    if (!tmpbuf[i])
1644
83.8k
      THROW("Memory allocation failure");
1645
185k
    for (row = 0; row < cinfo->max_v_samp_factor; row++) {
1646
101k
      unsigned char *_tmpbuf_aligned =
1647
101k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
1648
1649
101k
      tmpbuf[i][row] = &_tmpbuf_aligned[
1650
101k
        PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1651
101k
            compptr->h_samp_factor, 32) * row];
1652
101k
    }
1653
83.8k
    _tmpbuf2[i] =
1654
83.8k
      (JSAMPLE *)MALLOC(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1655
83.8k
                        compptr->v_samp_factor + 32);
1656
83.8k
    if (!_tmpbuf2[i])
1657
83.8k
      THROW("Memory allocation failure");
1658
83.8k
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1659
83.8k
    if (!tmpbuf2[i])
1660
83.8k
      THROW("Memory allocation failure");
1661
173k
    for (row = 0; row < compptr->v_samp_factor; row++) {
1662
89.8k
      unsigned char *_tmpbuf2_aligned =
1663
89.8k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
1664
1665
89.8k
      tmpbuf2[i][row] =
1666
89.8k
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1667
89.8k
    }
1668
83.8k
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
1669
83.8k
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1670
83.8k
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1671
83.8k
    if (!outbuf[i])
1672
83.8k
      THROW("Memory allocation failure");
1673
83.8k
    ptr = dstPlanes[i];
1674
192M
    for (row = 0; row < ph[i]; row++) {
1675
192M
      outbuf[i][row] = ptr;
1676
192M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1677
192M
    }
1678
83.8k
  }
1679
1680
35.8k
  CATCH_LIBJPEG(this);
1681
1682
81.2M
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
1683
81.2M
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
1684
81.2M
                                       cinfo->max_v_samp_factor);
1685
81.2M
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
1686
266M
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
1687
185M
         i++, compptr++)
1688
185M
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
1689
185M
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
1690
185M
        compptr->v_samp_factor, pw[i]);
1691
81.2M
  }
1692
35.8k
  cinfo->next_scanline += height;
1693
35.8k
  jpeg_abort_compress(cinfo);
1694
1695
35.8k
bailout:
1696
35.8k
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1697
35.8k
  free(row_pointer);
1698
394k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1699
358k
    free(tmpbuf[i]);
1700
358k
    free(_tmpbuf[i]);
1701
358k
    free(tmpbuf2[i]);
1702
358k
    free(_tmpbuf2[i]);
1703
358k
    free(outbuf[i]);
1704
358k
  }
1705
35.8k
  if (this->jerr.warning) retval = -1;
1706
35.8k
  return retval;
1707
35.8k
}
1708
1709
/* TurboJPEG 1.4+ */
1710
DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
1711
                                int width, int pitch, int height,
1712
                                int pixelFormat, unsigned char **dstPlanes,
1713
                                int *strides, int subsamp, int flags)
1714
0
{
1715
0
  static const char FUNCTION_NAME[] = "tjEncodeYUVPlanes";
1716
0
  int retval = 0;
1717
1718
0
  GET_TJINSTANCE(handle, -1);
1719
1720
0
  if (subsamp < 0 || subsamp >= this->numSamp)
1721
0
    THROW("Invalid argument");
1722
1723
0
  this->subsamp = subsamp;
1724
0
  processFlags(handle, flags, COMPRESS);
1725
1726
0
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1727
0
                             dstPlanes, strides);
1728
1729
0
bailout:
1730
0
  return retval;
1731
0
}
1732
1733
1734
/* TurboJPEG 3.0+ */
1735
DLLEXPORT int tj3EncodeYUV8(tjhandle handle, const unsigned char *srcBuf,
1736
                            int width, int pitch, int height, int pixelFormat,
1737
                            unsigned char *dstBuf, int align)
1738
35.8k
{
1739
35.8k
  static const char FUNCTION_NAME[] = "tj3EncodeYUV8";
1740
35.8k
  unsigned char *dstPlanes[3];
1741
35.8k
  int pw0, ph0, strides[3], retval = -1;
1742
1743
35.8k
  GET_TJINSTANCE(handle, -1);
1744
1745
35.8k
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
1746
35.8k
      !IS_POW2(align))
1747
35.8k
    THROW("Invalid argument");
1748
1749
35.8k
  if (this->subsamp == TJSAMP_UNKNOWN)
1750
35.8k
    THROW("TJPARAM_SUBSAMP must be specified");
1751
1752
35.8k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1753
35.8k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1754
35.8k
  dstPlanes[0] = dstBuf;
1755
35.8k
  strides[0] = PAD(pw0, align);
1756
35.8k
  if (this->subsamp == TJSAMP_GRAY) {
1757
11.8k
    strides[1] = strides[2] = 0;
1758
11.8k
    dstPlanes[1] = dstPlanes[2] = NULL;
1759
24.0k
  } else {
1760
24.0k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
1761
24.0k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
1762
1763
24.0k
    strides[1] = strides[2] = PAD(pw1, align);
1764
24.0k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1765
24.0k
        (unsigned long long)INT_MAX ||
1766
24.0k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1767
24.0k
        (unsigned long long)INT_MAX)
1768
24.0k
      THROW("Image or row alignment is too large");
1769
24.0k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1770
24.0k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1771
24.0k
  }
1772
1773
35.8k
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1774
35.8k
                             dstPlanes, strides);
1775
1776
0
bailout:
1777
0
  return retval;
1778
35.8k
}
1779
1780
/* TurboJPEG 1.4+ */
1781
DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
1782
                           int width, int pitch, int height, int pixelFormat,
1783
                           unsigned char *dstBuf, int align, int subsamp,
1784
                           int flags)
1785
0
{
1786
0
  static const char FUNCTION_NAME[] = "tjEncodeYUV3";
1787
0
  int retval = 0;
1788
1789
0
  GET_TJINSTANCE(handle, -1);
1790
1791
0
  if (subsamp < 0 || subsamp >= this->numSamp)
1792
0
    THROW("Invalid argument");
1793
1794
0
  this->subsamp = subsamp;
1795
0
  processFlags(handle, flags, COMPRESS);
1796
1797
0
  return tj3EncodeYUV8(handle, srcBuf, width, pitch, height, pixelFormat,
1798
0
                       dstBuf, align);
1799
1800
0
bailout:
1801
0
  return retval;
1802
0
}
1803
1804
/* TurboJPEG 1.2+ */
1805
DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
1806
                           int pitch, int height, int pixelFormat,
1807
                           unsigned char *dstBuf, int subsamp, int flags)
1808
0
{
1809
0
  return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1810
0
                      dstBuf, 4, subsamp, flags);
1811
0
}
1812
1813
/* TurboJPEG 1.1+ */
1814
DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
1815
                          int pitch, int height, int pixelSize,
1816
                          unsigned char *dstBuf, int subsamp, int flags)
1817
0
{
1818
0
  return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1819
0
                      getPixelFormat(pixelSize, flags), dstBuf, subsamp,
1820
0
                      flags);
1821
0
}
1822
1823
1824
/******************************* Decompressor ********************************/
1825
1826
static tjhandle _tjInitDecompress(tjinstance *this)
1827
55.4k
{
1828
55.4k
  static unsigned char buffer[1];
1829
1830
  /* This is also straight out of example.c */
1831
55.4k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1832
55.4k
  this->jerr.pub.error_exit = my_error_exit;
1833
55.4k
  this->jerr.pub.output_message = my_output_message;
1834
55.4k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1835
55.4k
  this->jerr.pub.emit_message = my_emit_message;
1836
55.4k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1837
55.4k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1838
55.4k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1839
55.4k
  this->jerr.tjHandle = (tjhandle)this;
1840
1841
55.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
1842
    /* If we get here, the JPEG code has signaled an error. */
1843
0
    free(this);
1844
0
    return NULL;
1845
0
  }
1846
1847
55.4k
  jpeg_create_decompress(&this->dinfo);
1848
  /* Make an initial call so it will create the source manager */
1849
55.4k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1850
1851
55.4k
  this->init |= DECOMPRESS;
1852
55.4k
  return (tjhandle)this;
1853
55.4k
}
1854
1855
/* TurboJPEG 1.0+ */
1856
DLLEXPORT tjhandle tjInitDecompress(void)
1857
0
{
1858
0
  return tj3Init(TJINIT_DECOMPRESS);
1859
0
}
1860
1861
1862
/* TurboJPEG 3.0+ */
1863
DLLEXPORT int tj3DecompressHeader(tjhandle handle,
1864
                                  const unsigned char *jpegBuf,
1865
                                  size_t jpegSize)
1866
19.4k
{
1867
19.4k
  static const char FUNCTION_NAME[] = "tj3DecompressHeader";
1868
19.4k
  int retval = 0;
1869
19.4k
  unsigned char *iccPtr = NULL;
1870
19.4k
  unsigned int iccLen = 0;
1871
1872
19.4k
  GET_DINSTANCE(handle);
1873
19.4k
  if ((this->init & DECOMPRESS) == 0)
1874
19.4k
    THROW("Instance has not been initialized for decompression");
1875
1876
19.4k
  if (jpegBuf == NULL || jpegSize <= 0)
1877
19.4k
    THROW("Invalid argument");
1878
1879
19.4k
  CATCH_LIBJPEG(this);
1880
1881
17.5k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1882
1883
  /* Extract ICC profile if TJPARAM_SAVEMARKERS is 2 or 4.  (We could
1884
     eventually reuse this mechanism to save other markers, if needed.)
1885
     Because ICC profiles can be large, we extract them by default but allow
1886
     the user to override that behavior. */
1887
17.5k
#ifdef SAVE_MARKERS_SUPPORTED
1888
17.5k
  if (this->saveMarkers == 2 || this->saveMarkers == 4)
1889
19.4k
    jpeg_save_markers(dinfo, JPEG_APP0 + 2, 0xFFFF);
1890
17.5k
#endif
1891
  /* jpeg_read_header() calls jpeg_abort() and returns JPEG_HEADER_TABLES_ONLY
1892
     if the datastream is a tables-only datastream.  Since we aren't using a
1893
     suspending data source, the only other value it can return is
1894
     JPEG_HEADER_OK. */
1895
17.5k
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1896
1.81k
    return 0;
1897
1898
15.7k
  setDecompParameters(this);
1899
1900
15.7k
  if (this->saveMarkers == 2 || this->saveMarkers == 4) {
1901
15.7k
    if (jpeg_read_icc_profile(dinfo, &iccPtr, &iccLen)) {
1902
625
      free(this->decompICCBuf);
1903
625
      this->decompICCBuf = iccPtr;
1904
625
      this->decompICCSize = (size_t)iccLen;
1905
625
    }
1906
15.7k
  }
1907
1908
15.7k
  jpeg_abort_decompress(dinfo);
1909
1910
15.7k
  if (this->colorspace == TJCS_DEFAULT)
1911
15.7k
    THROW("Could not determine colorspace of JPEG image");
1912
15.6k
  if (this->jpegWidth < 1 || this->jpegHeight < 1)
1913
15.6k
    THROW("Invalid data returned in header");
1914
1915
17.6k
bailout:
1916
17.6k
  if (this->jerr.warning) retval = -1;
1917
17.6k
  return retval;
1918
15.6k
}
1919
1920
/* TurboJPEG 1.4+ */
1921
DLLEXPORT int tjDecompressHeader3(tjhandle handle,
1922
                                  const unsigned char *jpegBuf,
1923
                                  unsigned long jpegSize, int *width,
1924
                                  int *height, int *jpegSubsamp,
1925
                                  int *jpegColorspace)
1926
0
{
1927
0
  static const char FUNCTION_NAME[] = "tjDecompressHeader3";
1928
0
  int retval = 0;
1929
1930
0
  GET_TJINSTANCE(handle, -1);
1931
1932
0
  if (width == NULL || height == NULL || jpegSubsamp == NULL ||
1933
0
      jpegColorspace == NULL)
1934
0
    THROW("Invalid argument");
1935
1936
0
  retval = tj3DecompressHeader(handle, jpegBuf, jpegSize);
1937
1938
0
  *width = tj3Get(handle, TJPARAM_JPEGWIDTH);
1939
0
  *height = tj3Get(handle, TJPARAM_JPEGHEIGHT);
1940
0
  *jpegSubsamp = tj3Get(handle, TJPARAM_SUBSAMP);
1941
0
  if (*jpegSubsamp == TJSAMP_UNKNOWN)
1942
0
    THROW("Could not determine subsampling level of JPEG image");
1943
0
  *jpegColorspace = tj3Get(handle, TJPARAM_COLORSPACE);
1944
1945
0
bailout:
1946
0
  return retval;
1947
0
}
1948
1949
/* TurboJPEG 1.1+ */
1950
DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
1951
                                  unsigned long jpegSize, int *width,
1952
                                  int *height, int *jpegSubsamp)
1953
0
{
1954
0
  int jpegColorspace;
1955
1956
0
  return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1957
0
                             jpegSubsamp, &jpegColorspace);
1958
0
}
1959
1960
/* TurboJPEG 1.0+ */
1961
DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
1962
                                 unsigned long jpegSize, int *width,
1963
                                 int *height)
1964
0
{
1965
0
  int jpegSubsamp;
1966
1967
0
  return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1968
0
                             &jpegSubsamp);
1969
0
}
1970
1971
1972
/* TurboJPEG 3.1+ */
1973
DLLEXPORT int tj3GetICCProfile(tjhandle handle, unsigned char **iccBuf,
1974
                               size_t *iccSize)
1975
0
{
1976
0
  static const char FUNCTION_NAME[] = "tj3GetICCProfile";
1977
0
  int retval = 0;
1978
1979
0
  GET_TJINSTANCE(handle, -1);
1980
1981
0
  if (iccSize == NULL)
1982
0
    THROW("Invalid argument");
1983
1984
0
  if (this->init & DECOMPRESS) {
1985
0
    if (!this->decompICCBuf || !this->decompICCSize) {
1986
0
      if (iccBuf) *iccBuf = NULL;
1987
0
      *iccSize = 0;
1988
0
      this->jerr.warning = TRUE;
1989
0
      THROW("No ICC profile data has been extracted");
1990
0
    }
1991
0
    *iccSize = this->decompICCSize;
1992
0
  } else
1993
0
    *iccSize = this->iccSize;
1994
0
  if (iccBuf == NULL)
1995
0
    return 0;
1996
0
  if (*iccSize) {
1997
0
    if ((*iccBuf = (unsigned char *)malloc(*iccSize)) == NULL)
1998
0
      THROW("Memory allocation failure");
1999
0
    if (this->init & DECOMPRESS)
2000
0
      memcpy(*iccBuf, this->decompICCBuf, *iccSize);
2001
0
    else
2002
0
      memcpy(*iccBuf, this->iccBuf, *iccSize);
2003
0
  } else
2004
0
    *iccBuf = NULL;
2005
2006
0
bailout:
2007
0
  return retval;
2008
0
}
2009
2010
2011
/* TurboJPEG 3.0+ */
2012
DLLEXPORT tjscalingfactor *tj3GetScalingFactors(int *numScalingFactors)
2013
0
{
2014
0
  static const char FUNCTION_NAME[] = "tj3GetScalingFactors";
2015
0
  tjscalingfactor *retval = (tjscalingfactor *)sf;
2016
2017
0
  if (numScalingFactors == NULL)
2018
0
    THROWG("Invalid argument", NULL);
2019
2020
0
  *numScalingFactors = NUMSF;
2021
2022
0
bailout:
2023
0
  return retval;
2024
0
}
2025
2026
/* TurboJPEG 1.2+ */
2027
DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numScalingFactors)
2028
0
{
2029
0
  return tj3GetScalingFactors(numScalingFactors);
2030
0
}
2031
2032
2033
/* TurboJPEG 3.0+ */
2034
DLLEXPORT int tj3SetScalingFactor(tjhandle handle,
2035
                                  tjscalingfactor scalingFactor)
2036
92.4k
{
2037
92.4k
  static const char FUNCTION_NAME[] = "tj3SetScalingFactor";
2038
92.4k
  int i, retval = 0;
2039
2040
92.4k
  GET_TJINSTANCE(handle, -1);
2041
92.4k
  if ((this->init & DECOMPRESS) == 0)
2042
92.4k
    THROW("Instance has not been initialized for decompression");
2043
2044
993k
  for (i = 0; i < NUMSF; i++) {
2045
993k
    if (scalingFactor.num == sf[i].num && scalingFactor.denom == sf[i].denom)
2046
92.4k
      break;
2047
993k
  }
2048
92.4k
  if (i >= NUMSF)
2049
92.4k
    THROW("Unsupported scaling factor");
2050
2051
92.4k
  this->scalingFactor = scalingFactor;
2052
2053
92.4k
bailout:
2054
92.4k
  return retval;
2055
92.4k
}
2056
2057
2058
/* TurboJPEG 3.0+ */
2059
DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion)
2060
43.3k
{
2061
43.3k
  static const char FUNCTION_NAME[] = "tj3SetCroppingRegion";
2062
43.3k
  int retval = 0, scaledWidth, scaledHeight;
2063
2064
43.3k
  GET_TJINSTANCE(handle, -1);
2065
43.3k
  if ((this->init & DECOMPRESS) == 0)
2066
43.3k
    THROW("Instance has not been initialized for decompression");
2067
2068
43.3k
  if (croppingRegion.x == 0 && croppingRegion.y == 0 &&
2069
38.4k
      croppingRegion.w == 0 && croppingRegion.h == 0) {
2070
38.4k
    this->croppingRegion = croppingRegion;
2071
38.4k
    return 0;
2072
38.4k
  }
2073
2074
4.92k
  if (croppingRegion.x < 0 || croppingRegion.y < 0 || croppingRegion.w < 0 ||
2075
4.92k
      croppingRegion.h < 0)
2076
4.92k
    THROW("Invalid cropping region");
2077
4.92k
  if (this->jpegWidth < 0 || this->jpegHeight < 0)
2078
4.92k
    THROW("JPEG header has not yet been read");
2079
4.92k
  if ((this->precision != 8 && this->precision != 12) || this->lossless)
2080
4.92k
    THROW("Cannot partially decompress lossless JPEG images");
2081
4.92k
  if (this->subsamp == TJSAMP_UNKNOWN)
2082
4.92k
    THROW("Could not determine subsampling level of JPEG image");
2083
2084
4.18k
  scaledWidth = TJSCALED(this->jpegWidth, this->scalingFactor);
2085
4.18k
  scaledHeight = TJSCALED(this->jpegHeight, this->scalingFactor);
2086
2087
4.18k
  if (croppingRegion.x %
2088
4.18k
      TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor) != 0)
2089
0
    THROWI("The left boundary of the cropping region (%d) is not\n"
2090
4.18k
           "divisible by the scaled iMCU width (%d)",
2091
4.18k
           croppingRegion.x,
2092
4.18k
           TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor));
2093
4.18k
  if (croppingRegion.w == 0)
2094
0
    croppingRegion.w = scaledWidth - croppingRegion.x;
2095
4.18k
  if (croppingRegion.h == 0)
2096
0
    croppingRegion.h = scaledHeight - croppingRegion.y;
2097
4.18k
  if (croppingRegion.w <= 0 || croppingRegion.h <= 0 ||
2098
4.18k
      croppingRegion.x + croppingRegion.w > scaledWidth ||
2099
4.18k
      croppingRegion.y + croppingRegion.h > scaledHeight)
2100
4.18k
    THROW("The cropping region exceeds the scaled image dimensions");
2101
2102
4.18k
  this->croppingRegion = croppingRegion;
2103
2104
4.92k
bailout:
2105
4.92k
  return retval;
2106
4.18k
}
2107
2108
2109
/* tj3Decompress*() is implemented in turbojpeg-mp.c */
2110
2111
/* TurboJPEG 1.2+ */
2112
DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
2113
                            unsigned long jpegSize, unsigned char *dstBuf,
2114
                            int width, int pitch, int height, int pixelFormat,
2115
                            int flags)
2116
0
{
2117
0
  static const char FUNCTION_NAME[] = "tjDecompress2";
2118
0
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
2119
2120
0
  GET_DINSTANCE(handle);
2121
0
  if ((this->init & DECOMPRESS) == 0)
2122
0
    THROW("Instance has not been initialized for decompression");
2123
2124
0
  if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
2125
0
    THROW("Invalid argument");
2126
2127
0
  CATCH_LIBJPEG(this);
2128
2129
0
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2130
0
  jpeg_read_header(dinfo, TRUE);
2131
0
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
2132
0
  if (width == 0) width = jpegwidth;
2133
0
  if (height == 0) height = jpegheight;
2134
0
  for (i = 0; i < NUMSF; i++) {
2135
0
    scaledw = TJSCALED(jpegwidth, sf[i]);
2136
0
    scaledh = TJSCALED(jpegheight, sf[i]);
2137
0
    if (scaledw <= width && scaledh <= height)
2138
0
      break;
2139
0
  }
2140
0
  if (i >= NUMSF)
2141
0
    THROW("Could not scale down to desired image dimensions");
2142
0
  if (dinfo->master->lossless && ((JDIMENSION)scaledw != dinfo->image_width ||
2143
0
                                  (JDIMENSION)scaledh != dinfo->image_height))
2144
0
    THROW("Cannot use decompression scaling with lossless JPEG images");
2145
2146
0
  processFlags(handle, flags, DECOMPRESS);
2147
2148
0
  if (tj3SetScalingFactor(handle, sf[i]) == -1)
2149
0
    return -1;
2150
0
  if (tj3SetCroppingRegion(handle, TJUNCROPPED) == -1)
2151
0
    return -1;
2152
0
  return tj3Decompress8(handle, jpegBuf, jpegSize, dstBuf, pitch, pixelFormat);
2153
2154
0
bailout:
2155
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2156
0
  if (this->jerr.warning) retval = -1;
2157
0
  return retval;
2158
0
}
2159
2160
/* TurboJPEG 1.0+ */
2161
DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
2162
                           unsigned long jpegSize, unsigned char *dstBuf,
2163
                           int width, int pitch, int height, int pixelSize,
2164
                           int flags)
2165
0
{
2166
0
  if (flags & TJ_YUV)
2167
0
    return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
2168
0
  else
2169
0
    return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
2170
0
                         height, getPixelFormat(pixelSize, flags), flags);
2171
0
}
2172
2173
2174
/* TurboJPEG 3.0+ */
2175
DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle,
2176
                                        const unsigned char *jpegBuf,
2177
                                        size_t jpegSize,
2178
                                        unsigned char **dstPlanes,
2179
                                        int *strides)
2180
16.6k
{
2181
16.6k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUVPlanes8";
2182
16.6k
  int i, row, retval = 0;
2183
16.6k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
2184
16.6k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
2185
16.6k
  JSAMPLE *_tmpbuf = NULL, *ptr;
2186
16.6k
  JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
2187
16.6k
  int dctsize;
2188
16.6k
  struct my_progress_mgr progress;
2189
2190
16.6k
  GET_DINSTANCE(handle);
2191
2192
183k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2193
166k
    tmpbuf[i] = NULL;  outbuf[i] = NULL;
2194
166k
  }
2195
2196
16.6k
  if ((this->init & DECOMPRESS) == 0)
2197
16.6k
    THROW("Instance has not been initialized for decompression");
2198
2199
16.6k
  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0])
2200
16.6k
    THROW("Invalid argument");
2201
2202
16.6k
  if (this->scanLimit) {
2203
16.6k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2204
16.6k
    progress.pub.progress_monitor = my_progress_monitor;
2205
16.6k
    progress.this = this;
2206
16.6k
    dinfo->progress = &progress.pub;
2207
16.6k
  } else
2208
0
    dinfo->progress = NULL;
2209
2210
16.6k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2211
2212
16.6k
  CATCH_LIBJPEG(this);
2213
2214
16.6k
  if (dinfo->global_state <= DSTATE_INHEADER) {
2215
0
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2216
0
    jpeg_read_header(dinfo, TRUE);
2217
0
  }
2218
16.6k
  setDecompParameters(this);
2219
16.6k
  if (this->maxPixels &&
2220
0
      (unsigned long long)this->jpegWidth * this->jpegHeight >
2221
0
      (unsigned long long)this->maxPixels)
2222
16.6k
    THROW("Image is too large");
2223
16.6k
  if (this->subsamp == TJSAMP_UNKNOWN)
2224
16.6k
    THROW("Could not determine subsampling level of JPEG image");
2225
2226
16.6k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
2227
16.6k
    THROW("Invalid argument");
2228
2229
16.6k
  if (dinfo->num_components > 3)
2230
16.6k
    THROW("JPEG image must have 3 or fewer components");
2231
2232
16.6k
  dinfo->scale_num = this->scalingFactor.num;
2233
16.6k
  dinfo->scale_denom = this->scalingFactor.denom;
2234
16.6k
  jpeg_calc_output_dimensions(dinfo);
2235
2236
16.6k
  dctsize = DCTSIZE * this->scalingFactor.num / this->scalingFactor.denom;
2237
2238
49.0k
  for (i = 0; i < dinfo->num_components; i++) {
2239
32.4k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
2240
32.4k
    int ih;
2241
2242
32.4k
    iw[i] = compptr->width_in_blocks * dctsize;
2243
32.4k
    ih = compptr->height_in_blocks * dctsize;
2244
32.4k
    pw[i] = tj3YUVPlaneWidth(i, dinfo->output_width, this->subsamp);
2245
32.4k
    ph[i] = tj3YUVPlaneHeight(i, dinfo->output_height, this->subsamp);
2246
32.4k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
2247
32.4k
    th[i] = compptr->v_samp_factor * dctsize;
2248
32.4k
    tmpbufsize += iw[i] * th[i];
2249
32.4k
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
2250
32.4k
      THROW("Memory allocation failure");
2251
32.4k
    ptr = dstPlanes[i];
2252
228M
    for (row = 0; row < ph[i]; row++) {
2253
228M
      outbuf[i][row] = ptr;
2254
228M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2255
228M
    }
2256
32.4k
  }
2257
16.6k
  if (usetmpbuf) {
2258
15.3k
    if ((_tmpbuf = (JSAMPLE *)MALLOC(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
2259
15.3k
      THROW("Memory allocation failure");
2260
15.3k
    ptr = _tmpbuf;
2261
45.6k
    for (i = 0; i < dinfo->num_components; i++) {
2262
30.2k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
2263
30.2k
        THROW("Memory allocation failure");
2264
334k
      for (row = 0; row < th[i]; row++) {
2265
304k
        tmpbuf[i][row] = ptr;
2266
304k
        ptr += iw[i];
2267
304k
      }
2268
30.2k
    }
2269
15.3k
  }
2270
2271
16.6k
  CATCH_LIBJPEG(this);
2272
2273
5.06k
  dinfo->do_fancy_upsampling = !this->fastUpsample;
2274
5.06k
  dinfo->dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2275
5.06k
  dinfo->raw_data_out = TRUE;
2276
2277
5.06k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2278
2279
5.06k
  jpeg_start_decompress(dinfo);
2280
2.35M
  for (row = 0; row < (int)dinfo->output_height;
2281
2.34M
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
2282
2.34M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
2283
2.34M
    int crow[MAX_COMPONENTS];
2284
2285
5.99M
    for (i = 0; i < dinfo->num_components; i++) {
2286
3.64M
      jpeg_component_info *compptr = &dinfo->comp_info[i];
2287
2288
3.64M
      if (this->subsamp == TJSAMP_420 || this->subsamp == TJSAMP_410 ||
2289
3.27M
          this->subsamp == TJSAMP_24) {
2290
        /* When 4:2:0, 4:1:0, or 2:4 subsampling is used with IDCT scaling,
2291
           libjpeg will try to be clever and use the IDCT to perform upsampling
2292
           on the U and V planes.  For instance, if the output image is to be
2293
           scaled by 1/2 relative to the JPEG image, then the scaling factor
2294
           and upsampling effectively cancel each other, so a normal 8x8 IDCT
2295
           can be used. However, this is not desirable when using the
2296
           decompress-to-YUV functionality in TurboJPEG, since we want to
2297
           output the U and V planes in their subsampled form.  Thus, we have
2298
           to override some internal libjpeg parameters to force it to use the
2299
           "scaled" IDCT functions on the U and V planes. */
2300
365k
        compptr->_DCT_scaled_size = dctsize;
2301
365k
        compptr->MCU_sample_width = tjMCUWidth[this->subsamp] *
2302
365k
          this->scalingFactor.num / this->scalingFactor.denom *
2303
365k
          compptr->h_samp_factor / dinfo->max_h_samp_factor;
2304
365k
        dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
2305
365k
      }
2306
3.64M
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2307
3.64M
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
2308
282k
      else yuvptr[i] = &outbuf[i][crow[i]];
2309
3.64M
    }
2310
2.34M
    jpeg_read_raw_data(dinfo, yuvptr,
2311
2.34M
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
2312
2.34M
    if (usetmpbuf) {
2313
2.14M
      int j;
2314
2315
5.50M
      for (i = 0; i < dinfo->num_components; i++) {
2316
28.8M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
2317
25.5M
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
2318
25.5M
        }
2319
3.35M
      }
2320
2.14M
    }
2321
2.34M
  }
2322
5.06k
  jpeg_finish_decompress(dinfo);
2323
2324
16.6k
bailout:
2325
16.6k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2326
183k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2327
166k
    free(tmpbuf[i]);
2328
166k
    free(outbuf[i]);
2329
166k
  }
2330
16.6k
  free(_tmpbuf);
2331
16.6k
  if (this->jerr.warning) retval = -1;
2332
16.6k
  return retval;
2333
5.06k
}
2334
2335
/* TurboJPEG 1.4+ */
2336
DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
2337
                                      const unsigned char *jpegBuf,
2338
                                      unsigned long jpegSize,
2339
                                      unsigned char **dstPlanes, int width,
2340
                                      int *strides, int height, int flags)
2341
0
{
2342
0
  static const char FUNCTION_NAME[] = "tjDecompressToYUVPlanes";
2343
0
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
2344
2345
0
  GET_DINSTANCE(handle);
2346
0
  if ((this->init & DECOMPRESS) == 0)
2347
0
    THROW("Instance has not been initialized for decompression");
2348
2349
0
  if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
2350
0
    THROW("Invalid argument");
2351
2352
0
  CATCH_LIBJPEG(this);
2353
2354
0
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2355
0
  jpeg_read_header(dinfo, TRUE);
2356
0
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
2357
0
  if (width == 0) width = jpegwidth;
2358
0
  if (height == 0) height = jpegheight;
2359
0
  for (i = 0; i < NUMSF; i++) {
2360
0
    scaledw = TJSCALED(jpegwidth, sf[i]);
2361
0
    scaledh = TJSCALED(jpegheight, sf[i]);
2362
0
    if (scaledw <= width && scaledh <= height)
2363
0
      break;
2364
0
  }
2365
0
  if (i >= NUMSF)
2366
0
    THROW("Could not scale down to desired image dimensions");
2367
2368
0
  processFlags(handle, flags, DECOMPRESS);
2369
2370
0
  if (tj3SetScalingFactor(handle, sf[i]) == -1)
2371
0
    return -1;
2372
0
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2373
0
                                   strides);
2374
2375
0
bailout:
2376
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2377
0
  if (this->jerr.warning) retval = -1;
2378
0
  return retval;
2379
0
}
2380
2381
2382
/* TurboJPEG 3.0+ */
2383
DLLEXPORT int tj3DecompressToYUV8(tjhandle handle,
2384
                                  const unsigned char *jpegBuf,
2385
                                  size_t jpegSize,
2386
                                  unsigned char *dstBuf, int align)
2387
45.5k
{
2388
45.5k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUV8";
2389
45.5k
  unsigned char *dstPlanes[3];
2390
45.5k
  int pw0, ph0, strides[3], retval = -1;
2391
45.5k
  int width, height;
2392
2393
45.5k
  GET_DINSTANCE(handle);
2394
2395
45.5k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || align < 1 ||
2396
45.5k
      !IS_POW2(align))
2397
45.5k
    THROW("Invalid argument");
2398
2399
45.5k
  CATCH_LIBJPEG(this);
2400
2401
45.5k
  if (dinfo->global_state <= DSTATE_INHEADER) {
2402
45.5k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2403
45.5k
    jpeg_read_header(dinfo, TRUE);
2404
45.5k
  }
2405
45.5k
  setDecompParameters(this);
2406
45.5k
  if (this->subsamp == TJSAMP_UNKNOWN)
2407
45.5k
    THROW("Could not determine subsampling level of JPEG image");
2408
2409
44.9k
  width = TJSCALED(dinfo->image_width, this->scalingFactor);
2410
44.9k
  height = TJSCALED(dinfo->image_height, this->scalingFactor);
2411
2412
44.9k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2413
44.9k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2414
44.9k
  dstPlanes[0] = dstBuf;
2415
44.9k
  strides[0] = PAD(pw0, align);
2416
44.9k
  if (this->subsamp == TJSAMP_GRAY) {
2417
16.8k
    strides[1] = strides[2] = 0;
2418
16.8k
    dstPlanes[1] = dstPlanes[2] = NULL;
2419
28.1k
  } else {
2420
28.1k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2421
28.1k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2422
2423
28.1k
    strides[1] = strides[2] = PAD(pw1, align);
2424
28.1k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2425
28.1k
        (unsigned long long)INT_MAX ||
2426
28.1k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2427
28.1k
        (unsigned long long)INT_MAX)
2428
28.1k
      THROW("Image or row alignment is too large");
2429
28.1k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
2430
28.1k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
2431
28.1k
  }
2432
2433
44.9k
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2434
44.9k
                                   strides);
2435
2436
604
bailout:
2437
604
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2438
604
  if (this->jerr.warning) retval = -1;
2439
604
  return retval;
2440
44.9k
}
2441
2442
/* TurboJPEG 1.4+ */
2443
DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
2444
                                 unsigned long jpegSize, unsigned char *dstBuf,
2445
                                 int width, int align, int height, int flags)
2446
0
{
2447
0
  static const char FUNCTION_NAME[] = "tjDecompressToYUV2";
2448
0
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
2449
2450
0
  GET_DINSTANCE(handle);
2451
0
  if ((this->init & DECOMPRESS) == 0)
2452
0
    THROW("Instance has not been initialized for decompression");
2453
2454
0
  if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
2455
0
    THROW("Invalid argument");
2456
2457
0
  CATCH_LIBJPEG(this);
2458
2459
0
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2460
0
  jpeg_read_header(dinfo, TRUE);
2461
0
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
2462
0
  if (width == 0) width = jpegwidth;
2463
0
  if (height == 0) height = jpegheight;
2464
0
  for (i = 0; i < NUMSF; i++) {
2465
0
    scaledw = TJSCALED(jpegwidth, sf[i]);
2466
0
    scaledh = TJSCALED(jpegheight, sf[i]);
2467
0
    if (scaledw <= width && scaledh <= height)
2468
0
      break;
2469
0
  }
2470
0
  if (i >= NUMSF)
2471
0
    THROW("Could not scale down to desired image dimensions");
2472
2473
0
  width = scaledw;  height = scaledh;
2474
2475
0
  processFlags(handle, flags, DECOMPRESS);
2476
2477
0
  if (tj3SetScalingFactor(handle, sf[i]) == -1)
2478
0
    return -1;
2479
0
  return tj3DecompressToYUV8(handle, jpegBuf, (size_t)jpegSize, dstBuf, align);
2480
2481
0
bailout:
2482
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2483
0
  if (this->jerr.warning) retval = -1;
2484
0
  return retval;
2485
0
}
2486
2487
/* TurboJPEG 1.1+ */
2488
DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
2489
                                unsigned long jpegSize, unsigned char *dstBuf,
2490
                                int flags)
2491
0
{
2492
0
  return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
2493
0
}
2494
2495
2496
static void setDecodeDefaults(tjinstance *this, int pixelFormat)
2497
2.13k
{
2498
2.13k
  int i;
2499
2500
2.13k
  this->dinfo.scale_num = this->dinfo.scale_denom = 1;
2501
2502
2.13k
  if (this->subsamp == TJSAMP_GRAY) {
2503
734
    this->dinfo.num_components = this->dinfo.comps_in_scan = 1;
2504
734
    this->dinfo.jpeg_color_space = JCS_GRAYSCALE;
2505
1.40k
  } else {
2506
1.40k
    this->dinfo.num_components = this->dinfo.comps_in_scan = 3;
2507
1.40k
    this->dinfo.jpeg_color_space = JCS_YCbCr;
2508
1.40k
  }
2509
2510
2.13k
  this->dinfo.comp_info = (jpeg_component_info *)
2511
2.13k
    (*this->dinfo.mem->alloc_small) ((j_common_ptr)&this->dinfo, JPOOL_IMAGE,
2512
2.13k
                                     this->dinfo.num_components *
2513
2.13k
                                     sizeof(jpeg_component_info));
2514
2515
7.07k
  for (i = 0; i < this->dinfo.num_components; i++) {
2516
4.94k
    jpeg_component_info *compptr = &this->dinfo.comp_info[i];
2517
2518
4.94k
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[this->subsamp] / 8 : 1;
2519
4.94k
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[this->subsamp] / 8 : 1;
2520
4.94k
    compptr->component_index = i;
2521
4.94k
    compptr->component_id = i + 1;
2522
4.94k
    compptr->quant_tbl_no = compptr->dc_tbl_no =
2523
4.94k
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
2524
4.94k
    this->dinfo.cur_comp_info[i] = compptr;
2525
4.94k
  }
2526
2.13k
  this->dinfo.data_precision = 8;
2527
6.40k
  for (i = 0; i < 2; i++) {
2528
4.27k
    if (this->dinfo.quant_tbl_ptrs[i] == NULL)
2529
489
      this->dinfo.quant_tbl_ptrs[i] =
2530
489
        jpeg_alloc_quant_table((j_common_ptr)&this->dinfo);
2531
4.27k
  }
2532
2533
2.13k
  this->dinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2534
2.13k
}
2535
2536
2537
static int my_read_markers(j_decompress_ptr dinfo)
2538
2.13k
{
2539
2.13k
  return JPEG_REACHED_SOS;
2540
2.13k
}
2541
2542
static void my_reset_marker_reader(j_decompress_ptr dinfo)
2543
2.13k
{
2544
2.13k
}
2545
2546
/* TurboJPEG 3.0+ */
2547
DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle,
2548
                                  const unsigned char * const *srcPlanes,
2549
                                  const int *strides, unsigned char *dstBuf,
2550
                                  int width, int pitch, int height,
2551
                                  int pixelFormat)
2552
2.13k
{
2553
2.13k
  static const char FUNCTION_NAME[] = "tj3DecodeYUVPlanes8";
2554
2.13k
  JSAMPROW *row_pointer = NULL;
2555
2.13k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS];
2556
2.13k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
2557
2.13k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
2558
2.13k
  JSAMPLE *ptr;
2559
2.13k
  jpeg_component_info *compptr;
2560
2.13k
  int (*old_read_markers) (j_decompress_ptr) = NULL;
2561
2.13k
  void (*old_reset_marker_reader) (j_decompress_ptr) = NULL;
2562
2563
2.13k
  GET_DINSTANCE(handle);
2564
2565
23.4k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2566
21.3k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;  inbuf[i] = NULL;
2567
21.3k
  }
2568
2569
2.13k
  if ((this->init & DECOMPRESS) == 0)
2570
2.13k
    THROW("Instance has not been initialized for decompression");
2571
2572
2.13k
  if (!srcPlanes || !srcPlanes[0] || dstBuf == NULL || width <= 0 ||
2573
2.13k
      pitch < 0 || height <= 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
2574
2.13k
    THROW("Invalid argument");
2575
2.13k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
2576
2.13k
    THROW("Invalid argument");
2577
2578
2.13k
  if (this->subsamp == TJSAMP_UNKNOWN)
2579
2.13k
    THROW("TJPARAM_SUBSAMP must be specified");
2580
2.13k
  if (pixelFormat == TJPF_CMYK)
2581
2.13k
    THROW("Cannot decode YUV images into packed-pixel CMYK images.");
2582
2583
2.13k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
2584
2.13k
  dinfo->image_width = width;
2585
2.13k
  dinfo->image_height = height;
2586
2587
2.13k
  dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
2588
2.13k
  dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
2589
2.13k
  dinfo->Se = DCTSIZE2 - 1;
2590
2.13k
  setDecodeDefaults(this, pixelFormat);
2591
2.13k
  old_read_markers = dinfo->marker->read_markers;
2592
2.13k
  dinfo->marker->read_markers = my_read_markers;
2593
2.13k
  old_reset_marker_reader = dinfo->marker->reset_marker_reader;
2594
2.13k
  dinfo->marker->reset_marker_reader = my_reset_marker_reader;
2595
2.13k
  CATCH_LIBJPEG(this);
2596
2.11k
  jpeg_read_header(dinfo, TRUE);
2597
2.11k
  dinfo->marker->read_markers = old_read_markers;
2598
2.11k
  dinfo->marker->reset_marker_reader = old_reset_marker_reader;
2599
2600
2.11k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
2601
2.11k
  this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2602
2.11k
  dinfo->do_fancy_upsampling = FALSE;
2603
2.11k
  dinfo->Se = DCTSIZE2 - 1;
2604
2.11k
  jinit_master_decompress(dinfo);
2605
2.11k
  (*dinfo->upsample->start_pass) (dinfo);
2606
2607
2.11k
  pw0 = PAD(width, dinfo->max_h_samp_factor);
2608
2.11k
  ph0 = PAD(height, dinfo->max_v_samp_factor);
2609
2610
2.11k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
2611
2612
2.11k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
2613
2.11k
    THROW("Memory allocation failure");
2614
11.7M
  for (i = 0; i < height; i++) {
2615
11.7M
    if (this->bottomUp)
2616
4.12M
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
2617
7.60M
    else
2618
7.60M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
2619
11.7M
  }
2620
2.11k
  if (height < ph0)
2621
893
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
2622
2623
6.98k
  for (i = 0; i < dinfo->num_components; i++) {
2624
4.87k
    compptr = &dinfo->comp_info[i];
2625
4.87k
    _tmpbuf[i] =
2626
4.87k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
2627
4.87k
                        compptr->v_samp_factor + 32);
2628
4.87k
    if (!_tmpbuf[i])
2629
4.87k
      THROW("Memory allocation failure");
2630
4.87k
    tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
2631
4.87k
    if (!tmpbuf[i])
2632
4.87k
      THROW("Memory allocation failure");
2633
10.6k
    for (row = 0; row < compptr->v_samp_factor; row++) {
2634
5.81k
      unsigned char *_tmpbuf_aligned =
2635
5.81k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
2636
2637
5.81k
      tmpbuf[i][row] =
2638
5.81k
        &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
2639
5.81k
    }
2640
4.87k
    pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
2641
4.87k
    ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2642
4.87k
    inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
2643
4.87k
    if (!inbuf[i])
2644
4.87k
      THROW("Memory allocation failure");
2645
4.87k
    ptr = (JSAMPLE *)srcPlanes[i];
2646
21.6M
    for (row = 0; row < ph[i]; row++) {
2647
21.6M
      inbuf[i][row] = ptr;
2648
21.6M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2649
21.6M
    }
2650
4.87k
  }
2651
2652
2.11k
  CATCH_LIBJPEG(this);
2653
2654
10.2M
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
2655
10.2M
    JDIMENSION inrow = 0, outrow = 0;
2656
2657
30.4M
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
2658
20.1M
         i++, compptr++)
2659
20.1M
      jcopy_sample_rows(inbuf[i],
2660
20.1M
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
2661
20.1M
        compptr->v_samp_factor, pw[i]);
2662
10.2M
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
2663
10.2M
                                 dinfo->max_v_samp_factor, &row_pointer[row],
2664
10.2M
                                 &outrow, dinfo->max_v_samp_factor);
2665
10.2M
  }
2666
2.11k
  jpeg_abort_decompress(dinfo);
2667
2668
2.13k
bailout:
2669
2.13k
  if (old_read_markers)
2670
2.13k
    dinfo->marker->read_markers = old_read_markers;
2671
2.13k
  if (old_reset_marker_reader)
2672
2.13k
    dinfo->marker->reset_marker_reader = old_reset_marker_reader;
2673
2.13k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2674
2.13k
  free(row_pointer);
2675
23.4k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2676
21.3k
    free(tmpbuf[i]);
2677
21.3k
    free(_tmpbuf[i]);
2678
21.3k
    free(inbuf[i]);
2679
21.3k
  }
2680
2.13k
  if (this->jerr.warning) retval = -1;
2681
2.13k
  return retval;
2682
2.11k
}
2683
2684
/* TurboJPEG 1.4+ */
2685
DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
2686
                                const unsigned char **srcPlanes,
2687
                                const int *strides, int subsamp,
2688
                                unsigned char *dstBuf, int width, int pitch,
2689
                                int height, int pixelFormat, int flags)
2690
0
{
2691
0
  static const char FUNCTION_NAME[] = "tjDecodeYUVPlanes";
2692
0
  int retval = 0;
2693
2694
0
  GET_TJINSTANCE(handle, -1);
2695
2696
0
  if (subsamp < 0 || subsamp >= this->numSamp)
2697
0
    THROW("Invalid argument");
2698
2699
0
  this->subsamp = subsamp;
2700
0
  processFlags(handle, flags, DECOMPRESS);
2701
2702
0
  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
2703
0
                             height, pixelFormat);
2704
2705
0
bailout:
2706
0
  return retval;
2707
0
}
2708
2709
2710
/* TurboJPEG 3.0+ */
2711
DLLEXPORT int tj3DecodeYUV8(tjhandle handle, const unsigned char *srcBuf,
2712
                            int align, unsigned char *dstBuf, int width,
2713
                            int pitch, int height, int pixelFormat)
2714
2.13k
{
2715
2.13k
  static const char FUNCTION_NAME[] = "tj3DecodeYUV8";
2716
2.13k
  const unsigned char *srcPlanes[3];
2717
2.13k
  int pw0, ph0, strides[3], retval = -1;
2718
2719
2.13k
  GET_TJINSTANCE(handle, -1);
2720
2721
2.13k
  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || width <= 0 ||
2722
2.13k
      height <= 0)
2723
2.13k
    THROW("Invalid argument");
2724
2725
2.13k
  if (this->subsamp == TJSAMP_UNKNOWN)
2726
2.13k
    THROW("TJPARAM_SUBSAMP must be specified");
2727
2728
2.13k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2729
2.13k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2730
2.13k
  srcPlanes[0] = srcBuf;
2731
2.13k
  strides[0] = PAD(pw0, align);
2732
2.13k
  if (this->subsamp == TJSAMP_GRAY) {
2733
734
    strides[1] = strides[2] = 0;
2734
734
    srcPlanes[1] = srcPlanes[2] = NULL;
2735
1.40k
  } else {
2736
1.40k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2737
1.40k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2738
2739
1.40k
    strides[1] = strides[2] = PAD(pw1, align);
2740
1.40k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2741
1.40k
        (unsigned long long)INT_MAX ||
2742
1.40k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2743
1.40k
        (unsigned long long)INT_MAX)
2744
1.40k
      THROW("Image or row alignment is too large");
2745
1.40k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
2746
1.40k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
2747
1.40k
  }
2748
2749
2.13k
  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
2750
2.13k
                             height, pixelFormat);
2751
2752
0
bailout:
2753
0
  return retval;
2754
2.13k
}
2755
2756
/* TurboJPEG 1.4+ */
2757
DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
2758
                          int align, int subsamp, unsigned char *dstBuf,
2759
                          int width, int pitch, int height, int pixelFormat,
2760
                          int flags)
2761
0
{
2762
0
  static const char FUNCTION_NAME[] = "tjDecodeYUV";
2763
0
  int retval = -1;
2764
2765
0
  GET_TJINSTANCE(handle, -1);
2766
2767
0
  if (subsamp < 0 || subsamp >= this->numSamp)
2768
0
    THROW("Invalid argument");
2769
2770
0
  this->subsamp = subsamp;
2771
0
  processFlags(handle, flags, DECOMPRESS);
2772
2773
0
  return tj3DecodeYUV8(handle, srcBuf, align, dstBuf, width, pitch, height,
2774
0
                       pixelFormat);
2775
2776
0
bailout:
2777
0
  return retval;
2778
0
}
2779
2780
2781
/******************************** Transformer ********************************/
2782
2783
/* TurboJPEG 1.2+ */
2784
DLLEXPORT tjhandle tjInitTransform(void)
2785
0
{
2786
0
  return tj3Init(TJINIT_TRANSFORM);
2787
0
}
2788
2789
2790
static int getDstSubsamp(int srcSubsamp, const tjtransform *transform)
2791
15.8k
{
2792
15.8k
  int dstSubsamp;
2793
2794
15.8k
  if (!transform)
2795
0
    return srcSubsamp;
2796
2797
15.8k
  dstSubsamp = (transform->options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2798
2799
15.8k
  if (transform->op == TJXOP_TRANSPOSE || transform->op == TJXOP_TRANSVERSE ||
2800
11.4k
      transform->op == TJXOP_ROT90 || transform->op == TJXOP_ROT270) {
2801
11.4k
    if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2802
11.2k
    else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2803
11.2k
    else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2804
11.2k
    else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2805
11.2k
    else if (dstSubsamp == TJSAMP_410) dstSubsamp = TJSAMP_24;
2806
11.2k
    else if (dstSubsamp == TJSAMP_24) dstSubsamp = TJSAMP_410;
2807
11.4k
  }
2808
2809
15.8k
  return dstSubsamp;
2810
15.8k
}
2811
2812
static int getTransformedSpecs(tjhandle handle, int *width, int *height,
2813
                               int *subsamp, const tjtransform *transform,
2814
                               const char *FUNCTION_NAME)
2815
23.4k
{
2816
23.4k
  int retval = 0, dstWidth, dstHeight, dstSubsamp;
2817
2818
23.4k
  GET_TJINSTANCE(handle, -1);
2819
23.4k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2820
23.4k
    THROW("Instance has not been initialized for transformation");
2821
2822
23.4k
  if (!width || !height || !subsamp || !transform || *width < 1 ||
2823
23.4k
      *height < 1 || *subsamp < TJSAMP_UNKNOWN || *subsamp >= this->numSamp)
2824
23.4k
    THROW("Invalid argument");
2825
2826
23.4k
  dstWidth = *width;  dstHeight = *height;
2827
23.4k
  if (transform->op == TJXOP_TRANSPOSE || transform->op == TJXOP_TRANSVERSE ||
2828
16.0k
      transform->op == TJXOP_ROT90 || transform->op == TJXOP_ROT270) {
2829
14.8k
    dstWidth = *height;  dstHeight = *width;
2830
14.8k
  }
2831
23.4k
  dstSubsamp = getDstSubsamp(*subsamp, transform);
2832
2833
23.4k
  if (transform->options & TJXOPT_CROP) {
2834
7.44k
    int croppedWidth, croppedHeight;
2835
2836
7.44k
    if (transform->r.x < 0 || transform->r.y < 0 || transform->r.w < 0 ||
2837
7.44k
        transform->r.h < 0)
2838
7.44k
      THROW("Invalid cropping region");
2839
7.44k
    if (dstSubsamp == TJSAMP_UNKNOWN)
2840
7.44k
      THROW("Could not determine subsampling level of JPEG image");
2841
7.44k
    if ((transform->r.x % tjMCUWidth[dstSubsamp]) != 0 ||
2842
7.44k
        (transform->r.y % tjMCUHeight[dstSubsamp]) != 0)
2843
0
      THROWI("To crop this JPEG image, x must be a multiple of %d\n"
2844
7.44k
             "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
2845
7.44k
             tjMCUHeight[dstSubsamp]);
2846
7.44k
    if (transform->r.x >= dstWidth || transform->r.y >= dstHeight)
2847
7.44k
      THROW("The cropping region exceeds the destination image dimensions");
2848
7.44k
    croppedWidth = transform->r.w == 0 ? dstWidth - transform->r.x :
2849
7.44k
                                         transform->r.w;
2850
7.44k
    croppedHeight = transform->r.h == 0 ? dstHeight - transform->r.y :
2851
7.44k
                                          transform->r.h;
2852
7.44k
    if (transform->r.x + croppedWidth > dstWidth ||
2853
7.44k
        transform->r.y + croppedHeight > dstHeight)
2854
7.44k
      THROW("The cropping region exceeds the destination image dimensions");
2855
7.44k
    dstWidth = croppedWidth;  dstHeight = croppedHeight;
2856
7.44k
  }
2857
2858
23.4k
  *width = dstWidth;  *height = dstHeight;  *subsamp = dstSubsamp;
2859
2860
23.4k
bailout:
2861
23.4k
  return retval;
2862
23.4k
}
2863
2864
2865
/* TurboJPEG 3.1+ */
2866
DLLEXPORT size_t tj3TransformBufSize(tjhandle handle,
2867
                                     const tjtransform *transform)
2868
23.4k
{
2869
23.4k
  static const char FUNCTION_NAME[] = "tj3TransformBufSize";
2870
23.4k
  size_t retval = 0;
2871
23.4k
  int dstWidth, dstHeight, dstSubsamp;
2872
2873
23.4k
  GET_TJINSTANCE(handle, 0);
2874
23.4k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2875
23.4k
    THROWRV("Instance has not been initialized for transformation", 0);
2876
2877
23.4k
  if (transform == NULL)
2878
0
    THROWRV("Invalid argument", 0)
2879
2880
23.4k
  if (this->jpegWidth < 0 || this->jpegHeight < 0)
2881
23.4k
    THROWRV("JPEG header has not yet been read", 0);
2882
2883
23.4k
  dstWidth = this->jpegWidth;
2884
23.4k
  dstHeight = this->jpegHeight;
2885
23.4k
  dstSubsamp = this->subsamp;
2886
23.4k
  if (getTransformedSpecs(handle, &dstWidth, &dstHeight, &dstSubsamp,
2887
23.4k
                          transform, FUNCTION_NAME) == -1) {
2888
0
    retval = 0;
2889
0
    goto bailout;
2890
0
  }
2891
2892
23.4k
  retval = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
2893
23.4k
  if ((this->saveMarkers == 2 || this->saveMarkers == 4) &&
2894
23.4k
      !(transform->options & TJXOPT_COPYNONE))
2895
7.44k
    retval += this->decompICCSize;
2896
16.0k
  else
2897
16.0k
    retval += this->iccSize;
2898
2899
23.4k
bailout:
2900
23.4k
  return retval;
2901
23.4k
}
2902
2903
2904
/* TurboJPEG 3.0+ */
2905
DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
2906
                           size_t jpegSize, int n, unsigned char **dstBufs,
2907
                           size_t *dstSizes, const tjtransform *t)
2908
30.9k
{
2909
30.9k
  static const char FUNCTION_NAME[] = "tj3Transform";
2910
30.9k
  int retval = 0;
2911
2912
30.9k
#if TRANSFORMS_SUPPORTED
2913
2914
30.9k
  jpeg_transform_info *xinfo = NULL;
2915
30.9k
  jvirt_barray_ptr *srccoefs, *dstcoefs;
2916
30.9k
  int i, saveMarkers = 0, srcSubsamp;
2917
30.9k
  boolean alloc = TRUE;
2918
30.9k
  struct my_progress_mgr progress;
2919
2920
30.9k
  GET_INSTANCE(handle);
2921
30.9k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2922
30.9k
    THROW("Instance has not been initialized for transformation");
2923
2924
30.9k
  if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
2925
30.9k
      dstSizes == NULL || t == NULL)
2926
30.9k
    THROW("Invalid argument");
2927
2928
30.9k
  if (this->scanLimit) {
2929
30.9k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2930
30.9k
    progress.pub.progress_monitor = my_progress_monitor;
2931
30.9k
    progress.this = this;
2932
30.9k
    dinfo->progress = &progress.pub;
2933
30.9k
  } else
2934
0
    dinfo->progress = NULL;
2935
2936
30.9k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2937
2938
30.9k
  if ((xinfo =
2939
30.9k
       (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
2940
30.9k
    THROW("Memory allocation failure");
2941
30.9k
  memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
2942
2943
30.9k
  CATCH_LIBJPEG(this);
2944
2945
11.4k
  if (dinfo->global_state <= DSTATE_INHEADER)
2946
30.9k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2947
2948
49.7k
  for (i = 0; i < n; i++) {
2949
38.3k
    if (t[i].op < 0 || t[i].op >= TJ_NUMXOP)
2950
38.3k
      THROW("Invalid transform operation");
2951
38.3k
    xinfo[i].transform = xformtypes[t[i].op];
2952
38.3k
    xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
2953
38.3k
    xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
2954
38.3k
    xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
2955
38.3k
    xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
2956
38.3k
    if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
2957
38.3k
    else xinfo[i].slow_hflip = 0;
2958
2959
38.3k
    if (xinfo[i].crop) {
2960
7.44k
      if (t[i].r.x < 0 || t[i].r.y < 0 || t[i].r.w < 0 || t[i].r.h < 0)
2961
7.44k
        THROW("Invalid cropping region");
2962
7.44k
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
2963
7.44k
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
2964
7.44k
      if (t[i].r.w != 0) {
2965
7.44k
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
2966
7.44k
      } else
2967
0
        xinfo[i].crop_width = JCROP_UNSET;
2968
7.44k
      if (t[i].r.h != 0) {
2969
7.44k
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
2970
7.44k
      } else
2971
0
        xinfo[i].crop_height = JCROP_UNSET;
2972
7.44k
    }
2973
38.3k
    if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
2974
38.3k
  }
2975
2976
11.4k
  jcopy_markers_setup(dinfo, saveMarkers ?
2977
18.4E
                             (JCOPY_OPTION)this->saveMarkers : JCOPYOPT_NONE);
2978
11.4k
  if (dinfo->global_state <= DSTATE_INHEADER)
2979
30.9k
    jpeg_read_header(dinfo, TRUE);
2980
11.4k
  if (this->maxPixels &&
2981
0
      (unsigned long long)dinfo->image_width * dinfo->image_height >
2982
0
      (unsigned long long)this->maxPixels)
2983
11.4k
    THROW("Image is too large");
2984
11.4k
  srcSubsamp = getSubsamp(this);
2985
2986
49.7k
  for (i = 0; i < n; i++) {
2987
38.3k
    if (!jtransform_request_workspace(dinfo, &xinfo[i]))
2988
38.3k
      THROW("Transform is not perfect");
2989
2990
38.3k
    if (xinfo[i].crop) {
2991
7.44k
      int dstSubsamp = getDstSubsamp(srcSubsamp, &t[i]);
2992
2993
7.44k
      if (dstSubsamp == TJSAMP_UNKNOWN)
2994
7.44k
        THROW("Could not determine subsampling level of destination image");
2995
7.44k
      if ((t[i].r.x % tjMCUWidth[dstSubsamp]) != 0 ||
2996
7.44k
          (t[i].r.y % tjMCUHeight[dstSubsamp]) != 0)
2997
0
        THROWI("To crop this JPEG image, x must be a multiple of %d\n"
2998
7.44k
               "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
2999
7.44k
               tjMCUHeight[dstSubsamp]);
3000
7.44k
    }
3001
38.3k
  }
3002
3003
11.4k
  srccoefs = jpeg_read_coefficients(dinfo);
3004
3005
32.1k
  for (i = 0; i < n; i++) {
3006
20.7k
    if (this->noRealloc) alloc = FALSE;
3007
20.7k
    if (!(t[i].options & TJXOPT_NOOUTPUT))
3008
20.7k
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
3009
20.7k
    jpeg_copy_critical_parameters(dinfo, cinfo);
3010
20.7k
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
3011
20.7k
    if (this->optimize || t[i].options & TJXOPT_OPTIMIZE)
3012
2.98k
      cinfo->optimize_coding = TRUE;
3013
20.7k
#ifdef C_PROGRESSIVE_SUPPORTED
3014
20.7k
    if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE)
3015
7.84k
      jpeg_simple_progression(cinfo);
3016
20.7k
#endif
3017
20.7k
    if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) {
3018
3.85k
      cinfo->arith_code = TRUE;
3019
3.85k
      cinfo->optimize_coding = FALSE;
3020
3.85k
    }
3021
20.7k
    cinfo->restart_interval = this->restartIntervalBlocks;
3022
20.7k
    cinfo->restart_in_rows = this->restartIntervalRows;
3023
20.7k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
3024
17.6k
      JCOPY_OPTION copyOption = t[i].options & TJXOPT_COPYNONE ?
3025
6.96k
                                JCOPYOPT_NONE :
3026
17.6k
                                (JCOPY_OPTION)this->saveMarkers;
3027
3028
17.6k
      jpeg_write_coefficients(cinfo, dstcoefs);
3029
17.6k
      jcopy_markers_execute(dinfo, cinfo, copyOption);
3030
17.6k
      if (this->iccBuf != NULL && this->iccSize != 0 &&
3031
17.4k
          copyOption != JCOPYOPT_ALL && copyOption != JCOPYOPT_ICC)
3032
6.96k
        jpeg_write_icc_profile(cinfo, this->iccBuf,
3033
6.96k
                               (unsigned int)this->iccSize);
3034
17.6k
    } else
3035
3.07k
      jinit_c_master_control(cinfo, TRUE);
3036
20.7k
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
3037
20.7k
    if (t[i].customFilter) {
3038
3.85k
      int ci, y;
3039
3.85k
      JDIMENSION by;
3040
3041
10.7k
      for (ci = 0; ci < cinfo->num_components; ci++) {
3042
6.93k
        jpeg_component_info *compptr = &cinfo->comp_info[ci];
3043
6.93k
        tjregion arrayRegion = { 0, 0, 0, 0 };
3044
6.93k
        tjregion planeRegion = { 0, 0, 0, 0 };
3045
3046
6.93k
        arrayRegion.w = compptr->width_in_blocks * DCTSIZE;
3047
6.93k
        arrayRegion.h = DCTSIZE;
3048
6.93k
        planeRegion.w = compptr->width_in_blocks * DCTSIZE;
3049
6.93k
        planeRegion.h = compptr->height_in_blocks * DCTSIZE;
3050
3051
3.48M
        for (by = 0; by < compptr->height_in_blocks;
3052
3.47M
             by += compptr->v_samp_factor) {
3053
3.47M
          JBLOCKARRAY barray = (dinfo->mem->access_virt_barray)
3054
3.47M
            ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
3055
3.47M
             TRUE);
3056
3057
8.06M
          for (y = 0; y < compptr->v_samp_factor; y++) {
3058
4.58M
            if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
3059
4.58M
                                  i, (tjtransform *)&t[i]) == -1)
3060
4.58M
              THROW("Error in custom filter");
3061
4.58M
            arrayRegion.y += DCTSIZE;
3062
4.58M
          }
3063
3.47M
        }
3064
6.93k
      }
3065
3.85k
    }
3066
20.7k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
3067
20.7k
  }
3068
3069
11.4k
  jpeg_finish_decompress(dinfo);
3070
3071
30.9k
bailout:
3072
30.9k
  if (cinfo->global_state > CSTATE_START) {
3073
3.28k
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
3074
3.28k
    jpeg_abort_compress(cinfo);
3075
3.28k
  }
3076
30.9k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
3077
30.9k
  free(xinfo);
3078
30.9k
  if (this->jerr.warning) retval = -1;
3079
30.9k
  return retval;
3080
3081
#else /* TRANSFORMS_SUPPORTED */
3082
3083
  GET_TJINSTANCE(handle, -1)
3084
  THROW("Lossless transformations were disabled at build time")
3085
bailout:
3086
  return retval;
3087
3088
#endif
3089
11.4k
}
3090
3091
/* TurboJPEG 1.2+ */
3092
DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
3093
                          unsigned long jpegSize, int n,
3094
                          unsigned char **dstBufs, unsigned long *dstSizes,
3095
                          tjtransform *t, int flags)
3096
0
{
3097
0
  static const char FUNCTION_NAME[] = "tjTransform";
3098
0
  int i, retval = 0, srcSubsamp = -1;
3099
0
  size_t *sizes = NULL;
3100
3101
0
  GET_DINSTANCE(handle);
3102
0
  if ((this->init & DECOMPRESS) == 0)
3103
0
    THROW("Instance has not been initialized for decompression");
3104
3105
0
  if (n < 1 || dstSizes == NULL)
3106
0
    THROW("Invalid argument");
3107
3108
0
  CATCH_LIBJPEG(this);
3109
3110
0
  processFlags(handle, flags, COMPRESS);
3111
3112
0
  if (this->noRealloc) {
3113
0
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
3114
0
    jpeg_read_header(dinfo, TRUE);
3115
0
    srcSubsamp = getSubsamp(this);
3116
0
  }
3117
3118
0
  if ((sizes = (size_t *)malloc(n * sizeof(size_t))) == NULL)
3119
0
    THROW("Memory allocation failure");
3120
0
  for (i = 0; i < n; i++) {
3121
0
    sizes[i] = (size_t)dstSizes[i];
3122
0
    if (this->noRealloc) {
3123
0
      int dstWidth = dinfo->image_width, dstHeight = dinfo->image_height;
3124
0
      int dstSubsamp = srcSubsamp;
3125
3126
0
      if (getTransformedSpecs(handle, &dstWidth, &dstHeight, &dstSubsamp,
3127
0
                              &t[i], FUNCTION_NAME) == -1) {
3128
0
        retval = -1;
3129
0
        goto bailout;
3130
0
      }
3131
0
      sizes[i] = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
3132
0
    }
3133
0
  }
3134
0
  retval = tj3Transform(handle, jpegBuf, (size_t)jpegSize, n, dstBufs, sizes,
3135
0
                        t);
3136
0
  for (i = 0; i < n; i++)
3137
0
    dstSizes[i] = (unsigned long)sizes[i];
3138
3139
0
bailout:
3140
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
3141
0
  if (this->jerr.warning) retval = -1;
3142
0
  free(sizes);
3143
0
  return retval;
3144
0
}
3145
3146
3147
/*************************** Packed-Pixel Image I/O **************************/
3148
3149
/* tj3LoadImage*() is implemented in turbojpeg-mp.c */
3150
3151
/* TurboJPEG 2.0+ */
3152
DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
3153
                                     int align, int *height,
3154
                                     int *pixelFormat, int flags)
3155
0
{
3156
0
  tjhandle handle = NULL;
3157
0
  unsigned char *dstBuf = NULL;
3158
3159
0
  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) return NULL;
3160
3161
0
  processFlags(handle, flags, COMPRESS);
3162
3163
0
  dstBuf = tj3LoadImage8(handle, filename, width, align, height, pixelFormat);
3164
3165
0
  tj3Destroy(handle);
3166
0
  return dstBuf;
3167
0
}
3168
3169
3170
/* tj3SaveImage*() is implemented in turbojpeg-mp.c */
3171
3172
/* TurboJPEG 2.0+ */
3173
DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
3174
                          int width, int pitch, int height, int pixelFormat,
3175
                          int flags)
3176
0
{
3177
0
  tjhandle handle = NULL;
3178
0
  int retval = -1;
3179
3180
0
  if ((handle = tj3Init(TJINIT_DECOMPRESS)) == NULL) return -1;
3181
3182
0
  processFlags(handle, flags, DECOMPRESS);
3183
3184
0
  retval = tj3SaveImage8(handle, filename, buffer, width, pitch, height,
3185
0
                         pixelFormat);
3186
3187
0
  tj3Destroy(handle);
3188
0
  return retval;
3189
0
}