Coverage Report

Created: 2026-04-28 06:57

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.66M
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
55
328k
#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
444k
{
78
444k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
79
80
444k
  (*cinfo->err->output_message) (cinfo);
81
444k
  longjmp(myerr->setjmp_buffer, 1);
82
444k
}
83
84
/* Based on output_message() in jerror.c */
85
86
static void my_output_message(j_common_ptr cinfo)
87
336k
{
88
336k
  (*cinfo->err->format_message) (cinfo, errStr);
89
336k
}
90
91
static void my_emit_message(j_common_ptr cinfo, int msg_level)
92
856M
{
93
856M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
94
95
856M
  myerr->emit_message(cinfo, msg_level);
96
856M
  if (msg_level < 0) {
97
576M
    myerr->warning = TRUE;
98
576M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
99
576M
  }
100
856M
}
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
539M
{
154
539M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
155
539M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
156
157
539M
  if (dinfo->is_decompressor) {
158
539M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
159
160
539M
    if (scan_no > myprog->this->scanLimit) {
161
2.74k
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
162
2.74k
               "Progressive JPEG image has more than %d scans",
163
2.74k
               myprog->this->scanLimit);
164
2.74k
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
165
2.74k
               "Progressive JPEG image has more than %d scans",
166
2.74k
               myprog->this->scanLimit);
167
2.74k
      myprog->this->isInstanceError = TRUE;
168
2.74k
      myerr->warning = FALSE;
169
2.74k
      longjmp(myerr->setjmp_buffer, 1);
170
2.74k
    }
171
539M
  }
172
539M
}
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.13M
#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
614k
#define CATCH_LIBJPEG(this) { \
279
614k
  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
614k
}
284
285
#define GET_INSTANCE(handle) \
286
16.5k
  tjinstance *this = (tjinstance *)handle; \
287
16.5k
  j_compress_ptr cinfo = NULL; \
288
16.5k
  j_decompress_ptr dinfo = NULL; \
289
16.5k
  \
290
16.5k
  if (!this) { \
291
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
292
0
    return -1; \
293
0
  } \
294
16.5k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
295
16.5k
  this->jerr.warning = FALSE; \
296
16.5k
  this->isInstanceError = FALSE;
297
298
#define GET_CINSTANCE(handle) \
299
89.2k
  tjinstance *this = (tjinstance *)handle; \
300
89.2k
  j_compress_ptr cinfo = NULL; \
301
89.2k
  \
302
89.2k
  if (!this) { \
303
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
304
0
    return -1; \
305
0
  } \
306
89.2k
  cinfo = &this->cinfo; \
307
89.2k
  this->jerr.warning = FALSE; \
308
89.2k
  this->isInstanceError = FALSE;
309
310
#define GET_DINSTANCE(handle) \
311
173k
  tjinstance *this = (tjinstance *)handle; \
312
173k
  j_decompress_ptr dinfo = NULL; \
313
173k
  \
314
173k
  if (!this) { \
315
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
316
0
    return -1; \
317
0
  } \
318
173k
  dinfo = &this->dinfo; \
319
173k
  this->jerr.warning = FALSE; \
320
173k
  this->isInstanceError = FALSE;
321
322
#define GET_TJINSTANCE(handle, errorReturn) \
323
1.29M
  tjinstance *this = (tjinstance *)handle; \
324
1.29M
  \
325
1.29M
  if (!this) { \
326
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
327
0
    return errorReturn; \
328
0
  } \
329
1.29M
  this->jerr.warning = FALSE; \
330
1.29M
  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
257k
{
353
257k
  int colorspace = yuv ? -1 : this->colorspace;
354
355
257k
  this->cinfo.in_color_space = pf2cs[pixelFormat];
356
257k
  this->cinfo.input_components = tjPixelSize[pixelFormat];
357
257k
  jpeg_set_defaults(&this->cinfo);
358
359
257k
  this->cinfo.restart_interval = this->restartIntervalBlocks;
360
257k
  this->cinfo.restart_in_rows = this->restartIntervalRows;
361
257k
  this->cinfo.X_density = (UINT16)this->xDensity;
362
257k
  this->cinfo.Y_density = (UINT16)this->yDensity;
363
257k
  this->cinfo.density_unit = (UINT8)this->densityUnits;
364
257k
  this->cinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
365
366
257k
  if (this->lossless && !yuv) {
367
82.8k
#ifdef C_LOSSLESS_SUPPORTED
368
82.8k
    jpeg_enable_lossless(&this->cinfo, this->losslessPSV, this->losslessPt);
369
82.8k
#endif
370
82.8k
    return;
371
82.8k
  }
372
373
174k
  jpeg_set_quality(&this->cinfo, this->quality, TRUE);
374
174k
  this->cinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
375
376
174k
  switch (colorspace) {
377
10.4k
  case TJCS_RGB:
378
10.4k
    jpeg_set_colorspace(&this->cinfo, JCS_RGB);  break;
379
18.2k
  case TJCS_YCbCr:
380
18.2k
    jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);  break;
381
14.1k
  case TJCS_GRAY:
382
14.1k
    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.1k
  case TJCS_YCCK:
386
10.1k
    jpeg_set_colorspace(&this->cinfo, JCS_YCCK);  break;
387
121k
  default:
388
121k
    if (this->subsamp == TJSAMP_GRAY)
389
40.0k
      jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);
390
81.3k
    else if (pixelFormat == TJPF_CMYK)
391
4.07k
      jpeg_set_colorspace(&this->cinfo, JCS_YCCK);
392
77.2k
    else
393
77.2k
      jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);
394
174k
  }
395
396
174k
  if (this->cinfo.data_precision == 8)
397
126k
    this->cinfo.optimize_coding = this->optimize;
398
174k
#ifdef C_PROGRESSIVE_SUPPORTED
399
174k
  if (this->progressive) jpeg_simple_progression(&this->cinfo);
400
174k
#endif
401
174k
  this->cinfo.arith_code = this->arithmetic;
402
403
174k
  this->cinfo.comp_info[0].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
404
174k
  this->cinfo.comp_info[1].h_samp_factor = 1;
405
174k
  this->cinfo.comp_info[2].h_samp_factor = 1;
406
174k
  if (this->cinfo.num_components > 3)
407
14.2k
    this->cinfo.comp_info[3].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
408
174k
  this->cinfo.comp_info[0].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
409
174k
  this->cinfo.comp_info[1].v_samp_factor = 1;
410
174k
  this->cinfo.comp_info[2].v_samp_factor = 1;
411
174k
  if (this->cinfo.num_components > 3)
412
14.2k
    this->cinfo.comp_info[3].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
413
174k
}
414
415
416
static int getSubsamp(j_decompress_ptr dinfo)
417
275k
{
418
275k
  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
275k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
425
123k
    return TJSAMP_GRAY;
426
427
833k
  for (i = 0; i < TJ_NUMSAMP; i++) {
428
769k
    if (i == TJSAMP_GRAY) continue;
429
430
691k
    if (dinfo->num_components == 3 ||
431
76.7k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
432
69.6k
          dinfo->jpeg_color_space == JCS_CMYK) &&
433
681k
         dinfo->num_components == 4)) {
434
681k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
435
290k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
436
135k
        int match = 0;
437
438
417k
        for (k = 1; k < dinfo->num_components; k++) {
439
281k
          int href = 1, vref = 1;
440
441
281k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
442
278k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
443
9.82k
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
444
9.82k
          }
445
281k
          if (dinfo->comp_info[k].h_samp_factor == href &&
446
241k
              dinfo->comp_info[k].v_samp_factor == vref)
447
197k
            match++;
448
281k
        }
449
135k
        if (match == dinfo->num_components - 1) {
450
82.4k
          retval = i;  break;
451
82.4k
        }
452
135k
      }
453
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
454
         in non-standard ways. */
455
598k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
456
353k
          dinfo->comp_info[0].v_samp_factor == 2 &&
457
169k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
458
76.0k
        int match = 0;
459
460
230k
        for (k = 1; k < dinfo->num_components; k++) {
461
154k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
462
463
154k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
464
153k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
465
2.08k
            href = vref = 2;
466
2.08k
          }
467
154k
          if (dinfo->comp_info[k].h_samp_factor == href &&
468
131k
              dinfo->comp_info[k].v_samp_factor == vref)
469
13.6k
            match++;
470
154k
        }
