Coverage Report

Created: 2025-11-09 06:52

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