Coverage Report

Created: 2026-06-12 06:28

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