471
76.0k
        if (match == dinfo->num_components - 1) {
472
4.70k
          retval = i;  break;
473
4.70k
        }
474
76.0k
      }
475
      /* Handle 4:4:4 images whose sampling factors are specified in
476
         non-standard ways. */
477
593k
      if (dinfo->comp_info[0].h_samp_factor *
478
593k
          dinfo->comp_info[0].v_samp_factor <=
479
593k
          D_MAX_BLOCKS_IN_MCU / 3 && i == TJSAMP_444) {
480
53.2k
        int match = 0;
481
164k
        for (k = 1; k < dinfo->num_components; k++) {
482
113k
          if (dinfo->comp_info[k].h_samp_factor ==
483
113k
              dinfo->comp_info[0].h_samp_factor &&
484
28.1k
              dinfo->comp_info[k].v_samp_factor ==
485
28.1k
              dinfo->comp_info[0].v_samp_factor)
486
10.0k
            match++;
487
113k
          if (match == dinfo->num_components - 1) {
488
2.09k
            retval = i;  break;
489
2.09k
          }
490
113k
        }
491
53.2k
      }
492
593k
    }
493
691k
  }
494
151k
  return retval;
495
275k
}
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
96.3k
  case JCS_GRAYSCALE:  this->colorspace = TJCS_GRAY;  break;
506
49.4k
  case JCS_RGB:        this->colorspace = TJCS_RGB;  break;
507
73.0k
  case JCS_YCbCr:      this->colorspace = TJCS_YCbCr;  break;
508
6.52k
  case JCS_CMYK:       this->colorspace = TJCS_CMYK;  break;
509
1.05k
  case JCS_YCCK:       this->colorspace = TJCS_YCCK;  break;
510
587
  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
296k
{
558
296k
  static const char FUNCTION_NAME[] = "tj3Init";
559
296k
  tjinstance *this = NULL;
560
296k
  tjhandle retval = NULL;
561
562
296k
  if (initType < 0 || initType >= TJ_NUMINIT)
563
296k
    THROWG("Invalid argument", NULL);
564
565
296k
  if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL)
566
296k
    THROWG("Memory allocation failure", NULL);
567
296k
  memset(this, 0, sizeof(tjinstance));
568
296k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
569
570
296k
  this->quality = -1;
571
296k
  this->subsamp = TJSAMP_UNKNOWN;
572
296k
  this->jpegWidth = -1;
573
296k
  this->jpegHeight = -1;
574
296k
  this->precision = 8;
575
296k
  this->colorspace = -1;
576
296k
  this->losslessPSV = 1;
577
296k
  this->xDensity = 1;
578
296k
  this->yDensity = 1;
579
296k
  this->scalingFactor = TJUNSCALED;
580
581
296k
  switch (initType) {
582
259k
  case TJINIT_COMPRESS:  return _tjInitCompress(this);
583
26.4k
  case TJINIT_DECOMPRESS:  return _tjInitDecompress(this);
584
11.4k
  case TJINIT_TRANSFORM:
585
11.4k
    retval = _tjInitCompress(this);
586
11.4k
    if (!retval) return NULL;
587
11.4k
    retval = _tjInitDecompress(this);
588
11.4k
    return retval;
589
296k
  }
590
591
0
bailout:
592
0
  return retval;
593
296k
}
594
595
596
/* TurboJPEG 3+ */
597
DLLEXPORT void tj3Destroy(tjhandle handle)
598
613k
{
599
613k
  tjinstance *this = (tjinstance *)handle;
600
613k
  j_compress_ptr cinfo = NULL;
601
613k
  j_decompress_ptr dinfo = NULL;
602
603
613k
  if (!this) return;
604
605
613k
  cinfo = &this->cinfo;  dinfo = &this->dinfo;
606
613k
  this->jerr.warning = FALSE;
607
613k
  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
613k
  if (setjmp(this->jerr.setjmp_buffer)) goto destroy_decompress;
612
613k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
613
613k
destroy_decompress:
614
613k
  if (setjmp(this->jerr.setjmp_buffer)) goto bailout;
615
613k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
616
613k
bailout:
617
613k
  free(this);
618
613k
}
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
177k
{
640
177k
  tjinstance *this = (tjinstance *)handle;
641
642
177k
  if (this && this->isInstanceError) {
643
64.9k
    this->isInstanceError = FALSE;
644
64.9k
    return this->errStr;
645
64.9k
  } else
646
112k
    return errStr;
647
177k
}
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
372k
#define SET_PARAM(field, minValue, maxValue) { \
679
372k
  if (value < minValue || (maxValue > 0 && value > maxValue)) \
680
372k
    THROW("Parameter value out of range"); \
681
372k
  this->field = value; \
682
372k
}
683
684
618k
#define SET_BOOL_PARAM(field) { \
685
618k
  if (value < 0 || value > 1) \
686
618k
    THROW("Parameter value out of range"); \
687
618k
  this->field = (boolean)value; \
688
618k
}
689
690
/* TurboJPEG 3+ */
691
DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
692
990k
{
693
990k
  static const char FUNCTION_NAME[] = "tj3Set";
694
990k
  int retval = 0;
695
696
990k
  GET_TJINSTANCE(handle, -1);
697
698
990k
  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
120k
  case TJPARAM_NOREALLOC:
706
120k
    if (!(this->init & COMPRESS))
707
120k
      THROW("TJPARAM_NOREALLOC is not applicable to decompression instances.");
708
120k
    SET_BOOL_PARAM(noRealloc);
709
120k
    break;
710
39.3k
  case TJPARAM_QUALITY:
711
39.3k
    if (!(this->init & COMPRESS))
712
39.3k
      THROW("TJPARAM_QUALITY is not applicable to decompression instances.");
713
39.3k
    SET_PARAM(quality, 1, 100);
714
39.3k
    break;
715
39.3k
  case TJPARAM_SUBSAMP:
716
39.3k
    SET_PARAM(subsamp, 0, TJ_NUMSAMP - 1);
717
39.3k
    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
34.1k
  case TJPARAM_FASTUPSAMPLE:
739
34.1k
    if (!(this->init & DECOMPRESS))
740
34.1k
      THROW("TJPARAM_FASTUPSAMPLE is not applicable to compression instances.");
741
34.1k
    SET_BOOL_PARAM(fastUpsample);
742
34.1k
    break;
743
97.6k
  case TJPARAM_FASTDCT:
744
97.6k
    SET_BOOL_PARAM(fastDCT);
745
97.6k
    break;
746
55.1k
  case TJPARAM_OPTIMIZE:
747
55.1k
    if (!(this->init & COMPRESS))
748
55.1k
      THROW("TJPARAM_OPTIMIZE is not applicable to decompression instances.");
749
55.1k
    SET_BOOL_PARAM(optimize);
750
55.1k
    break;
751
75.9k
  case TJPARAM_PROGRESSIVE:
752
75.9k
    if (!(this->init & COMPRESS))
753
75.9k
      THROW("TJPARAM_PROGRESSIVE is read-only in decompression instances.");
754
75.9k
    SET_BOOL_PARAM(progressive);
755
75.9k
    break;
756
43.2k
  case TJPARAM_SCANLIMIT:
757
43.2k
    if (!(this->init & DECOMPRESS))
758
43.2k
      THROW("TJPARAM_SCANLIMIT is not applicable to compression instances.");
759
43.2k
    SET_PARAM(scanLimit, 0, -1);
760
43.2k
    break;
761
75.9k
  case TJPARAM_ARITHMETIC:
762
75.9k
    if (!(this->init & COMPRESS))
763
75.9k
      THROW("TJPARAM_ARITHMETIC is read-only in decompression instances.");
764
75.9k
    SET_BOOL_PARAM(arithmetic);
765
75.9k
    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
22.0k
  case TJPARAM_RESTARTBLOCKS:
782
22.0k
    if (!(this->init & COMPRESS))
783
22.0k
      THROW("TJPARAM_RESTARTBLOCKS is not applicable to decompression instances.");
784
22.0k
    SET_PARAM(restartIntervalBlocks, 0, 65535);
785
22.0k
    if (value != 0) this->restartIntervalRows = 0;
786
22.0k
    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
990k
  }
817
818
990k
bailout:
819
990k
  return retval;
820
990k
}
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.3k
  case TJPARAM_NOREALLOC:
