Coverage Report

Created: 2026-05-30 07:16

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