Coverage Report

Created: 2026-04-12 06:05

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