835
41.3k
    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.4k
  case TJPARAM_JPEGWIDTH:
841
19.4k
    return this->jpegWidth;
842
19.4k
  case TJPARAM_JPEGHEIGHT:
843
19.4k
    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.7k
  case TJPARAM_LOSSLESS:
861
38.7k
    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
419k
{
894
419k
  return MALLOC(bytes);
895
419k
}
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
890k
{
907
890k
  free(buf);
908
890k
}
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
323k
{
920
323k
  static const char FUNCTION_NAME[] = "tj3JPEGBufSize";
921
323k
  unsigned long long retval = 0;
922
323k
  int mcuw, mcuh, chromasf;
923
924
323k
  if (width < 1 || height < 1 || jpegSubsamp < TJSAMP_UNKNOWN ||
925
323k
      jpegSubsamp >= TJ_NUMSAMP)
926
323k
    THROWG("Invalid argument", 0);
927
928
323k
  if (jpegSubsamp == TJSAMP_UNKNOWN)
929
16.8k
    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
323k
  mcuw = tjMCUWidth[jpegSubsamp];
935
323k
  mcuh = tjMCUHeight[jpegSubsamp];
936
323k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
937
323k
  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
323k
bailout:
944
323k
  return (size_t)retval;
945
323k
}
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
83.7k
{
988
83.7k
  static const char FUNCTION_NAME[] = "tj3YUVBufSize";
989
83.7k
  unsigned long long retval = 0;
990
83.7k
  int nc, i;
991
992
83.7k
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
993
83.1k
    THROWG("Invalid argument", 0);
994
995
83.1k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
996
271k
  for (i = 0; i < nc; i++) {
997
188k
    int pw = tj3YUVPlaneWidth(i, width, subsamp);
998
188k
    int stride = PAD(pw, align);
999
188k
    int ph = tj3YUVPlaneHeight(i, height, subsamp);
1000
1001
188k
    if (pw == 0 || ph == 0) return 0;
1002
188k
    else retval += (unsigned long long)stride * ph;
1003
188k
  }
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
83.7k
bailout:
1010
83.7k
  return (size_t)retval;
1011
83.1k
}
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
491k
{
1074
491k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneWidth";
1075
491k
  unsigned long long pw, retval = 0;
1076
491k
  int nc;
1077
1078
491k
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1079
491k
    THROWG("Invalid argument", 0);
1080
491k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1081
491k
  if (componentID < 0 || componentID >= nc)
1082
491k
    THROWG("Invalid argument", 0);
1083
1084
491k
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
1085
491k
  if (componentID == 0)
1086
251k
    retval = pw;
1087
239k
  else
1088
239k
    retval = pw * 8 / tjMCUWidth[subsamp];
1089
1090
491k
  if (retval > (unsigned long long)INT_MAX)
1091
491k
    THROWG("Width is too large", 0);
1092
1093
491k
bailout:
1094
491k
  return (int)retval;
1095
491k
}
1096
1097
/* TurboJPEG 1.4+ */
1098
DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
1099
24.1k
{
1100
24.1k
  int retval = tj3YUVPlaneWidth(componentID, width, subsamp);
1101
24.1k
  return (retval == 0) ? -1 : retval;
1102
24.1k
}
1103
1104
1105
/* TurboJPEG 3+ */
1106
DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp)
1107
491k
{
1108
491k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneHeight";
1109
491k
  unsigned long long ph, retval = 0;
1110
491k
  int nc;
1111
1112
491k
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1113
491k
    THROWG("Invalid argument", 0);
1114
491k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1115
491k
  if (componentID < 0 || componentID >= nc)
1116
491k
    THROWG("Invalid argument", 0);
1117
1118
491k
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
1119
491k
  if (componentID == 0)
1120
251k
    retval = ph;
1121
239k
  else
1122
239k
    retval = ph * 8 / tjMCUHeight[subsamp];
1123
1124
491k
  if (retval > (unsigned long long)INT_MAX)
1125
491k
    THROWG("Height is too large", 0);
1126
1127
491k
bailout:
1128
491k
  return (int)retval;
1129
491k
}
1130
1131
/* TurboJPEG 1.4+ */
1132
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
1133
24.1k
{
1134
24.1k
  int retval = tj3YUVPlaneHeight(componentID, height, subsamp);
1135
24.1k
  return (retval == 0) ? -1 : retval;
1136
24.1k
}
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.7k
#define BITS_IN_JSAMPLE  8
1180
#include "turbojpeg-mp.c"
1181
#undef BITS_IN_JSAMPLE
1182
46.0k
#define BITS_IN_JSAMPLE  12
1183
#include "turbojpeg-mp.c"
1184
#undef BITS_IN_JSAMPLE
1185
14.3k
#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.5k
{
1249
11.5k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUVPlanes8";
1250
11.5k
  int i, row, retval = 0;
1251
11.5k
  boolean alloc = TRUE;
1252
11.5k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1253
11.5k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1254
11.5k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1255
11.5k
  JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1256
1257
11.5k
  GET_CINSTANCE(handle)
1258
1259
127k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1260
115k
    tmpbuf[i] = NULL;  inbuf[i] = NULL;
1261
115k
  }
1262
1263
11.5k
  if ((this->init & COMPRESS) == 0)
1264
11.5k
    THROW("Instance has not been initialized for compression");
1265
1266
11.5k
  if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
1267
11.5k
      jpegBuf == NULL || jpegSize == NULL)
1268
11.5k
    THROW("Invalid argument");
1269
11.5k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1270
11.5k
    THROW("Invalid argument");
1271
1272
11.5k
  if (this->quality == -1)
1273
11.5k
    THROW("TJPARAM_QUALITY must be specified");
1274
11.5k
  if (this->subsamp == TJSAMP_UNKNOWN)
1275
11.5k
    THROW("TJPARAM_SUBSAMP must be specified");
1276
1277
11.5k
  CATCH_LIBJPEG(this);
1278
1279
11.5k
  cinfo->image_width = width;
1280
11.5k
  cinfo->image_height = height;
1281
11.5k
  cinfo->data_precision = 8;
1282
1283
11.5k
  if (this->noRealloc) {
1284
11.5k
    alloc = FALSE;  *jpegSize = tj3JPEGBufSize(width, height, this->subsamp);
1285
11.5k
  }
1286
11.5k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1287
11.5k
  setCompDefaults(this, TJPF_RGB, TRUE);
1288
11.5k
  cinfo->raw_data_in = TRUE;
1289
1290
11.5k
  jpeg_start_compress(cinfo, TRUE);
1291
38.9k
  for (i = 0; i < cinfo->num_components; i++) {
1292
27.3k
    jpeg_component_info *compptr = &cinfo->comp_info[i];
1293
27.3k
    int ih;
1294
1295
27.3k
    iw[i] = compptr->width_in_blocks * DCTSIZE;
1296
27.3k
    ih = compptr->height_in_blocks * DCTSIZE;
1297
27.3k
    pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
1298
27.3k
            compptr->h_samp_factor / cinfo->max_h_samp_factor;
1299
27.3k
    ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
1300
27.3k
            compptr->v_samp_factor / cinfo->max_v_samp_factor;
1301
27.3k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1302
27.3k
    th[i] = compptr->v_samp_factor * DCTSIZE;
1303
27.3k
    tmpbufsize += iw[i] * th[i];
1304
27.3k
    if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1305
27.3k
      THROW("Memory allocation failure");
1306
27.3k
    ptr = (JSAMPLE *)srcPlanes[i];
1307
81.6M
    for (row = 0; row < ph[i]; row++) {
1308
81.6M
      inbuf[i][row] = ptr;
1309
81.6M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1310
81.6M
    }
1311
27.3k
  }
1312
11.5k
  if (usetmpbuf) {
1313
11.4k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1314
11.4k
      THROW("Memory allocation failure");
1315
11.4k
    ptr = _tmpbuf;
1316
38.7k
    for (i = 0; i < cinfo->num_components; i++) {
1317
27.2k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1318
27.2k
        THROW("Memory allocation failure");
1319
260k
      for (row = 0; row < th[i]; row++) {
1320
233k
        tmpbuf[i][row] = ptr;
1321
233k
        ptr += iw[i];
1322
233k
      }
1323
27.2k
    }
1324
11.4k
  }
1325
1326
11.5k
  CATCH_LIBJPEG(this);
