Coverage Report

Created: 2026-07-16 07:45

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