Coverage Report

Created: 2026-10-17 07:27

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