1327
1328
4.31M
  for (row = 0; row < (int)cinfo->image_height;
1329
4.30M
       row += cinfo->max_v_samp_factor * DCTSIZE) {
1330
4.30M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1331
4.30M
    int crow[MAX_COMPONENTS];
1332
1333
14.1M
    for (i = 0; i < cinfo->num_components; i++) {
1334
9.82M
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1335
1336
9.82M
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1337
9.82M
      if (usetmpbuf) {
1338
9.82M
        int j, k;
1339
1340
91.4M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1341
81.6M
          memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1342
          /* Duplicate last sample in row to fill out MCU */
1343
619M
          for (k = pw[i]; k < iw[i]; k++)
1344
537M
            tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1345
81.6M
        }
1346
        /* Duplicate last row to fill out MCU */
1347
9.97M
        for (j = ph[i] - crow[i]; j < th[i]; j++)
1348
148k
          memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1349
9.82M
        yuvptr[i] = tmpbuf[i];
1350
9.82M
      } else
1351
366
        yuvptr[i] = &inbuf[i][crow[i]];
1352
9.82M
    }
1353
4.30M
    jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1354
4.30M
  }
1355
11.5k
  jpeg_finish_compress(cinfo);
1356
1357
11.5k
bailout:
1358
11.5k
  if (cinfo->global_state > CSTATE_START && alloc)
1359
0
    (*cinfo->dest->term_destination) (cinfo);
1360
11.5k
  if (cinfo->global_state > CSTATE_START || retval == -1)
1361
0
    jpeg_abort_compress(cinfo);
1362
127k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1363
115k
    free(tmpbuf[i]);
1364
115k
    free(inbuf[i]);
1365
115k
  }
1366
11.5k
  free(_tmpbuf);
1367
11.5k
  if (this->jerr.warning) retval = -1;
1368
11.5k
  return retval;
1369
11.5k
}
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.3k
{
1410
36.3k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUV8";
1411
36.3k
  const unsigned char *srcPlanes[3];
1412
36.3k
  int pw0, ph0, strides[3], retval = -1;
1413
1414
36.3k
  GET_TJINSTANCE(handle, -1);
1415
1416
36.3k
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1417
36.3k
      height <= 0)
1418
36.3k
    THROW("Invalid argument");
1419
1420
36.3k
  if (this->subsamp == TJSAMP_UNKNOWN)
1421
36.3k
    THROW("TJPARAM_SUBSAMP must be specified");
1422
1423
36.3k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1424
36.3k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1425
36.3k
  srcPlanes[0] = srcBuf;
1426
36.3k
  strides[0] = PAD(pw0, align);
1427
36.3k
  if (this->subsamp == TJSAMP_GRAY) {
1428
12.2k
    strides[1] = strides[2] = 0;
1429
12.2k
    srcPlanes[1] = srcPlanes[2] = NULL;
1430
24.1k
  } else {
1431
24.1k
    int pw1 = tjPlaneWidth(1, width, this->subsamp);
1432
24.1k
    int ph1 = tjPlaneHeight(1, height, this->subsamp);
1433
1434
24.1k
    strides[1] = strides[2] = PAD(pw1, align);
1435
24.1k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1436
24.1k
        (unsigned long long)INT_MAX ||
1437
24.1k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1438
24.1k
        (unsigned long long)INT_MAX)
1439
24.1k
      THROW("Image or row alignment is too large");
1440
24.1k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1441
24.1k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1442
24.1k
  }
1443
1444
36.3k
  return tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
1445
36.3k
                                   jpegBuf, jpegSize);
1446
1447
0
bailout:
1448
0
  return retval;
1449
36.3k
}
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.3k
{
1487
36.3k
  static const char FUNCTION_NAME[] = "tj3EncodeYUVPlanes8";
1488
36.3k
  JSAMPROW *row_pointer = NULL;
1489
36.3k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
1490
36.3k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
1491
36.3k
  JSAMPROW *outbuf[MAX_COMPONENTS];
1492
36.3k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1493
36.3k
  JSAMPLE *ptr;
1494
36.3k
  jpeg_component_info *compptr;
1495
1496
36.3k
  GET_CINSTANCE(handle)
1497
1498
399k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1499
363k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
1500
363k
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
1501
363k
  }
1502
1503
36.3k
  if ((this->init & COMPRESS) == 0)
1504
36.3k
    THROW("Instance has not been initialized for compression");
1505
1506
36.3k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1507
36.3k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
1508
36.3k
      !dstPlanes[0])
1509
36.3k
    THROW("Invalid argument");
1510
36.3k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1511
36.3k
    THROW("Invalid argument");
1512
1513
36.3k
  if (this->subsamp == TJSAMP_UNKNOWN)
1514
36.3k
    THROW("TJPARAM_SUBSAMP must be specified");
1515
36.3k
  if (pixelFormat == TJPF_CMYK)
1516
36.3k
    THROW("Cannot generate YUV images from packed-pixel CMYK images");
1517
1518
36.3k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1519
0
  else if (pitch < width * tjPixelSize[pixelFormat])
1520
36.3k
    THROW("Invalid argument");
1521
1522
36.3k
  CATCH_LIBJPEG(this);
1523
1524
36.3k
  cinfo->image_width = width;
1525
36.3k
  cinfo->image_height = height;
1526
36.3k
  cinfo->data_precision = 8;
1527
1528
36.3k
  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.3k
  if (cinfo->global_state != CSTATE_START)
1535
36.3k
    THROW("libjpeg API is in the wrong state");
1536
36.3k
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
1537
36.3k
  jinit_c_master_control(cinfo, FALSE);
1538
36.3k
  jinit_color_converter(cinfo);
1539
36.3k
  jinit_downsampler(cinfo);
1540
36.3k
  (*cinfo->cconvert->start_pass) (cinfo);
1541
1542
36.3k
  pw0 = PAD(width, cinfo->max_h_samp_factor);
1543
36.3k
  ph0 = PAD(height, cinfo->max_v_samp_factor);
1544
1545
36.3k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1546
36.3k
    THROW("Memory allocation failure");
1547
103M
  for (i = 0; i < height; i++) {
1548
103M
    if (this->bottomUp)
1549
17.1M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
1550
86.2M
    else
1551
86.2M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
1552
103M
  }
1553
36.3k
  if (height < ph0)
1554
6.08k
    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.5k
    compptr = &cinfo->comp_info[i];
1558
84.5k
    _tmpbuf[i] = (JSAMPLE *)MALLOC(
1559
84.5k
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1560
84.5k
          compptr->h_samp_factor, 32) *
1561
84.5k
      cinfo->max_v_samp_factor + 32);
1562
84.5k
    if (!_tmpbuf[i])
1563
84.5k
      THROW("Memory allocation failure");
1564
84.5k
    tmpbuf[i] =
1565
84.5k
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
1566
84.5k
    if (!tmpbuf[i])
1567
84.5k
      THROW("Memory allocation failure");
1568
187k
    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.5k
    _tmpbuf2[i] =
1577
84.5k
      (JSAMPLE *)MALLOC(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1578
84.5k
                        compptr->v_samp_factor + 32);
1579
84.5k
    if (!_tmpbuf2[i])
1580
84.5k
      THROW("Memory allocation failure");
1581
84.5k
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1582
84.5k
    if (!tmpbuf2[i])
1583
84.5k
      THROW("Memory allocation failure");
1584
175k
    for (row = 0; row < compptr->v_samp_factor; row++) {
1585
90.6k
      unsigned char *_tmpbuf2_aligned =
1586
90.6k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
1587
1588
90.6k
      tmpbuf2[i][row] =
1589
90.6k
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1590
90.6k
    }
1591
84.5k
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
1592
84.5k
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1593
84.5k
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1594
84.5k
    if (!outbuf[i])
1595
84.5k
      THROW("Memory allocation failure");
1596
84.5k
    ptr = dstPlanes[i];
1597
224M
    for (row = 0; row < ph[i]; row++) {
1598
224M
      outbuf[i][row] = ptr;
1599
224M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1600
224M
    }
1601
84.5k
  }
1602
1603
36.3k
  CATCH_LIBJPEG(this);
1604
1605
94.7M
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
1606
94.6M
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
1607
94.6M
                                       cinfo->max_v_samp_factor);
1608
94.6M
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
1609
310M
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
1610
215M
         i++, compptr++)
