Coverage Report

Created: 2026-05-11 07:55

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