Coverage Report

Created: 2026-08-31 07:19

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