1611
215M
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
1612
215M
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
1613
215M
        compptr->v_samp_factor, pw[i]);
1614
94.6M
  }
1615
36.3k
  cinfo->next_scanline += height;
1616
36.3k
  jpeg_abort_compress(cinfo);
1617
1618
36.3k
bailout:
1619
36.3k
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1620
36.3k
  free(row_pointer);
1621
399k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1622
363k
    free(tmpbuf[i]);
1623
363k
    free(_tmpbuf[i]);
1624
363k
    free(tmpbuf2[i]);
1625
363k
    free(_tmpbuf2[i]);
1626
363k
    free(outbuf[i]);
1627
363k
  }
1628
36.3k
  if (this->jerr.warning) retval = -1;
1629
36.3k
  return retval;
1630
36.3k
}
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.3k
{
1662
36.3k
  static const char FUNCTION_NAME[] = "tj3EncodeYUV8";
1663
36.3k
  unsigned char *dstPlanes[3];
1664
36.3k
  int pw0, ph0, strides[3], retval = -1;
1665
1666
36.3k
  GET_TJINSTANCE(handle, -1);
1667
1668
36.3k
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
1669
36.3k
      !IS_POW2(align))
1670
36.3k
    THROW("Invalid argument");
1671
1672
36.3k
  if (this->subsamp == TJSAMP_UNKNOWN)
1673
36.3k
    THROW("TJPARAM_SUBSAMP must be specified");
1674
1675
36.3k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1676
36.3k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1677
36.3k
  dstPlanes[0] = dstBuf;
1678
36.3k
  strides[0] = PAD(pw0, align);
1679
36.3k
  if (this->subsamp == TJSAMP_GRAY) {
1680
12.2k
    strides[1] = strides[2] = 0;
1681
12.2k
    dstPlanes[1] = dstPlanes[2] = NULL;
1682
24.1k
  } else {
1683
24.1k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
1684
24.1k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
1685
1686
24.1k
    strides[1] = strides[2] = PAD(pw1, align);
1687
24.1k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1688
24.1k
        (unsigned long long)INT_MAX ||
1689
24.1k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1690
24.1k
        (unsigned long long)INT_MAX)
1691
24.1k
      THROW("Image or row alignment is too large");
1692
24.1k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1693
24.1k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1694
24.1k
  }
1695
1696
36.3k
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1697
36.3k
                             dstPlanes, strides);
1698
1699
0
bailout:
1700
0
  return retval;
1701
36.3k
}
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
57.4k
{
1751
57.4k
  static unsigned char buffer[1];
1752
1753
  /* This is also straight out of example.c */
1754
57.4k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1755
57.4k
  this->jerr.pub.error_exit = my_error_exit;
1756
57.4k
  this->jerr.pub.output_message = my_output_message;
1757
57.4k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1758
57.4k
  this->jerr.pub.emit_message = my_emit_message;
1759
57.4k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1760
57.4k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1761
57.4k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1762
1763
57.4k
  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
57.4k
  jpeg_create_decompress(&this->dinfo);
1770
  /* Make an initial call so it will create the source manager */
1771
57.4k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1772
1773
57.4k
  this->init |= DECOMPRESS;
1774
57.4k
  return (tjhandle)this;
1775
57.4k
}
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.4k
{
1789
19.4k
  static const char FUNCTION_NAME[] = "tj3DecompressHeader";
1790
19.4k
  int retval = 0;
1791
1792
19.4k
  GET_DINSTANCE(handle);
1793
19.4k
  if ((this->init & DECOMPRESS) == 0)
1794
19.4k
    THROW("Instance has not been initialized for decompression");
1795
1796
19.4k
  if (jpegBuf == NULL || jpegSize <= 0)
1797
19.4k
    THROW("Invalid argument");
1798
1799
19.4k
  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.71k
    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
96.7k
{
1902
96.7k
  static const char FUNCTION_NAME[] = "tj3SetScalingFactor";
1903
96.7k
  int i, retval = 0;
1904
1905
96.7k
  GET_TJINSTANCE(handle, -1);
1906
96.7k
  if ((this->init & DECOMPRESS) == 0)
1907
96.7k
    THROW("Instance has not been initialized for decompression");
1908
1909
1.03M
  for (i = 0; i < NUMSF; i++) {
1910
1.03M
    if (scalingFactor.num == sf[i].num && scalingFactor.denom == sf[i].denom)
1911
96.7k
      break;
1912
1.03M
  }
1913
96.7k
  if (i >= NUMSF)
1914
96.7k
    THROW("Unsupported scaling factor");
1915
1916
96.7k
  this->scalingFactor = scalingFactor;
1917
1918
96.7k
bailout:
1919
96.7k
  return retval;
1920
96.7k
}
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
1.01k
  if (croppingRegion.x < 0 || croppingRegion.y < 0 || croppingRegion.w < 0 ||
1940
1.01k
      croppingRegion.h < 0)
1941
1.01k
    THROW("Invalid cropping region");
1942
1.01k
  if (this->jpegWidth < 0 || this->jpegHeight < 0)
1943
1.01k
    THROW("JPEG header has not yet been read");
1944
1.01k
  if (this->precision == 16 || this->lossless)
1945
1.00k
    THROW("Cannot partially decompress lossless JPEG images");
1946
1.00k
  if (this->subsamp == TJSAMP_UNKNOWN)
1947
894
    THROW("Could not determine subsampling level of JPEG image");
1948
1949
894
  scaledWidth = TJSCALED(this->jpegWidth, this->scalingFactor);
1950
894
  scaledHeight = TJSCALED(this->jpegHeight, this->scalingFactor);
1951
1952
894
  if (croppingRegion.x %
1953
894
      TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor) != 0)
1954
0
    THROWI("The left boundary of the cropping region (%d) is not\n"
1955
894
           "divisible by the scaled iMCU width (%d)",
1956
894
           croppingRegion.x,
1957
894
           TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor));
1958
894
  if (croppingRegion.w == 0)
1959
0
    croppingRegion.w = scaledWidth - croppingRegion.x;
1960
894
  if (croppingRegion.h == 0)
1961
0
    croppingRegion.h = scaledHeight - croppingRegion.y;
1962
894
  if (croppingRegion.w <= 0 || croppingRegion.h <= 0 ||
1963
894
      croppingRegion.x + croppingRegion.w > scaledWidth ||
1964
894
      croppingRegion.y + croppingRegion.h > scaledHeight)
1965
894
    THROW("The cropping region exceeds the scaled image dimensions");
1966
1967
894
  this->croppingRegion = croppingRegion;
1968
1969
1.01k
bailout:
1970
1.01k
  return retval;
1971
894
}
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
30.2k
{
2046
30.2k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUVPlanes8";
2047
30.2k
  int i, row, retval = 0;
2048
30.2k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
2049
30.2k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
2050
30.2k
  JSAMPLE *_tmpbuf = NULL, *ptr;
2051
30.2k
  JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
2052
30.2k
  int dctsize;
2053
30.2k
  struct my_progress_mgr progress;
2054
2055
30.2k
  GET_DINSTANCE(handle);
2056
2057
332k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2058
302k
    tmpbuf[i] = NULL;  outbuf[i] = NULL;
2059
302k
  }
2060
2061
30.2k
  if ((this->init & DECOMPRESS) == 0)
2062
30.2k
    THROW("Instance has not been initialized for decompression");
2063
2064
30.2k
  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0])
2065
30.2k
    THROW("Invalid argument");
2066
2067
30.2k
  if (this->scanLimit) {
2068
30.2k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2069
30.2k
    progress.pub.progress_monitor = my_progress_monitor;
2070
30.2k
    progress.this = this;
2071
30.2k
    dinfo->progress = &progress.pub;
2072
30.2k
  } else
2073
0
    dinfo->progress = NULL;
2074
2075
30.2k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2076
2077
30.2k
  CATCH_LIBJPEG(this);
2078
2079
30.2k
  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
30.2k
  setDecompParameters(this);
2084
30.2k
  if (this->maxPixels &&
2085
0
      (unsigned long long)this->jpegWidth * this->jpegHeight >
2086
0
      (unsigned long long)this->maxPixels)
2087
30.2k
    THROW("Image is too large");
2088
30.2k
  if (this->subsamp == TJSAMP_UNKNOWN)
2089
30.2k
    THROW("Could not determine subsampling level of JPEG image");
