Coverage Report

Created: 2025-08-03 06:59

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