2090
2091
30.2k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
2092
30.2k
    THROW("Invalid argument");
2093
2094
30.2k
  if (dinfo->num_components > 3)
2095
30.1k
    THROW("JPEG image must have 3 or fewer components");
2096
2097
30.1k
  dinfo->scale_num = this->scalingFactor.num;
2098
30.1k
  dinfo->scale_denom = this->scalingFactor.denom;
2099
30.1k
  jpeg_calc_output_dimensions(dinfo);
2100
2101
30.1k
  dctsize = DCTSIZE * this->scalingFactor.num / this->scalingFactor.denom;
2102
2103
102k
  for (i = 0; i < dinfo->num_components; i++) {
2104
71.8k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
2105
71.8k
    int ih;
2106
2107
71.8k
    iw[i] = compptr->width_in_blocks * dctsize;
2108
71.8k
    ih = compptr->height_in_blocks * dctsize;
2109
71.8k
    pw[i] = tj3YUVPlaneWidth(i, dinfo->output_width, this->subsamp);
2110
71.8k
    ph[i] = tj3YUVPlaneHeight(i, dinfo->output_height, this->subsamp);
2111
71.8k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
2112
71.8k
    th[i] = compptr->v_samp_factor * dctsize;
2113
71.8k
    tmpbufsize += iw[i] * th[i];
2114
71.8k
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
2115
71.8k
      THROW("Memory allocation failure");
2116
71.8k
    ptr = dstPlanes[i];
2117
322M
    for (row = 0; row < ph[i]; row++) {
2118
321M
      outbuf[i][row] = ptr;
2119
321M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2120
321M
    }
2121
71.8k
  }
2122
30.1k
  if (usetmpbuf) {
2123
25.1k
    if ((_tmpbuf = (JSAMPLE *)MALLOC(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
2124
25.1k
      THROW("Memory allocation failure");
2125
25.1k
    ptr = _tmpbuf;
2126
84.7k
    for (i = 0; i < dinfo->num_components; i++) {
2127
59.6k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
2128
59.6k
        THROW("Memory allocation failure");
2129
693k
      for (row = 0; row < th[i]; row++) {
2130
633k
        tmpbuf[i][row] = ptr;
2131
633k
        ptr += iw[i];
2132
633k
      }
2133
59.6k
    }
2134
25.1k
  }
2135
2136
30.1k
  CATCH_LIBJPEG(this);
2137
2138
10.1k
  dinfo->do_fancy_upsampling = !this->fastUpsample;
2139
10.1k
  dinfo->dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2140
10.1k
  dinfo->raw_data_out = TRUE;
2141
2142
10.1k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2143
2144
10.1k
  jpeg_start_decompress(dinfo);
2145
3.75M
  for (row = 0; row < (int)dinfo->output_height;
2146
3.74M
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
2147
3.74M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
2148
3.74M
    int crow[MAX_COMPONENTS];
2149
2150
10.5M
    for (i = 0; i < dinfo->num_components; i++) {
2151
6.81M
      jpeg_component_info *compptr = &dinfo->comp_info[i];
2152
2153
6.81M
      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.17M
        compptr->_DCT_scaled_size = dctsize;
2165
1.17M
        compptr->MCU_sample_width = tjMCUWidth[this->subsamp] *
2166
1.17M
          this->scalingFactor.num / this->scalingFactor.denom *
2167
1.17M
          compptr->h_samp_factor / dinfo->max_h_samp_factor;
2168
1.17M
        dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
2169
1.17M
      }
2170
6.81M
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2171
6.81M
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
2172
1.49M
      else yuvptr[i] = &outbuf[i][crow[i]];
2173
6.81M
    }
2174
3.74M
    jpeg_read_raw_data(dinfo, yuvptr,
2175
3.74M
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
2176
3.74M
    if (usetmpbuf) {
2177
2.87M
      int j;
2178
2179
8.17M
      for (i = 0; i < dinfo->num_components; i++) {
2180
55.1M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
2181
49.8M
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
2182
49.8M
        }
2183
5.30M
      }
2184
2.87M
    }
2185
3.74M
  }
2186
10.1k
  jpeg_finish_decompress(dinfo);
2187
2188
30.2k
bailout:
2189
30.2k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2190
332k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2191
302k
    free(tmpbuf[i]);
2192
302k
    free(outbuf[i]);
2193
302k
  }
2194
30.2k
  free(_tmpbuf);
2195
30.2k
  if (this->jerr.warning) retval = -1;
2196
30.2k
  return retval;
2197
10.1k
}
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
47.4k
{
2252
47.4k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUV8";
2253
47.4k
  unsigned char *dstPlanes[3];
2254
47.4k
  int pw0, ph0, strides[3], retval = -1;
2255
47.4k
  int width, height;
2256
2257
47.4k
  GET_DINSTANCE(handle);
2258
2259
47.4k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || align < 1 ||
2260
47.4k
      !IS_POW2(align))
2261
47.4k
    THROW("Invalid argument");
2262
2263
47.4k
  CATCH_LIBJPEG(this);
2264
2265
47.4k
  if (dinfo->global_state <= DSTATE_INHEADER) {
2266
47.4k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2267
47.4k
    jpeg_read_header(dinfo, TRUE);
2268
47.4k
  }
2269
47.4k
  setDecompParameters(this);
2270
47.4k
  if (this->subsamp == TJSAMP_UNKNOWN)
2271
46.8k
    THROW("Could not determine subsampling level of JPEG image");
2272
2273
46.8k
  width = TJSCALED(dinfo->image_width, this->scalingFactor);
2274
46.8k
  height = TJSCALED(dinfo->image_height, this->scalingFactor);
2275
2276
46.8k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2277
46.8k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2278
46.8k
  dstPlanes[0] = dstBuf;
2279
46.8k
  strides[0] = PAD(pw0, align);
2280
46.8k
  if (this->subsamp == TJSAMP_GRAY) {
2281
18.4k
    strides[1] = strides[2] = 0;
2282
18.4k
    dstPlanes[1] = dstPlanes[2] = NULL;
2283
28.4k
  } else {
2284
28.4k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2285
28.4k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2286
2287
28.4k
    strides[1] = strides[2] = PAD(pw1, align);
2288
28.4k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2289
28.4k
        (unsigned long long)INT_MAX ||
2290
28.4k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2291
28.4k
        (unsigned long long)INT_MAX)
2292
28.4k
      THROW("Image or row alignment is too large");
2293
28.4k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
2294
28.4k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
2295
28.4k
  }
2296
2297
46.8k
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2298
46.8k
                                   strides);
2299
2300
574
bailout:
2301
574
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2302
574
  if (this->jerr.warning) retval = -1;
2303
574
  return retval;
2304
46.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.21k
{
2362
2.21k
  int i;
2363
2364
2.21k
  this->dinfo.scale_num = this->dinfo.scale_denom = 1;
2365
2366
2.21k
  if (this->subsamp == TJSAMP_GRAY) {
2367
741
    this->dinfo.num_components = this->dinfo.comps_in_scan = 1;
2368
741
    this->dinfo.jpeg_color_space = JCS_GRAYSCALE;
2369
1.46k
  } else {
2370
1.46k
    this->dinfo.num_components = this->dinfo.comps_in_scan = 3;
2371
1.46k
    this->dinfo.jpeg_color_space = JCS_YCbCr;
2372
1.46k
  }
2373
2374
2.21k
  this->dinfo.comp_info = (jpeg_component_info *)
2375
2.21k
    (*this->dinfo.mem->alloc_small) ((j_common_ptr)&this->dinfo, JPOOL_IMAGE,
2376
2.21k
                                     this->dinfo.num_components *
2377
2.21k
                                     sizeof(jpeg_component_info));
2378
2379
7.35k
  for (i = 0; i < this->dinfo.num_components; i++) {
2380
5.14k
    jpeg_component_info *compptr = &this->dinfo.comp_info[i];
2381
2382
5.14k
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[this->subsamp] / 8 : 1;
2383
5.14k
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[this->subsamp] / 8 : 1;
2384
5.14k
    compptr->component_index = i;
2385
5.14k
    compptr->component_id = i + 1;
2386
5.14k
    compptr->quant_tbl_no = compptr->dc_tbl_no =
2387
5.14k
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
2388
5.14k
    this->dinfo.cur_comp_info[i] = compptr;
2389
5.14k
  }
2390
2.21k
  this->dinfo.data_precision = 8;
2391
6.63k
  for (i = 0; i < 2; i++) {
2392
4.42k
    if (this->dinfo.quant_tbl_ptrs[i] == NULL)
2393
517
      this->dinfo.quant_tbl_ptrs[i] =
2394
517
        jpeg_alloc_quant_table((j_common_ptr)&this->dinfo);
2395
4.42k
  }
2396
2397
2.21k
  this->dinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2398
2.21k
}
2399
2400
2401
static int my_read_markers(j_decompress_ptr dinfo)
2402
2.21k
{
2403
2.21k
  return JPEG_REACHED_SOS;
2404
2.21k
}
2405
2406
static void my_reset_marker_reader(j_decompress_ptr dinfo)
2407
2.21k
{
2408
2.21k
}
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.21k
{
2417
2.21k
  static const char FUNCTION_NAME[] = "tj3DecodeYUVPlanes8";
2418
2.21k
  JSAMPROW *row_pointer = NULL;
2419
2.21k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS];
2420
2.21k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
2421
2.21k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
2422
2.21k
  JSAMPLE *ptr;
2423
2.21k
  jpeg_component_info *compptr;
2424
2.21k
  int (*old_read_markers) (j_decompress_ptr) = NULL;
2425
2.21k
  void (*old_reset_marker_reader) (j_decompress_ptr) = NULL;
2426
2427
2.21k
  GET_DINSTANCE(handle);
2428
2429
24.3k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2430
22.1k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;  inbuf[i] = NULL;
2431
22.1k
  }
2432
2433
2.21k
  if ((this->init & DECOMPRESS) == 0)
2434
2.21k
    THROW("Instance has not been initialized for decompression");
2435
2436
2.21k
  if (!srcPlanes || !srcPlanes[0] || dstBuf == NULL || width <= 0 ||
2437
2.21k
      pitch < 0 || height <= 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
2438
2.21k
    THROW("Invalid argument");
2439
2.21k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
2440
2.21k
    THROW("Invalid argument");
2441
2442
2.21k
  if (this->subsamp == TJSAMP_UNKNOWN)
2443
2.21k
    THROW("TJPARAM_SUBSAMP must be specified");
2444
2.21k
  if (pixelFormat == TJPF_CMYK)
2445
2.21k
    THROW("Cannot decode YUV images into packed-pixel CMYK images.");
2446
2447
2.21k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
2448
0
  else if (pitch < width * tjPixelSize[pixelFormat])
2449
2.21k
    THROW("Invalid argument");
2450
2.21k
  dinfo->image_width = width;
2451
2.21k
  dinfo->image_height = height;
2452
2453
2.21k
  dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
2454
2.21k
  dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
2455
2.21k
  dinfo->Se = DCTSIZE2 - 1;
2456
2.21k
  setDecodeDefaults(this, pixelFormat);
2457
2.21k
  old_read_markers = dinfo->marker->read_markers;
2458
2.21k
  dinfo->marker->read_markers = my_read_markers;
2459
2.21k
  old_reset_marker_reader = dinfo->marker->reset_marker_reader;
2460
2.21k
  dinfo->marker->reset_marker_reader = my_reset_marker_reader;
2461
2.21k
  CATCH_LIBJPEG(this);
2462
2.18k
  jpeg_read_header(dinfo, TRUE);
2463
2.18k
  dinfo->marker->read_markers = old_read_markers;
2464
2.18k
  dinfo->marker->reset_marker_reader = old_reset_marker_reader;
2465
2466
2.18k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
2467
2.18k
  this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2468
2.18k
  dinfo->do_fancy_upsampling = FALSE;
2469
2.18k
  dinfo->Se = DCTSIZE2 - 1;
2470
2.18k
  jinit_master_decompress(dinfo);
2471
2.18k
  (*dinfo->upsample->start_pass) (dinfo);
2472
2473
2.18k
  pw0 = PAD(width, dinfo->max_h_samp_factor);
2474
2.18k
  ph0 = PAD(height, dinfo->max_v_samp_factor);
2475
2476
2.18k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
2477
2478
2.18k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
2479
2.18k
    THROW("Memory allocation failure");
2480
12.0M
  for (i = 0; i < height; i++) {
2481
12.0M
    if (this->bottomUp)
2482
4.22M
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
2483
7.81M
    else
2484
7.81M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
2485
12.0M
  }
2486
2.18k
  if (height < ph0)
2487
1.00k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
2488
2489
7.24k
  for (i = 0; i < dinfo->num_components; i++) {
2490
5.06k
    compptr = &dinfo->comp_info[i];
2491
5.06k
    _tmpbuf[i] =
2492
5.06k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
2493
5.06k
                        compptr->v_samp_factor + 32);
2494
5.06k
    if (!_tmpbuf[i])
2495
5.06k
      THROW("Memory allocation failure");
2496
5.06k
    tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
2497
5.06k
    if (!tmpbuf[i])
2498
5.06k
      THROW("Memory allocation failure");
2499
11.2k
    for (row = 0; row < compptr->v_samp_factor; row++) {
2500
6.16k
      unsigned char *_tmpbuf_aligned =
2501
6.16k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
2502
2503
6.16k
      tmpbuf[i][row] =
2504
6.16k
        &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
2505
6.16k
    }
2506
5.06k
    pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
2507
5.06k
    ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2508
5.06k
    inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
2509
5.06k
    if (!inbuf[i])
2510
5.06k
      THROW("Memory allocation failure");
2511
5.06k
    ptr = (JSAMPLE *)srcPlanes[i];
2512
22.0M
    for (row = 0; row < ph[i]; row++) {
2513
22.0M
      inbuf[i][row] = ptr;
2514
22.0M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2515
22.0M
    }
2516
5.06k
  }
2517
2518
2.18k
  CATCH_LIBJPEG(this);
2519
2520
10.4M
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
2521
10.4M
    JDIMENSION inrow = 0, outrow = 0;
2522
2523
30.9M
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
2524
20.4M
         i++, compptr++)
2525
20.4M
      jcopy_sample_rows(inbuf[i],
2526
20.4M
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
2527
20.4M
        compptr->v_samp_factor, pw[i]);
2528
10.4M
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
2529
10.4M
                                 dinfo->max_v_samp_factor, &row_pointer[row],
2530
10.4M
                                 &outrow, dinfo->max_v_samp_factor);
2531
10.4M
  }
2532
2.18k
  jpeg_abort_decompress(dinfo);
2533
2534
2.21k
bailout:
2535
2.21k
  if (old_read_markers)
2536
2.21k
    dinfo->marker->read_markers = old_read_markers;
2537
2.21k
  if (old_reset_marker_reader)
2538
2.21k
    dinfo->marker->reset_marker_reader = old_reset_marker_reader;
2539
2.21k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2540
2.21k
  free(row_pointer);
2541
24.3k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2542
22.1k
    free(tmpbuf[i]);
2543
22.1k
    free(_tmpbuf[i]);
2544
22.1k
    free(inbuf[i]);
2545
22.1k
  }
2546
2.21k
  if (this->jerr.warning) retval = -1;
2547
2.21k
  return retval;
2548
2.18k
}
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.21k
{
2581
2.21k
  static const char FUNCTION_NAME[] = "tj3DecodeYUV8";
2582
2.21k
  const unsigned char *srcPlanes[3];
2583
2.21k
  int pw0, ph0, strides[3], retval = -1;
2584
2585
2.21k
  GET_TJINSTANCE(handle, -1);
2586
2587
2.21k
  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || width <= 0 ||
2588
2.21k
      height <= 0)
2589
2.21k
    THROW("Invalid argument");
2590
2591
2.21k
  if (this->subsamp == TJSAMP_UNKNOWN)
2592
2.21k
    THROW("TJPARAM_SUBSAMP must be specified");
2593
2594
2.21k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2595
2.21k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2596
2.21k
  srcPlanes[0] = srcBuf;
2597
2.21k
  strides[0] = PAD(pw0, align);
2598
2.21k
  if (this->subsamp == TJSAMP_GRAY) {
2599
741
    strides[1] = strides[2] = 0;
2600
741
    srcPlanes[1] = srcPlanes[2] = NULL;
2601
1.46k
  } else {
2602
1.46k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2603
1.46k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2604
2605
1.46k
    strides[1] = strides[2] = PAD(pw1, align);
2606
1.46k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2607
1.46k
        (unsigned long long)INT_MAX ||
2608
1.46k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2609
1.46k
        (unsigned long long)INT_MAX)
2610
1.46k
      THROW("Image or row alignment is too large");
2611
1.46k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
2612
1.46k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
2613
1.46k
  }
2614
2615
2.21k
  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
2616
2.21k
                             height, pixelFormat);
2617
2618
0
bailout:
2619
0
  return retval;
2620
2.21k
}
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.5k
{
2661
16.5k
  static const char FUNCTION_NAME[] = "tj3Transform";
2662
16.5k
  int retval = 0;
2663
2664
16.5k
#if TRANSFORMS_SUPPORTED
2665
2666
16.5k
  jpeg_transform_info *xinfo = NULL;
2667
16.5k
  jvirt_barray_ptr *srccoefs, *dstcoefs;
2668
16.5k
  int i, saveMarkers = 0, srcSubsamp;
2669
16.5k
  boolean alloc = TRUE;
2670
16.5k
  struct my_progress_mgr progress;
2671
2672
16.5k
  GET_INSTANCE(handle);
2673
16.5k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2674
16.5k
    THROW("Instance has not been initialized for transformation");
2675
2676
16.5k
  if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
2677
16.5k
      dstSizes == NULL || t == NULL)
2678
16.5k
    THROW("Invalid argument");
2679
2680
16.5k
  if (this->scanLimit) {
2681
16.5k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2682
16.5k
    progress.pub.progress_monitor = my_progress_monitor;
2683
16.5k
    progress.this = this;
2684
16.5k
    dinfo->progress = &progress.pub;
2685
16.5k
  } else
2686
0
    dinfo->progress = NULL;
2687
2688
16.5k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2689
2690
16.5k
  if ((xinfo =
2691
16.5k
       (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
2692
16.5k
    THROW("Memory allocation failure");
2693
16.5k
  memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
2694
2695
16.5k
  CATCH_LIBJPEG(this);
2696
2697
7.61k
  if (dinfo->global_state <= DSTATE_INHEADER)
2698
16.5k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2699
2700
28.1k
  for (i = 0; i < n; i++) {
2701
20.4k
    if (t[i].op < 0 || t[i].op >= TJ_NUMXOP)
2702
20.4k
      THROW("Invalid transform operation");
2703
20.4k
    xinfo[i].transform = xformtypes[t[i].op];
2704
20.4k
    xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
2705
20.4k
    xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
2706
20.4k
    xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
2707
20.4k
    xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
2708
20.4k
    if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
2709
20.4k
    else xinfo[i].slow_hflip = 0;
2710
2711
20.4k
    if (xinfo[i].crop) {
2712
3.97k
      if (t[i].r.x < 0 || t[i].r.y < 0 || t[i].r.w < 0 || t[i].r.h < 0)
2713
3.97k
        THROW("Invalid cropping region");
2714
3.97k
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
2715
3.97k
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
2716
3.97k
      if (t[i].r.w != 0) {
2717
3.97k
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
2718
3.97k
      } else
2719
0
        xinfo[i].crop_width = JCROP_UNSET;
2720
3.97k
      if (t[i].r.h != 0) {
2721
3.97k
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
2722
3.97k
      } else
2723
0
        xinfo[i].crop_height = JCROP_UNSET;
2724
3.97k
    }
2725
20.4k
    if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
2726
20.4k
  }
2727
2728
18.4E
  jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
2729
7.61k
  if (dinfo->global_state <= DSTATE_INHEADER)
2730
16.5k
    jpeg_read_header(dinfo, TRUE);
2731
7.61k
  if (this->maxPixels &&
2732
0
      (unsigned long long)dinfo->image_width * dinfo->image_height >
2733
0
      (unsigned long long)this->maxPixels)
2734
7.61k
    THROW("Image is too large");
2735
7.61k
  srcSubsamp = getSubsamp(&this->dinfo);
2736
2737
28.1k
  for (i = 0; i < n; i++) {
2738
20.4k
    if (!jtransform_request_workspace(dinfo, &xinfo[i]))
2739
20.4k
      THROW("Transform is not perfect");
2740
2741
20.4k
    if (xinfo[i].crop) {
2742
3.97k
      int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2743
2744
3.97k
      if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2745
3.97k
          t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2746
3.97k
        if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2747
3.97k
        else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2748
3.97k
        else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2749
3.97k
        else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2750
3.97k
      }
2751
3.97k
      if (dstSubsamp == TJSAMP_UNKNOWN)
2752
3.97k
        THROW("Could not determine subsampling level of destination image");
2753
3.97k
      if ((t[i].r.x % tjMCUWidth[dstSubsamp]) != 0 ||
2754
3.97k
          (t[i].r.y % tjMCUHeight[dstSubsamp]) != 0)
2755
0
        THROWI("To crop this JPEG image, x must be a multiple of %d\n"
2756
3.97k
               "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
2757
3.97k
               tjMCUHeight[dstSubsamp]);
2758
3.97k
    }
2759
20.4k
  }
2760
2761
7.61k
  srccoefs = jpeg_read_coefficients(dinfo);
2762
2763
18.8k
  for (i = 0; i < n; i++) {
2764
12.0k
    JDIMENSION dstWidth = dinfo->image_width, dstHeight = dinfo->image_height;
2765
2766
12.0k
    if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2767
9.53k
        t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2768
5.13k
      dstWidth = dinfo->image_height;  dstHeight = dinfo->image_width;
2769
5.13k
    }
2770
2771
12.0k
    if (xinfo[i].crop) {
2772
2.56k
      if ((JDIMENSION)t[i].r.x >= dstWidth ||
2773
2.56k
          t[i].r.x + xinfo[i].crop_width > dstWidth ||
2774
2.56k
          (JDIMENSION)t[i].r.y >= dstHeight ||
2775
2.56k
          t[i].r.y + xinfo[i].crop_height > dstHeight)
2776
2.56k
        THROW("The cropping region exceeds the destination image dimensions");
2777
2.56k
      dstWidth = xinfo[i].crop_width;  dstHeight = xinfo[i].crop_height;
2778
2.56k
    }
2779
12.0k
    if (this->noRealloc) {
2780
7.76k
      int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2781
2782
7.76k
      if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2783
5.20k
          t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2784
5.13k
        if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2785
5.05k
        else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2786
5.00k
        else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2787
5.00k
        else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2788
5.13k
      }
2789
7.76k
      if (dstSubsamp == TJSAMP_UNKNOWN)
2790
6.86k
        THROW("Could not determine subsampling level of destination image");
2791
6.86k
      alloc = FALSE;
2792
6.86k
      dstSizes[i] = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
2793
6.86k
    }
2794
11.1k
    if (!(t[i].options & TJXOPT_NOOUTPUT))
2795
11.1k
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2796
11.1k
    jpeg_copy_critical_parameters(dinfo, cinfo);
2797
11.1k
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
2798
11.1k
    if (this->optimize || t[i].options & TJXOPT_OPTIMIZE)
2799
1.90k
      cinfo->optimize_coding = TRUE;
2800
11.1k
#ifdef C_PROGRESSIVE_SUPPORTED
2801
11.1k
    if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE)
2802
4.42k
      jpeg_simple_progression(cinfo);
2803
11.1k
#endif
2804
11.1k
    if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) {
2805
2.06k
      cinfo->arith_code = TRUE;
2806
2.06k
      cinfo->optimize_coding = FALSE;
2807
2.06k
    }
2808
11.1k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
2809
10.1k
      jpeg_write_coefficients(cinfo, dstcoefs);
2810
10.1k
      jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
2811
6.14k
                                          JCOPYOPT_NONE : JCOPYOPT_ALL);
2812
10.1k
    } else
2813
1.04k
      jinit_c_master_control(cinfo, TRUE);
2814
11.1k
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
2815
11.1k
    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.1k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2845
11.1k
  }
2846
2847
6.71k
  jpeg_finish_decompress(dinfo);
2848
2849
16.5k
bailout:
2850
16.5k
  if (cinfo->global_state > CSTATE_START) {
2851
1.67k
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
2852
1.67k
    jpeg_abort_compress(cinfo);
2853
1.67k
  }
2854
16.5k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2855
16.5k
  free(xinfo);
2856
16.5k
  if (this->jerr.warning) retval = -1;
2857
16.5k
  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.71k
}
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
}