Coverage Report

Created: 2025-12-14 06:14

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.06M
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
55
216k
#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
219k
{
78
219k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
79
80
219k
  (*cinfo->err->output_message) (cinfo);
81
219k
  longjmp(myerr->setjmp_buffer, 1);
82
219k
}
83
84
/* Based on output_message() in jerror.c */
85
86
static void my_output_message(j_common_ptr cinfo)
87
318k
{
88
318k
  (*cinfo->err->format_message) (cinfo, errStr);
89
318k
}
90
91
static void my_emit_message(j_common_ptr cinfo, int msg_level)
92
716M
{
93
716M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
94
95
716M
  myerr->emit_message(cinfo, msg_level);
96
716M
  if (msg_level < 0) {
97
473M
    myerr->warning = TRUE;
98
473M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
99
473M
  }
100
716M
}
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
374M
{
157
374M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
158
374M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
159
160
374M
  if (dinfo->is_decompressor) {
161
374M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
162
163
374M
    if (scan_no > myprog->this->scanLimit) {
164
60
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
165
60
               "Progressive JPEG image has more than %d scans",
166
60
               myprog->this->scanLimit);
167
60
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
168
60
               "Progressive JPEG image has more than %d scans",
169
60
               myprog->this->scanLimit);
170
60
      myprog->this->isInstanceError = TRUE;
171
60
      myerr->warning = FALSE;
172
60
      longjmp(myerr->setjmp_buffer, 1);
173
60
    }
174
374M
  }
175
374M
}
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
319k
#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.1k
  tjinstance *this = (tjinstance *)handle; \
269
31.1k
  j_compress_ptr cinfo = NULL; \
270
31.1k
  j_decompress_ptr dinfo = NULL; \
271
31.1k
  \
272
31.1k
  if (!this) { \
273
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
274
0
    return -1; \
275
0
  } \
276
31.1k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
277
31.1k
  this->jerr.warning = FALSE; \
278
31.1k
  this->isInstanceError = FALSE;
279
280
#define GET_CINSTANCE(handle) \
281
130k
  tjinstance *this = (tjinstance *)handle; \
282
130k
  j_compress_ptr cinfo = NULL; \
283
130k
  \
284
130k
  if (!this) { \
285
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
286
0
    return -1; \
287
0
  } \
288
130k
  cinfo = &this->cinfo; \
289
130k
  this->jerr.warning = FALSE; \
290
130k
  this->isInstanceError = FALSE;
291
292
#define GET_DINSTANCE(handle) \
293
93.9k
  tjinstance *this = (tjinstance *)handle; \
294
93.9k
  j_decompress_ptr dinfo = NULL; \
295
93.9k
  \
296
93.9k
  if (!this) { \
297
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
298
0
    return -1; \
299
0
  } \
300
93.9k
  dinfo = &this->dinfo; \
301
93.9k
  this->jerr.warning = FALSE; \
302
93.9k
  this->isInstanceError = FALSE;
303
304
#define GET_TJINSTANCE(handle, errorReturn) \
305
2.16M
  tjinstance *this = (tjinstance *)handle; \
306
2.16M
  \
307
2.16M
  if (!this) { \
308
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
309
0
    return errorReturn; \
310
0
  } \
311
2.16M
  this->jerr.warning = FALSE; \
312
2.16M
  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
182k
{
335
182k
  int colorspace = yuv ? -1 : this->colorspace;
336
337
182k
  this->cinfo.in_color_space = pf2cs[pixelFormat];
338
182k
  this->cinfo.input_components = tjPixelSize[pixelFormat];
339
182k
  jpeg_set_defaults(&this->cinfo);
340
341
182k
  this->cinfo.restart_interval = this->restartIntervalBlocks;
342
182k
  this->cinfo.restart_in_rows = this->restartIntervalRows;
343
182k
  this->cinfo.X_density = (UINT16)this->xDensity;
344
182k
  this->cinfo.Y_density = (UINT16)this->yDensity;
345
182k
  this->cinfo.density_unit = (UINT8)this->densityUnits;
346
182k
  this->cinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
347
348
182k
  if (this->lossless && !yuv) {
349
37.2k
#ifdef C_LOSSLESS_SUPPORTED
350
37.2k
    jpeg_enable_lossless(&this->cinfo, this->losslessPSV, this->losslessPt);
351
37.2k
#endif
352
37.2k
    return;
353
37.2k
  }
354
355
145k
  jpeg_set_quality(&this->cinfo, this->quality, TRUE);
356
145k
  this->cinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
357
358
145k
  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
145k
  default:
370
145k
    if (this->subsamp == TJSAMP_GRAY)
371
42.0k
      jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);
372
103k
    else if (pixelFormat == TJPF_CMYK)
373
11.6k
      jpeg_set_colorspace(&this->cinfo, JCS_YCCK);
374
91.4k
    else
375
91.4k
      jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);
376
145k
  }
377
378
145k
  if (this->cinfo.data_precision == 8)
379
105k
    this->cinfo.optimize_coding = this->optimize;
380
145k
#ifdef C_PROGRESSIVE_SUPPORTED
381
145k
  if (this->progressive) jpeg_simple_progression(&this->cinfo);
382
145k
#endif
383
145k
  this->cinfo.arith_code = this->arithmetic;
384
385
145k
  this->cinfo.comp_info[0].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
386
145k
  this->cinfo.comp_info[1].h_samp_factor = 1;
387
145k
  this->cinfo.comp_info[2].h_samp_factor = 1;
388
145k
  if (this->cinfo.num_components > 3)
389
11.6k
    this->cinfo.comp_info[3].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
390
145k
  this->cinfo.comp_info[0].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
391
145k
  this->cinfo.comp_info[1].v_samp_factor = 1;
392
145k
  this->cinfo.comp_info[2].v_samp_factor = 1;
393
145k
  if (this->cinfo.num_components > 3)
394
11.6k
    this->cinfo.comp_info[3].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
395
145k
}
396
397
398
static int getSubsamp(j_decompress_ptr dinfo)
399
144k
{
400
144k
  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
144k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
407
76.8k
    return TJSAMP_GRAY;
408
409
358k
  for (i = 0; i < TJ_NUMSAMP; i++) {
410
328k
    if (i == TJSAMP_GRAY) continue;
411
412
292k
    if (dinfo->num_components == 3 ||
413
32.1k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
414
30.8k
          dinfo->jpeg_color_space == JCS_CMYK) &&
415
285k
         dinfo->num_components == 4)) {
416
285k
      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.1k
        int match = 0;
419
420
179k
        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.64k
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
426
4.64k
          }
427
121k
          if (dinfo->comp_info[k].h_samp_factor == href &&
428
97.6k
              dinfo->comp_info[k].v_samp_factor == vref)
429
84.1k
            match++;
430
121k
        }
431
58.1k
        if (match == dinfo->num_components - 1) {
432
35.1k
          retval = i;  break;
433
35.1k
        }
434
58.1k
      }
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
76.7k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
440
35.0k
        int match = 0;
441
442
105k
        for (k = 1; k < dinfo->num_components; k++) {
443
70.6k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
444
445
70.6k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
446
70.2k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
447
578
            href = vref = 2;
448
578
          }
449
70.6k
          if (dinfo->comp_info[k].h_samp_factor == href &&
450
57.5k
              dinfo->comp_info[k].v_samp_factor == vref)
451
9.52k
            match++;
452
70.6k
        }
453
35.0k
        if (match == dinfo->num_components - 1) {
454
3.57k
          retval = i;  break;
455
3.57k
        }
456
35.0k
      }
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.3k
        int match = 0;
463
64.0k
        for (k = 1; k < dinfo->num_components; k++) {
464
44.7k
          if (dinfo->comp_info[k].h_samp_factor ==
465
44.7k
              dinfo->comp_info[0].h_samp_factor &&
466
15.9k
              dinfo->comp_info[k].v_samp_factor ==
467
15.9k
              dinfo->comp_info[0].v_samp_factor)
468
8.93k
            match++;
469
44.7k
          if (match == dinfo->num_components - 1) {
470
2.05k
            retval = i;  break;
471
2.05k
          }
472
44.7k
        }
473
21.3k
      }
474
246k
    }
475
292k
  }
476
67.9k
  return retval;
477
144k
}
478
479
480
static void setDecompParameters(tjinstance *this)
481
97.6k
{
482
97.6k
  this->subsamp = getSubsamp(&this->dinfo);
483
97.6k
  this->jpegWidth = this->dinfo.image_width;
484
97.6k
  this->jpegHeight = this->dinfo.image_height;
485
97.6k
  this->precision = this->dinfo.data_precision;
486
97.6k
  switch (this->dinfo.jpeg_color_space) {
487
45.9k
  case JCS_GRAYSCALE:  this->colorspace = TJCS_GRAY;  break;
488
21.0k
  case JCS_RGB:        this->colorspace = TJCS_RGB;  break;
489
29.0k
  case JCS_YCbCr:      this->colorspace = TJCS_YCbCr;  break;
490
1.16k
  case JCS_CMYK:       this->colorspace = TJCS_CMYK;  break;
491
130
  case JCS_YCCK:       this->colorspace = TJCS_YCCK;  break;
492
330
  default:             this->colorspace = -1;  break;
493
97.6k
  }
494
97.6k
  this->progressive = this->dinfo.progressive_mode;
495
97.6k
  this->arithmetic = this->dinfo.arith_code;
496
97.6k
  this->lossless = this->dinfo.master->lossless;
497
97.6k
  this->losslessPSV = this->dinfo.Ss;
498
97.6k
  this->losslessPt = this->dinfo.Al;
499
97.6k
  this->xDensity = this->dinfo.X_density;
500
97.6k
  this->yDensity = this->dinfo.Y_density;
501
97.6k
  this->densityUnits = this->dinfo.density_unit;
502
97.6k
}
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.2k
  case TJINIT_DECOMPRESS:  return _tjInitDecompress(this);
567
16.0k
  case TJINIT_TRANSFORM:
568
16.0k
    retval = _tjInitCompress(this);
569
16.0k
    if (!retval) return NULL;
570
16.0k
    retval = _tjInitDecompress(this);
571
16.0k
    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
735k
#define SET_PARAM(field, minValue, maxValue) { \
659
735k
  if (value < minValue || (maxValue > 0 && value > maxValue)) \
660
735k
    THROW("Parameter value out of range"); \
661
735k
  this->field = value; \
662
735k
}
663
664
1.05M
#define SET_BOOL_PARAM(field) { \
665
1.05M
  if (value < 0 || value > 1) \
666
1.05M
    THROW("Parameter value out of range"); \
667
1.05M
  this->field = (boolean)value; \
668
1.05M
}
669
670
/* TurboJPEG 3.0+ */
671
DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
672
1.79M
{
673
1.79M
  static const char FUNCTION_NAME[] = "tj3Set";
674
1.79M
  int retval = 0;
675
676
1.79M
  GET_TJINSTANCE(handle, -1);
677
678
1.79M
  switch (param) {
679
0
  case TJPARAM_STOPONWARNING:
680
0
    SET_BOOL_PARAM(jerr.stopOnWarning);
681
0
    break;
682
238k
  case TJPARAM_BOTTOMUP:
683
238k
    SET_BOOL_PARAM(bottomUp);
684
238k
    break;
685
230k
  case TJPARAM_NOREALLOC:
686
230k
    if (!(this->init & COMPRESS))
687
230k
      THROW("TJPARAM_NOREALLOC is not applicable to decompression instances.");
688
230k
    SET_BOOL_PARAM(noRealloc);
689
230k
    break;
690
73.6k
  case TJPARAM_QUALITY:
691
73.6k
    if (!(this->init & COMPRESS))
692
73.6k
      THROW("TJPARAM_QUALITY is not applicable to decompression instances.");
693
73.6k
    SET_PARAM(quality, 1, 100);
694
73.6k
    break;
695
73.6k
  case TJPARAM_SUBSAMP:
696
73.6k
    SET_PARAM(subsamp, 0, TJ_NUMSAMP - 1);
697
73.6k
    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
82.7k
  case TJPARAM_PRECISION:
709
82.7k
    SET_PARAM(precision, 2, 16);
710
82.7k
    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.7k
  case TJPARAM_FASTUPSAMPLE:
717
23.7k
    if (!(this->init & DECOMPRESS))
718
23.7k
      THROW("TJPARAM_FASTUPSAMPLE is not applicable to compression instances.");
719
23.7k
    SET_BOOL_PARAM(fastUpsample);
720
23.7k
    break;
721
152k
  case TJPARAM_FASTDCT:
722
152k
    SET_BOOL_PARAM(fastDCT);
723
152k
    break;
724
102k
  case TJPARAM_OPTIMIZE:
725
102k
    if (!(this->init & COMPRESS))
726
102k
      THROW("TJPARAM_OPTIMIZE is not applicable to decompression instances.");
727
102k
    SET_BOOL_PARAM(optimize);
728
102k
    break;
729
142k
  case TJPARAM_PROGRESSIVE:
730
142k
    if (!(this->init & COMPRESS))
731
142k
      THROW("TJPARAM_PROGRESSIVE is read-only in decompression instances.");
732
142k
    SET_BOOL_PARAM(progressive);
733
142k
    break;
734
27.7k
  case TJPARAM_SCANLIMIT:
735
27.7k
    if (!(this->init & DECOMPRESS))
736
27.7k
      THROW("TJPARAM_SCANLIMIT is not applicable to compression instances.");
737
27.7k
    SET_PARAM(scanLimit, 0, -1);
738
27.7k
    break;
739
142k
  case TJPARAM_ARITHMETIC:
740
142k
    if (!(this->init & COMPRESS))
741
142k
      THROW("TJPARAM_ARITHMETIC is read-only in decompression instances.");
742
142k
    SET_BOOL_PARAM(arithmetic);
743
142k
    break;
744
24.3k
  case TJPARAM_LOSSLESS:
745
24.3k
    if (!(this->init & COMPRESS))
746
24.3k
      THROW("TJPARAM_LOSSLESS is read-only in decompression instances.");
747
24.3k
    SET_BOOL_PARAM(lossless);
748
24.3k
    break;
749
24.3k
  case TJPARAM_LOSSLESSPSV:
750
24.3k
    if (!(this->init & COMPRESS))
751
24.3k
      THROW("TJPARAM_LOSSLESSPSV is read-only in decompression instances.");
752
24.3k
    SET_PARAM(losslessPSV, 1, 7);
753
24.3k
    break;
754
24.3k
  case TJPARAM_LOSSLESSPT:
755
24.3k
    if (!(this->init & COMPRESS))
756
24.3k
      THROW("TJPARAM_LOSSLESSPT is read-only in decompression instances.");
757
24.3k
    SET_PARAM(losslessPt, 0, 15);
758
24.3k
    break;
759
40.3k
  case TJPARAM_RESTARTBLOCKS:
760
40.3k
    if (!(this->init & COMPRESS))
761
40.3k
      THROW("TJPARAM_RESTARTBLOCKS is not applicable to decompression instances.");
762
40.3k
    SET_PARAM(restartIntervalBlocks, 0, 65535);
763
40.3k
    if (value != 0) this->restartIntervalRows = 0;
764
40.3k
    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
214k
  case TJPARAM_MAXPIXELS:
790
214k
    SET_PARAM(maxPixels, 0, -1);
791
214k
    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.79M
  }
800
801
1.79M
bailout:
802
1.79M
  return retval;
803
1.79M
}
804
805
806
/* TurboJPEG 3.0+ */
807
DLLEXPORT int tj3Get(tjhandle handle, int param)
808
212k
{
809
212k
  tjinstance *this = (tjinstance *)handle;
810
212k
  if (!this) return -1;
811
812
212k
  switch (param) {
813
0
  case TJPARAM_STOPONWARNING:
814
0
    return this->jerr.stopOnWarning;
815
0
  case TJPARAM_BOTTOMUP:
816
0
    return this->bottomUp;
817
76.3k
  case TJPARAM_NOREALLOC:
818
76.3k
    return this->noRealloc;
819
0
  case TJPARAM_QUALITY:
820
0
    return this->quality;
821
22.8k
  case TJPARAM_SUBSAMP:
822
22.8k
    return this->subsamp;
823
36.4k
  case TJPARAM_JPEGWIDTH:
824
36.4k
    return this->jpegWidth;
825
36.4k
  case TJPARAM_JPEGHEIGHT:
826
36.4k
    return this->jpegHeight;
827
13.6k
  case TJPARAM_PRECISION:
828
13.6k
    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.2k
  case TJPARAM_LOSSLESS:
844
26.2k
    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
212k
  }
866
867
0
  return -1;
868
212k
}
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
222k
{
879
222k
  return MALLOC(bytes);
880
222k
}
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
197k
{
892
197k
  free(buf);
893
197k
}
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
249k
{
905
249k
  static const char FUNCTION_NAME[] = "tj3JPEGBufSize";
906
249k
  unsigned long long retval = 0;
907
249k
  int mcuw, mcuh, chromasf;
908
909
249k
  if (width < 1 || height < 1 || jpegSubsamp < TJSAMP_UNKNOWN ||
910
249k
      jpegSubsamp >= TJ_NUMSAMP)
911
249k
    THROWG("Invalid argument", 0);
912
913
249k
  if (jpegSubsamp == TJSAMP_UNKNOWN)
914
13.3k
    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
249k
  mcuw = tjMCUWidth[jpegSubsamp];
920
249k
  mcuh = tjMCUHeight[jpegSubsamp];
921
249k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
922
249k
  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
249k
bailout:
929
249k
  return (size_t)retval;
930
249k
}
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.3k
{
973
48.3k
  static const char FUNCTION_NAME[] = "tj3YUVBufSize";
974
48.3k
  unsigned long long retval = 0;
975
48.3k
  int nc, i;
976
977
48.3k
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
978
48.1k
    THROWG("Invalid argument", 0);
979
980
48.1k
  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.3k
bailout:
995
48.3k
  return (size_t)retval;
996
48.1k
}
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
278k
{
1059
278k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneWidth";
1060
278k
  unsigned long long pw, retval = 0;
1061
278k
  int nc;
1062
1063
278k
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1064
278k
    THROWG("Invalid argument", 0);
1065
278k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1066
278k
  if (componentID < 0 || componentID >= nc)
1067
278k
    THROWG("Invalid argument", 0);
1068
1069
278k
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
1070
278k
  if (componentID == 0)
1071
147k
    retval = pw;
1072
131k
  else
1073
131k
    retval = pw * 8 / tjMCUWidth[subsamp];
1074
1075
278k
  if (retval > (unsigned long long)INT_MAX)
1076
278k
    THROWG("Width is too large", 0);
1077
1078
278k
bailout:
1079
278k
  return (int)retval;
1080
278k
}
1081
1082
/* TurboJPEG 1.4+ */
1083
DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
1084
22.4k
{
1085
22.4k
  int retval = tj3YUVPlaneWidth(componentID, width, subsamp);
1086
22.4k
  return (retval == 0) ? -1 : retval;
1087
22.4k
}
1088
1089
1090
/* TurboJPEG 3.0+ */
1091
DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp)
1092
278k
{
1093
278k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneHeight";
1094
278k
  unsigned long long ph, retval = 0;
1095
278k
  int nc;
1096
1097
278k
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1098
278k
    THROWG("Invalid argument", 0);
1099
278k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1100
278k
  if (componentID < 0 || componentID >= nc)
1101
278k
    THROWG("Invalid argument", 0);
1102
1103
278k
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
1104
278k
  if (componentID == 0)
1105
147k
    retval = ph;
1106
131k
  else
1107
131k
    retval = ph * 8 / tjMCUHeight[subsamp];
1108
1109
278k
  if (retval > (unsigned long long)INT_MAX)
1110
278k
    THROWG("Height is too large", 0);
1111
1112
278k
bailout:
1113
278k
  return (int)retval;
1114
278k
}
1115
1116
/* TurboJPEG 1.4+ */
1117
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
1118
22.4k
{
1119
22.4k
  int retval = tj3YUVPlaneHeight(componentID, height, subsamp);
1120
22.4k
  return (retval == 0) ? -1 : retval;
1121
22.4k
}
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
227k
#define BITS_IN_JSAMPLE  8
1194
#include "turbojpeg-mp.c"
1195
#undef BITS_IN_JSAMPLE
1196
188k
#define BITS_IN_JSAMPLE  12
1197
#include "turbojpeg-mp.c"
1198
#undef BITS_IN_JSAMPLE
1199
92.6k
#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.5k
{
1265
21.5k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUVPlanes8";
1266
21.5k
  int i, row, retval = 0;
1267
21.5k
  boolean alloc = TRUE;
1268
21.5k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1269
21.5k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1270
21.5k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1271
21.5k
  JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1272
1273
21.5k
  GET_CINSTANCE(handle)
1274
1275
237k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1276
215k
    tmpbuf[i] = NULL;  inbuf[i] = NULL;
1277
215k
  }
1278
1279
21.5k
  if ((this->init & COMPRESS) == 0)
1280
21.5k
    THROW("Instance has not been initialized for compression");
1281
1282
21.5k
  if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
1283
21.5k
      jpegBuf == NULL || jpegSize == NULL)
1284
21.5k
    THROW("Invalid argument");
1285
21.5k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1286
21.5k
    THROW("Invalid argument");
1287
1288
21.5k
  if (this->quality == -1)
1289
21.5k
    THROW("TJPARAM_QUALITY must be specified");
1290
21.5k
  if (this->subsamp == TJSAMP_UNKNOWN)
1291
21.5k
    THROW("TJPARAM_SUBSAMP must be specified");
1292
1293
21.5k
  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.5k
  cinfo->image_width = width;
1299
21.5k
  cinfo->image_height = height;
1300
21.5k
  cinfo->data_precision = 8;
1301
1302
21.5k
  if (this->noRealloc) alloc = FALSE;
1303
21.5k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1304
21.5k
  setCompDefaults(this, TJPF_RGB, TRUE);
1305
21.5k
  cinfo->raw_data_in = TRUE;
1306
1307
21.5k
  jpeg_start_compress(cinfo, TRUE);
1308
21.5k
  if (this->iccBuf != NULL && this->iccSize != 0)
1309
0
    jpeg_write_icc_profile(cinfo, this->iccBuf, (unsigned int)this->iccSize);
1310
72.6k
  for (i = 0; i < cinfo->num_components; i++) {
1311
51.0k
    jpeg_component_info *compptr = &cinfo->comp_info[i];
1312
51.0k
    int ih;
1313
1314
51.0k
    iw[i] = compptr->width_in_blocks * DCTSIZE;
1315
51.0k
    ih = compptr->height_in_blocks * DCTSIZE;
1316
51.0k
    pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
1317
51.0k
            compptr->h_samp_factor / cinfo->max_h_samp_factor;
1318
51.0k
    ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
1319
51.0k
            compptr->v_samp_factor / cinfo->max_v_samp_factor;
1320
51.0k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1321
51.0k
    th[i] = compptr->v_samp_factor * DCTSIZE;
1322
51.0k
    tmpbufsize += iw[i] * th[i];
1323
51.0k
    if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1324
51.0k
      THROW("Memory allocation failure");
1325
51.0k
    ptr = (JSAMPLE *)srcPlanes[i];
1326
149M
    for (row = 0; row < ph[i]; row++) {
1327
149M
      inbuf[i][row] = ptr;
1328
149M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1329
149M
    }
1330
51.0k
  }
1331
21.5k
  if (usetmpbuf) {
1332
21.4k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1333
21.4k
      THROW("Memory allocation failure");
1334
21.4k
    ptr = _tmpbuf;
1335
72.1k
    for (i = 0; i < cinfo->num_components; i++) {
1336
50.7k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1337
50.7k
        THROW("Memory allocation failure");
1338
486k
      for (row = 0; row < th[i]; row++) {
1339
435k
        tmpbuf[i][row] = ptr;
1340
435k
        ptr += iw[i];
1341
435k
      }
1342
50.7k
    }
1343
21.4k
  }
1344
1345
21.5k
  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
7.84M
  for (row = 0; row < (int)cinfo->image_height;
1351
7.82M
       row += cinfo->max_v_samp_factor * DCTSIZE) {
1352
7.82M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1353
7.82M
    int crow[MAX_COMPONENTS];
1354
1355
25.8M
    for (i = 0; i < cinfo->num_components; i++) {
1356
18.0M
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1357
1358
18.0M
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1359
18.0M
      if (usetmpbuf) {
1360
18.0M
        int j, k;
1361
1362
167M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1363
149M
          memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1364
          /* Duplicate last sample in row to fill out MCU */
1365
1.09G
          for (k = pw[i]; k < iw[i]; k++)
1366
949M
            tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1367
149M
        }
1368
        /* Duplicate last row to fill out MCU */
1369
18.2M
        for (j = ph[i] - crow[i]; j < th[i]; j++)
1370
277k
          memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1371
18.0M
        yuvptr[i] = tmpbuf[i];
1372
18.0M
      } else
1373
1.06k
        yuvptr[i] = &inbuf[i][crow[i]];
1374
18.0M
    }
1375
7.82M
    jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1376
7.82M
  }
1377
21.5k
  jpeg_finish_compress(cinfo);
1378
1379
21.5k
bailout:
1380
21.5k
  if (cinfo->global_state > CSTATE_START && alloc)
1381
0
    (*cinfo->dest->term_destination) (cinfo);
1382
21.5k
  if (cinfo->global_state > CSTATE_START || retval == -1)
1383
0
    jpeg_abort_compress(cinfo);
1384
237k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1385
215k
    free(tmpbuf[i]);
1386
215k
    free(inbuf[i]);
1387
215k
  }
1388
21.5k
  free(_tmpbuf);
1389
21.5k
  if (this->jerr.warning) retval = -1;
1390
21.5k
  return retval;
1391
21.5k
}
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.7k
{
1434
32.7k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUV8";
1435
32.7k
  const unsigned char *srcPlanes[3];
1436
32.7k
  int pw0, ph0, strides[3], retval = -1;
1437
1438
32.7k
  GET_TJINSTANCE(handle, -1);
1439
1440
32.7k
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1441
32.7k
      height <= 0)
1442
32.7k
    THROW("Invalid argument");
1443
1444
32.7k
  if (this->subsamp == TJSAMP_UNKNOWN)
1445
32.7k
    THROW("TJPARAM_SUBSAMP must be specified");
1446
1447
32.7k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1448
32.7k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1449
32.7k
  srcPlanes[0] = srcBuf;
1450
32.7k
  strides[0] = PAD(pw0, align);
1451
32.7k
  if (this->subsamp == TJSAMP_GRAY) {
1452
10.3k
    strides[1] = strides[2] = 0;
1453
10.3k
    srcPlanes[1] = srcPlanes[2] = NULL;
1454
22.4k
  } else {
1455
22.4k
    int pw1 = tjPlaneWidth(1, width, this->subsamp);
1456
22.4k
    int ph1 = tjPlaneHeight(1, height, this->subsamp);
1457
1458
22.4k
    strides[1] = strides[2] = PAD(pw1, align);
1459
22.4k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1460
22.4k
        (unsigned long long)INT_MAX ||
1461
22.4k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1462
22.4k
        (unsigned long long)INT_MAX)
1463
22.4k
      THROW("Image or row alignment is too large");
1464
22.4k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1465
22.4k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1466
22.4k
  }
1467
1468
32.7k
  return tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
1469
32.7k
                                   jpegBuf, jpegSize);
1470
1471
0
bailout:
1472
0
  return retval;
1473
32.7k
}
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
32.9k
{
1513
32.9k
  static const char FUNCTION_NAME[] = "tj3EncodeYUVPlanes8";
1514
32.9k
  JSAMPROW *row_pointer = NULL;
1515
32.9k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
1516
32.9k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
1517
32.9k
  JSAMPROW *outbuf[MAX_COMPONENTS];
1518
32.9k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1519
32.9k
  JSAMPLE *ptr;
1520
32.9k
  jpeg_component_info *compptr;
1521
1522
32.9k
  GET_CINSTANCE(handle)
1523
1524
362k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1525
329k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
1526
329k
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
1527
329k
  }
1528
1529
32.9k
  if ((this->init & COMPRESS) == 0)
1530
32.9k
    THROW("Instance has not been initialized for compression");
1531
1532
32.9k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1533
32.9k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
1534
32.9k
      !dstPlanes[0])
1535
32.9k
    THROW("Invalid argument");
1536
32.9k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1537
32.9k
    THROW("Invalid argument");
1538
1539
32.9k
  if (this->subsamp == TJSAMP_UNKNOWN)
1540
32.9k
    THROW("TJPARAM_SUBSAMP must be specified");
1541
32.9k
  if (pixelFormat == TJPF_CMYK)
1542
32.9k
    THROW("Cannot generate YUV images from packed-pixel CMYK images");
1543
1544
32.9k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1545
1546
32.9k
  if (setjmp(this->jerr.setjmp_buffer)) {
1547
    /* If we get here, the JPEG code has signaled an error. */
1548
155
    retval = -1;  goto bailout;
1549
155
  }
1550
1551
32.7k
  cinfo->image_width = width;
1552
32.7k
  cinfo->image_height = height;
1553
32.7k
  cinfo->data_precision = 8;
1554
1555
32.7k
  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.7k
  if (cinfo->global_state != CSTATE_START)
1562
32.7k
    THROW("libjpeg API is in the wrong state");
1563
32.7k
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
1564
32.7k
  jinit_c_master_control(cinfo, FALSE);
1565
32.7k
  jinit_color_converter(cinfo);
1566
32.7k
  jinit_downsampler(cinfo);
1567
32.7k
  (*cinfo->cconvert->start_pass) (cinfo);
1568
1569
32.7k
  pw0 = PAD(width, cinfo->max_h_samp_factor);
1570
32.7k
  ph0 = PAD(height, cinfo->max_v_samp_factor);
1571
1572
32.7k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1573
32.7k
    THROW("Memory allocation failure");
1574
105M
  for (i = 0; i < height; i++) {
1575
105M
    if (this->bottomUp)
1576
17.8M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
1577
87.6M
    else
1578
87.6M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
1579
105M
  }
1580
32.7k
  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.6k
    compptr = &cinfo->comp_info[i];
1585
77.6k
    _tmpbuf[i] = (JSAMPLE *)MALLOC(
1586
77.6k
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1587
77.6k
          compptr->h_samp_factor, 32) *
1588
77.6k
      cinfo->max_v_samp_factor + 32);
1589
77.6k
    if (!_tmpbuf[i])
1590
77.6k
      THROW("Memory allocation failure");
1591
77.6k
    tmpbuf[i] =
1592
77.6k
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
1593
77.6k
    if (!tmpbuf[i])
1594
77.6k
      THROW("Memory allocation failure");
1595
172k
    for (row = 0; row < cinfo->max_v_samp_factor; row++) {
1596
94.4k
      unsigned char *_tmpbuf_aligned =
1597
94.4k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
1598
1599
94.4k
      tmpbuf[i][row] = &_tmpbuf_aligned[
1600
94.4k
        PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1601
94.4k
            compptr->h_samp_factor, 32) * row];
1602
94.4k
    }
1603
77.6k
    _tmpbuf2[i] =
1604
77.6k
      (JSAMPLE *)MALLOC(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1605
77.6k
                        compptr->v_samp_factor + 32);
1606
77.6k
    if (!_tmpbuf2[i])
1607
77.6k
      THROW("Memory allocation failure");
1608
77.6k
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1609
77.6k
    if (!tmpbuf2[i])
1610
77.6k
      THROW("Memory allocation failure");
1611
160k
    for (row = 0; row < compptr->v_samp_factor; row++) {
1612
83.2k
      unsigned char *_tmpbuf2_aligned =
1613
83.2k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
1614
1615
83.2k
      tmpbuf2[i][row] =
1616
83.2k
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1617
83.2k
    }
1618
77.6k
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
1619
77.6k
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1620
77.6k
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1621
77.6k
    if (!outbuf[i])
1622
77.6k
      THROW("Memory allocation failure");
1623
77.6k
    ptr = dstPlanes[i];
1624
230M
    for (row = 0; row < ph[i]; row++) {
1625
230M
      outbuf[i][row] = ptr;
1626
230M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1627
230M
    }
1628
77.6k
  }
1629
1630
32.7k
  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
96.6M
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
1636
96.6M
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
1637
96.6M
                                       cinfo->max_v_samp_factor);
1638
96.6M
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
1639
318M
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
1640
221M
         i++, compptr++)
1641
221M
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
1642
221M
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
1643
221M
        compptr->v_samp_factor, pw[i]);
1644
96.6M
  }
1645
32.7k
  cinfo->next_scanline += height;
1646
32.7k
  jpeg_abort_compress(cinfo);
1647
1648
32.9k
bailout:
1649
32.9k
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1650
32.9k
  free(row_pointer);
1651
362k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1652
329k
    free(tmpbuf[i]);
1653
329k
    free(_tmpbuf[i]);
1654
329k
    free(tmpbuf2[i]);
1655
329k
    free(_tmpbuf2[i]);
1656
329k
    free(outbuf[i]);
1657
329k
  }
1658
32.9k
  if (this->jerr.warning) retval = -1;
1659
32.9k
  return retval;
1660
32.7k
}
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
32.9k
{
1692
32.9k
  static const char FUNCTION_NAME[] = "tj3EncodeYUV8";
1693
32.9k
  unsigned char *dstPlanes[3];
1694
32.9k
  int pw0, ph0, strides[3], retval = -1;
1695
1696
32.9k
  GET_TJINSTANCE(handle, -1);
1697
1698
32.9k
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
1699
32.9k
      !IS_POW2(align))
1700
32.9k
    THROW("Invalid argument");
1701
1702
32.9k
  if (this->subsamp == TJSAMP_UNKNOWN)
1703
32.9k
    THROW("TJPARAM_SUBSAMP must be specified");
1704
1705
32.9k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1706
32.9k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1707
32.9k
  dstPlanes[0] = dstBuf;
1708
32.9k
  strides[0] = PAD(pw0, align);
1709
32.9k
  if (this->subsamp == TJSAMP_GRAY) {
1710
10.4k
    strides[1] = strides[2] = 0;
1711
10.4k
    dstPlanes[1] = dstPlanes[2] = NULL;
1712
22.5k
  } else {
1713
22.5k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
1714
22.5k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
1715
1716
22.5k
    strides[1] = strides[2] = PAD(pw1, align);
1717
22.5k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1718
22.5k
        (unsigned long long)INT_MAX ||
1719
22.5k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1720
22.5k
        (unsigned long long)INT_MAX)
1721
22.5k
      THROW("Image or row alignment is too large");
1722
22.5k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1723
22.5k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1724
22.5k
  }
1725
1726
32.9k
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1727
32.9k
                             dstPlanes, strides);
1728
1729
0
bailout:
1730
0
  return retval;
1731
32.9k
}
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.2k
{
1781
54.2k
  static unsigned char buffer[1];
1782
1783
  /* This is also straight out of example.c */
1784
54.2k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1785
54.2k
  this->jerr.pub.error_exit = my_error_exit;
1786
54.2k
  this->jerr.pub.output_message = my_output_message;
1787
54.2k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1788
54.2k
  this->jerr.pub.emit_message = my_emit_message;
1789
54.2k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1790
54.2k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1791
54.2k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1792
1793
54.2k
  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.2k
  jpeg_create_decompress(&this->dinfo);
1800
  /* Make an initial call so it will create the source manager */
1801
54.2k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1802
1803
54.2k
  this->init |= DECOMPRESS;
1804
54.2k
  return (tjhandle)this;
1805
54.2k
}
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.4k
{
1819
36.4k
  static const char FUNCTION_NAME[] = "tj3DecompressHeader";
1820
36.4k
  int retval = 0;
1821
36.4k
  unsigned char *iccPtr = NULL;
1822
36.4k
  unsigned int iccLen = 0;
1823
1824
36.4k
  GET_DINSTANCE(handle);
1825
36.4k
  if ((this->init & DECOMPRESS) == 0)
1826
36.4k
    THROW("Instance has not been initialized for decompression");
1827
1828
36.4k
  if (jpegBuf == NULL || jpegSize <= 0)
1829
36.4k
    THROW("Invalid argument");
1830
1831
36.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
1832
    /* If we get here, the JPEG code has signaled an error. */
1833
3.65k
    return -1;
1834
3.65k
  }
1835
1836
32.8k
  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
32.8k
  if (this->saveMarkers == 2 || this->saveMarkers == 4)
1843
36.4k
    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
32.8k
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1849
3.88k
    return 0;
1850
1851
28.9k
  setDecompParameters(this);
1852
1853
28.9k
  if (this->saveMarkers == 2 || this->saveMarkers == 4) {
1854
28.9k
    if (jpeg_read_icc_profile(dinfo, &iccPtr, &iccLen)) {
1855
1.12k
      free(this->tempICCBuf);
1856
1.12k
      this->tempICCBuf = iccPtr;
1857
1.12k
      this->tempICCSize = (size_t)iccLen;
1858
1.12k
    }
1859
28.9k
  }
1860
1861
28.9k
  jpeg_abort_decompress(dinfo);
1862
1863
28.9k
  if (this->colorspace < 0)
1864
28.9k
    THROW("Could not determine colorspace of JPEG image");
1865
28.7k
  if (this->jpegWidth < 1 || this->jpegHeight < 1)
1866
28.7k
    THROW("Invalid data returned in header");
1867
1868
28.9k
bailout:
1869
28.9k
  if (this->jerr.warning) retval = -1;
1870
28.9k
  return retval;
1871
28.7k
}
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.8k
{
1984
30.8k
  static const char FUNCTION_NAME[] = "tj3SetScalingFactor";
1985
30.8k
  int i, retval = 0;
1986
1987
30.8k
  GET_TJINSTANCE(handle, -1);
1988
30.8k
  if ((this->init & DECOMPRESS) == 0)
1989
30.8k
    THROW("Instance has not been initialized for decompression");
1990
1991
288k
  for (i = 0; i < NUMSF; i++) {
1992
288k
    if (scalingFactor.num == sf[i].num && scalingFactor.denom == sf[i].denom)
1993
30.8k
      break;
1994
288k
  }
1995
30.8k
  if (i >= NUMSF)
1996
30.8k
    THROW("Unsupported scaling factor");
1997
1998
30.8k
  this->scalingFactor = scalingFactor;
1999
2000
30.8k
bailout:
2001
30.8k
  return retval;
2002
30.8k
}
2003
2004
2005
/* TurboJPEG 3.0+ */
2006
DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion)
2007
12.8k
{
2008
12.8k
  static const char FUNCTION_NAME[] = "tj3SetCroppingRegion";
2009
12.8k
  int retval = 0, scaledWidth, scaledHeight;
2010
2011
12.8k
  GET_TJINSTANCE(handle, -1);
2012
12.8k
  if ((this->init & DECOMPRESS) == 0)
2013
12.8k
    THROW("Instance has not been initialized for decompression");
2014
2015
12.8k
  if (croppingRegion.x == 0 && croppingRegion.y == 0 &&
2016
12.5k
      croppingRegion.w == 0 && croppingRegion.h == 0) {
2017
12.5k
    this->croppingRegion = croppingRegion;
2018
12.5k
    return 0;
2019
12.5k
  }
2020
2021
237
  if (croppingRegion.x < 0 || croppingRegion.y < 0 || croppingRegion.w < 0 ||
2022
237
      croppingRegion.h < 0)
2023
237
    THROW("Invalid cropping region");
2024
237
  if (this->jpegWidth < 0 || this->jpegHeight < 0)
2025
237
    THROW("JPEG header has not yet been read");
2026
237
  if ((this->precision != 8 && this->precision != 12) || this->lossless)
2027
237
    THROW("Cannot partially decompress lossless JPEG images");
2028
237
  if (this->subsamp == TJSAMP_UNKNOWN)
2029
237
    THROW("Could not determine subsampling level of JPEG image");
2030
2031
193
  scaledWidth = TJSCALED(this->jpegWidth, this->scalingFactor);
2032
193
  scaledHeight = TJSCALED(this->jpegHeight, this->scalingFactor);
2033
2034
193
  if (croppingRegion.x %
2035
193
      TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor) != 0)
2036
0
    THROWI("The left boundary of the cropping region (%d) is not\n"
2037
193
           "divisible by the scaled iMCU width (%d)",
2038
193
           croppingRegion.x,
2039
193
           TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor));
2040
193
  if (croppingRegion.w == 0)
2041
0
    croppingRegion.w = scaledWidth - croppingRegion.x;
2042
193
  if (croppingRegion.h == 0)
2043
0
    croppingRegion.h = scaledHeight - croppingRegion.y;
2044
193
  if (croppingRegion.w <= 0 || croppingRegion.h <= 0 ||
2045
193
      croppingRegion.x + croppingRegion.w > scaledWidth ||
2046
193
      croppingRegion.y + croppingRegion.h > scaledHeight)
2047
193
    THROW("The cropping region exceeds the scaled image dimensions");
2048
2049
193
  this->croppingRegion = croppingRegion;
2050
2051
237
bailout:
2052
237
  return retval;
2053
193
}
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.2k
  for (i = 0; i < dinfo->num_components; i++) {
2189
30.9k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
2190
30.9k
    int ih;
2191
2192
30.9k
    iw[i] = compptr->width_in_blocks * dctsize;
2193
30.9k
    ih = compptr->height_in_blocks * dctsize;
2194
30.9k
    pw[i] = tj3YUVPlaneWidth(i, dinfo->output_width, this->subsamp);
2195
30.9k
    ph[i] = tj3YUVPlaneHeight(i, dinfo->output_height, this->subsamp);
2196
30.9k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
2197
30.9k
    th[i] = compptr->v_samp_factor * dctsize;
2198
30.9k
    tmpbufsize += iw[i] * th[i];
2199
30.9k
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
2200
30.9k
      THROW("Memory allocation failure");
2201
30.9k
    ptr = dstPlanes[i];
2202
191M
    for (row = 0; row < ph[i]; row++) {
2203
191M
      outbuf[i][row] = ptr;
2204
191M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2205
191M
    }
2206
30.9k
  }
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.4k
    for (i = 0; i < dinfo->num_components; i++) {
2212
27.9k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
2213
27.9k
        THROW("Memory allocation failure");
2214
354k
      for (row = 0; row < th[i]; row++) {
2215
326k
        tmpbuf[i][row] = ptr;
2216
326k
        ptr += iw[i];
2217
326k
      }
2218
27.9k
    }
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.65k
    retval = -1;  goto bailout;
2224
7.65k
  }
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.40M
  for (row = 0; row < (int)dinfo->output_height;
2234
3.39M
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
2235
3.39M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
2236
3.39M
    int crow[MAX_COMPONENTS];
2237
2238
9.62M
    for (i = 0; i < dinfo->num_components; i++) {
2239
6.23M
      jpeg_component_info *compptr = &dinfo->comp_info[i];
2240
2241
6.23M
      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.67M
        compptr->_DCT_scaled_size = dctsize;
2253
1.67M
        compptr->MCU_sample_width = tjMCUWidth[this->subsamp] *
2254
1.67M
          this->scalingFactor.num / this->scalingFactor.denom *
2255
1.67M
          compptr->v_samp_factor / dinfo->max_v_samp_factor;
2256
1.67M
        dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
2257
1.67M
      }
2258
6.23M
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2259
6.23M
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
2260
645k
      else yuvptr[i] = &outbuf[i][crow[i]];
2261
6.23M
    }
2262
3.39M
    jpeg_read_raw_data(dinfo, yuvptr,
2263
3.39M
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
2264
3.39M
    if (usetmpbuf) {
2265
3.02M
      int j;
2266
2267
8.60M
      for (i = 0; i < dinfo->num_components; i++) {
2268
63.0M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
2269
57.4M
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
2270
57.4M
        }
2271
5.57M
      }
2272
3.02M
    }
2273
3.39M
  }
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.30k
    strides[1] = strides[2] = 0;
2376
7.30k
    dstPlanes[1] = dstPlanes[2] = NULL;
2377
7.91k
  } else {
2378
7.91k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2379
7.91k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2380
2381
7.91k
    strides[1] = strides[2] = PAD(pw1, align);
2382
7.91k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2383
7.91k
        (unsigned long long)INT_MAX ||
2384
7.91k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2385
7.91k
        (unsigned long long)INT_MAX)
2386
7.91k
      THROW("Image or row alignment is too large");
2387
7.91k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
2388
7.91k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
2389
7.91k
  }
2390
2391
15.2k
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2392
15.2k
                                   strides);
2393
2394
150
bailout:
2395
150
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2396
150
  if (this->jerr.warning) retval = -1;
2397
150
  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.89k
{
2459
2.89k
  int i;
2460
2461
2.89k
  this->dinfo.scale_num = this->dinfo.scale_denom = 1;
2462
2463
2.89k
  if (this->subsamp == TJSAMP_GRAY) {
2464
1.28k
    this->dinfo.num_components = this->dinfo.comps_in_scan = 1;
2465
1.28k
    this->dinfo.jpeg_color_space = JCS_GRAYSCALE;
2466
1.60k
  } else {
2467
1.60k
    this->dinfo.num_components = this->dinfo.comps_in_scan = 3;
2468
1.60k
    this->dinfo.jpeg_color_space = JCS_YCbCr;
2469
1.60k
  }
2470
2471
2.89k
  this->dinfo.comp_info = (jpeg_component_info *)
2472
2.89k
    (*this->dinfo.mem->alloc_small) ((j_common_ptr)&this->dinfo, JPOOL_IMAGE,
2473
2.89k
                                     this->dinfo.num_components *
2474
2.89k
                                     sizeof(jpeg_component_info));
2475
2476
8.99k
  for (i = 0; i < this->dinfo.num_components; i++) {
2477
6.09k
    jpeg_component_info *compptr = &this->dinfo.comp_info[i];
2478
2479
6.09k
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[this->subsamp] / 8 : 1;
2480
6.09k
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[this->subsamp] / 8 : 1;
2481
6.09k
    compptr->component_index = i;
2482
6.09k
    compptr->component_id = i + 1;
2483
6.09k
    compptr->quant_tbl_no = compptr->dc_tbl_no =
2484
6.09k
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
2485
6.09k
    this->dinfo.cur_comp_info[i] = compptr;
2486
6.09k
  }
2487
2.89k
  this->dinfo.data_precision = 8;
2488
8.67k
  for (i = 0; i < 2; i++) {
2489
5.78k
    if (this->dinfo.quant_tbl_ptrs[i] == NULL)
2490
969
      this->dinfo.quant_tbl_ptrs[i] =
2491
969
        jpeg_alloc_quant_table((j_common_ptr)&this->dinfo);
2492
5.78k
  }
2493
2494
2.89k
  this->dinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2495
2.89k
}
2496
2497
2498
static int my_read_markers(j_decompress_ptr dinfo)
2499
2.89k
{
2500
2.89k
  return JPEG_REACHED_SOS;
2501
2.89k
}
2502
2503
static void my_reset_marker_reader(j_decompress_ptr dinfo)
2504
2.89k
{
2505
2.89k
}
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.89k
{
2514
2.89k
  static const char FUNCTION_NAME[] = "tj3DecodeYUVPlanes8";
2515
2.89k
  JSAMPROW *row_pointer = NULL;
2516
2.89k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS];
2517
2.89k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
2518
2.89k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
2519
2.89k
  JSAMPLE *ptr;
2520
2.89k
  jpeg_component_info *compptr;
2521
2.89k
  int (*old_read_markers) (j_decompress_ptr);
2522
2.89k
  void (*old_reset_marker_reader) (j_decompress_ptr);
2523
2524
2.89k
  GET_DINSTANCE(handle);
2525
2526
31.8k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2527
28.9k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;  inbuf[i] = NULL;
2528
28.9k
  }
2529
2530
2.89k
  if ((this->init & DECOMPRESS) == 0)
2531
2.89k
    THROW("Instance has not been initialized for decompression");
2532
2533
2.89k
  if (!srcPlanes || !srcPlanes[0] || dstBuf == NULL || width <= 0 ||
2534
2.89k
      pitch < 0 || height <= 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
2535
2.89k
    THROW("Invalid argument");
2536
2.89k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
2537
2.89k
    THROW("Invalid argument");
2538
2539
2.89k
  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.88k
  if (this->subsamp == TJSAMP_UNKNOWN)
2545
2.88k
    THROW("TJPARAM_SUBSAMP must be specified");
2546
2.88k
  if (pixelFormat == TJPF_CMYK)
2547
2.88k
    THROW("Cannot decode YUV images into packed-pixel CMYK images.");
2548
2549
2.89k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
2550
2.88k
  dinfo->image_width = width;
2551
2.88k
  dinfo->image_height = height;
2552
2553
2.88k
  dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
2554
2.88k
  dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
2555
2.88k
  dinfo->Se = DCTSIZE2 - 1;
2556
2.88k
  setDecodeDefaults(this, pixelFormat);
2557
2.88k
  old_read_markers = dinfo->marker->read_markers;
2558
2.88k
  dinfo->marker->read_markers = my_read_markers;
2559
2.88k
  old_reset_marker_reader = dinfo->marker->reset_marker_reader;
2560
2.88k
  dinfo->marker->reset_marker_reader = my_reset_marker_reader;
2561
2.88k
  jpeg_read_header(dinfo, TRUE);
2562
2.88k
  dinfo->marker->read_markers = old_read_markers;
2563
2.88k
  dinfo->marker->reset_marker_reader = old_reset_marker_reader;
2564
2565
2.88k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
2566
2.88k
  this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2567
2.88k
  dinfo->do_fancy_upsampling = FALSE;
2568
2.88k
  dinfo->Se = DCTSIZE2 - 1;
2569
2.88k
  jinit_master_decompress(dinfo);
2570
2.88k
  (*dinfo->upsample->start_pass) (dinfo);
2571
2572
2.88k
  pw0 = PAD(width, dinfo->max_h_samp_factor);
2573
2.88k
  ph0 = PAD(height, dinfo->max_v_samp_factor);
2574
2575
2.88k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
2576
2577
2.88k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
2578
2.88k
    THROW("Memory allocation failure");
2579
14.9M
  for (i = 0; i < height; i++) {
2580
14.9M
    if (this->bottomUp)
2581
5.42M
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
2582
9.47M
    else
2583
9.47M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
2584
14.9M
  }
2585
2.88k
  if (height < ph0)
2586
1.08k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
2587
2588
8.97k
  for (i = 0; i < dinfo->num_components; i++) {
2589
6.08k
    compptr = &dinfo->comp_info[i];
2590
6.08k
    _tmpbuf[i] =
2591
6.08k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
2592
6.08k
                        compptr->v_samp_factor + 32);
2593
6.08k
    if (!_tmpbuf[i])
2594
6.08k
      THROW("Memory allocation failure");
2595
6.08k
    tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
2596
6.08k
    if (!tmpbuf[i])
2597
6.08k
      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.08k
    pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
2606
6.08k
    ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2607
6.08k
    inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
2608
6.08k
    if (!inbuf[i])
2609
6.08k
      THROW("Memory allocation failure");
2610
6.08k
    ptr = (JSAMPLE *)srcPlanes[i];
2611
25.9M
    for (row = 0; row < ph[i]; row++) {
2612
25.9M
      inbuf[i][row] = ptr;
2613
25.9M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2614
25.9M
    }
2615
6.08k
  }
2616
2617
2.88k
  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.8M
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
2623
12.8M
    JDIMENSION inrow = 0, outrow = 0;
2624
2625
36.7M
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
2626
23.8M
         i++, compptr++)
2627
23.8M
      jcopy_sample_rows(inbuf[i],
2628
23.8M
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
2629
23.8M
        compptr->v_samp_factor, pw[i]);
2630
12.8M
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
2631
12.8M
                                 dinfo->max_v_samp_factor, &row_pointer[row],
2632
12.8M
                                 &outrow, dinfo->max_v_samp_factor);
2633
12.8M
  }
2634
2.88k
  jpeg_abort_decompress(dinfo);
2635
2636
2.89k
bailout:
2637
2.89k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2638
2.89k
  free(row_pointer);
2639
31.8k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2640
28.9k
    free(tmpbuf[i]);
2641
28.9k
    free(_tmpbuf[i]);
2642
28.9k
    free(inbuf[i]);
2643
28.9k
  }
2644
2.89k
  if (this->jerr.warning) retval = -1;
2645
2.89k
  return retval;
2646
2.88k
}
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.89k
{
2679
2.89k
  static const char FUNCTION_NAME[] = "tj3DecodeYUV8";
2680
2.89k
  const unsigned char *srcPlanes[3];
2681
2.89k
  int pw0, ph0, strides[3], retval = -1;
2682
2683
2.89k
  GET_TJINSTANCE(handle, -1);
2684
2685
2.89k
  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || width <= 0 ||
2686
2.89k
      height <= 0)
2687
2.89k
    THROW("Invalid argument");
2688
2689
2.89k
  if (this->subsamp == TJSAMP_UNKNOWN)
2690
2.89k
    THROW("TJPARAM_SUBSAMP must be specified");
2691
2692
2.89k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2693
2.89k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2694
2.89k
  srcPlanes[0] = srcBuf;
2695
2.89k
  strides[0] = PAD(pw0, align);
2696
2.89k
  if (this->subsamp == TJSAMP_GRAY) {
2697
1.28k
    strides[1] = strides[2] = 0;
2698
1.28k
    srcPlanes[1] = srcPlanes[2] = NULL;
2699
1.60k
  } else {
2700
1.60k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2701
1.60k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2702
2703
1.60k
    strides[1] = strides[2] = PAD(pw1, align);
2704
1.60k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2705
1.60k
        (unsigned long long)INT_MAX ||
2706
1.60k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2707
1.60k
        (unsigned long long)INT_MAX)
2708
1.60k
      THROW("Image or row alignment is too large");
2709
1.60k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
2710
1.60k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
2711
1.60k
  }
2712
2713
2.89k
  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
2714
2.89k
                             height, pixelFormat);
2715
2716
0
bailout:
2717
0
  return retval;
2718
2.89k
}
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.1k
{
2756
31.1k
  int dstSubsamp;
2757
2758
31.1k
  if (!transform)
2759
0
    return srcSubsamp;
2760
2761
31.1k
  dstSubsamp = (transform->options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2762
2763
31.1k
  if (transform->op == TJXOP_TRANSPOSE || transform->op == TJXOP_TRANSVERSE ||
2764
23.3k
      transform->op == TJXOP_ROT90 || transform->op == TJXOP_ROT270) {
2765
23.3k
    if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2766
22.9k
    else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2767
22.8k
    else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2768
22.7k
    else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2769
23.3k
  }
2770
2771
31.1k
  return dstSubsamp;
2772
31.1k
}
2773
2774
static int getTransformedSpecs(tjhandle handle, int *width, int *height,
2775
                               int *subsamp, const tjtransform *transform,
2776
                               const char *FUNCTION_NAME)
2777
23.3k
{
2778
23.3k
  int retval = 0, dstWidth, dstHeight, dstSubsamp;
2779
2780
23.3k
  GET_TJINSTANCE(handle, -1);
2781
23.3k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2782
23.3k
    THROW("Instance has not been initialized for transformation");
2783
2784
23.3k
  if (!width || !height || !subsamp || !transform || *width < 1 ||
2785
23.3k
      *height < 1 || *subsamp < TJSAMP_UNKNOWN || *subsamp >= TJ_NUMSAMP)
2786
23.3k
    THROW("Invalid argument");
2787
2788
23.3k
  dstWidth = *width;  dstHeight = *height;
2789
23.3k
  if (transform->op == TJXOP_TRANSPOSE || transform->op == TJXOP_TRANSVERSE ||
2790
15.5k
      transform->op == TJXOP_ROT90 || transform->op == TJXOP_ROT270) {
2791
15.5k
    dstWidth = *height;  dstHeight = *width;
2792
15.5k
  }
2793
23.3k
  dstSubsamp = getDstSubsamp(*subsamp, transform);
2794
2795
23.3k
  if (transform->options & TJXOPT_CROP) {
2796
7.78k
    int croppedWidth, croppedHeight;
2797
2798
7.78k
    if (transform->r.x < 0 || transform->r.y < 0 || transform->r.w < 0 ||
2799
7.78k
        transform->r.h < 0)
2800
7.78k
      THROW("Invalid cropping region");
2801
7.78k
    if (dstSubsamp == TJSAMP_UNKNOWN)
2802
7.78k
      THROW("Could not determine subsampling level of JPEG image");
2803
7.78k
    if ((transform->r.x % tjMCUWidth[dstSubsamp]) != 0 ||
2804
7.78k
        (transform->r.y % tjMCUHeight[dstSubsamp]) != 0)
2805
0
      THROWI("To crop this JPEG image, x must be a multiple of %d\n"
2806
7.78k
             "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
2807
7.78k
             tjMCUHeight[dstSubsamp]);
2808
7.78k
    if (transform->r.x >= dstWidth || transform->r.y >= dstHeight)
2809
7.78k
      THROW("The cropping region exceeds the destination image dimensions");
2810
7.78k
    croppedWidth = transform->r.w == 0 ? dstWidth - transform->r.x :
2811
7.78k
                                         transform->r.w;
2812
7.78k
    croppedHeight = transform->r.h == 0 ? dstHeight - transform->r.y :
2813
7.78k
                                          transform->r.h;
2814
7.78k
    if (transform->r.x + croppedWidth > dstWidth ||
2815
7.78k
        transform->r.y + croppedHeight > dstHeight)
2816
7.78k
      THROW("The cropping region exceeds the destination image dimensions");
2817
7.78k
    dstWidth = croppedWidth;  dstHeight = croppedHeight;
2818
7.78k
  }
2819
2820
23.3k
  *width = dstWidth;  *height = dstHeight;  *subsamp = dstSubsamp;
2821
2822
23.3k
bailout:
2823
23.3k
  return retval;
2824
23.3k
}
2825
2826
2827
/* TurboJPEG 3.1+ */
2828
DLLEXPORT size_t tj3TransformBufSize(tjhandle handle,
2829
                                     const tjtransform *transform)
2830
23.3k
{
2831
23.3k
  static const char FUNCTION_NAME[] = "tj3TransformBufSize";
2832
23.3k
  size_t retval = 0;
2833
23.3k
  int dstWidth, dstHeight, dstSubsamp;
2834
2835
23.3k
  GET_TJINSTANCE(handle, 0);
2836
23.3k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2837
23.3k
    THROWRV("Instance has not been initialized for transformation", 0);
2838
2839
23.3k
  if (transform == NULL)
2840
0
    THROWRV("Invalid argument", 0)
2841
2842
23.3k
  if (this->jpegWidth < 0 || this->jpegHeight < 0)
2843
23.3k
    THROWRV("JPEG header has not yet been read", 0);
2844
2845
23.3k
  dstWidth = this->jpegWidth;
2846
23.3k
  dstHeight = this->jpegHeight;
2847
23.3k
  dstSubsamp = this->subsamp;
2848
23.3k
  if (getTransformedSpecs(handle, &dstWidth, &dstHeight, &dstSubsamp,
2849
23.3k
                          transform, FUNCTION_NAME) == -1) {
2850
0
    retval = 0;
2851
0
    goto bailout;
2852
0
  }
2853
2854
23.3k
  retval = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
2855
23.3k
  if ((this->saveMarkers == 2 || this->saveMarkers == 4) &&
2856
23.3k
      !(transform->options & TJXOPT_COPYNONE))
2857
7.78k
    retval += this->tempICCSize;
2858
15.5k
  else
2859
15.5k
    retval += this->iccSize;
2860
2861
23.3k
bailout:
2862
23.3k
  return retval;
2863
23.3k
}
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.1k
{
2871
31.1k
  static const char FUNCTION_NAME[] = "tj3Transform";
2872
31.1k
  jpeg_transform_info *xinfo = NULL;
2873
31.1k
  jvirt_barray_ptr *srccoefs, *dstcoefs;
2874
31.1k
  int retval = 0, i, saveMarkers = 0, srcSubsamp;
2875
31.1k
  boolean alloc = TRUE;
2876
31.1k
  struct my_progress_mgr progress;
2877
2878
31.1k
  GET_INSTANCE(handle);
2879
31.1k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2880
31.1k
    THROW("Instance has not been initialized for transformation");
2881
2882
31.1k
  if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
2883
31.1k
      dstSizes == NULL || t == NULL)
2884
31.1k
    THROW("Invalid argument");
2885
2886
31.1k
  if (this->scanLimit) {
2887
31.1k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2888
31.1k
    progress.pub.progress_monitor = my_progress_monitor;
2889
31.1k
    progress.this = this;
2890
31.1k
    dinfo->progress = &progress.pub;
2891
31.1k
  } else
2892
0
    dinfo->progress = NULL;
2893
2894
31.1k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2895
2896
31.1k
  if ((xinfo =
2897
31.1k
       (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
2898
31.1k
    THROW("Memory allocation failure");
2899
31.1k
  memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
2900
2901
31.1k
  if (setjmp(this->jerr.setjmp_buffer)) {
2902
    /* If we get here, the JPEG code has signaled an error. */
2903
17.7k
    retval = -1;  goto bailout;
2904
17.7k
  }
2905
2906
13.3k
  if (dinfo->global_state <= DSTATE_INHEADER)
2907
31.1k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2908
2909
44.5k
  for (i = 0; i < n; i++) {
2910
31.1k
    if (t[i].op < 0 || t[i].op >= TJ_NUMXOP)
2911
31.1k
      THROW("Invalid transform operation");
2912
31.1k
    xinfo[i].transform = xformtypes[t[i].op];
2913
31.1k
    xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
2914
31.1k
    xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
2915
31.1k
    xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
2916
31.1k
    xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
2917
31.1k
    if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
2918
31.1k
    else xinfo[i].slow_hflip = 0;
2919
2920
31.1k
    if (xinfo[i].crop) {
2921
7.78k
      if (t[i].r.x < 0 || t[i].r.y < 0 || t[i].r.w < 0 || t[i].r.h < 0)
2922
7.78k
        THROW("Invalid cropping region");
2923
7.78k
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
2924
7.78k
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
2925
7.78k
      if (t[i].r.w != 0) {
2926
7.78k
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
2927
7.78k
      } else
2928
0
        xinfo[i].crop_width = JCROP_UNSET;
2929
7.78k
      if (t[i].r.h != 0) {
2930
7.78k
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
2931
7.78k
      } else
2932
0
        xinfo[i].crop_height = JCROP_UNSET;
2933
7.78k
    }
2934
31.1k
    if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
2935
31.1k
  }
2936
2937
13.3k
  jcopy_markers_setup(dinfo, saveMarkers ?
2938
18.4E
                             (JCOPY_OPTION)this->saveMarkers : JCOPYOPT_NONE);
2939
13.3k
  if (dinfo->global_state <= DSTATE_INHEADER)
2940
31.1k
    jpeg_read_header(dinfo, TRUE);
2941
13.3k
  if (this->maxPixels &&
2942
0
      (unsigned long long)dinfo->image_width * dinfo->image_height >
2943
0
      (unsigned long long)this->maxPixels)
2944
13.3k
    THROW("Image is too large");
2945
13.3k
  srcSubsamp = getSubsamp(&this->dinfo);
2946
2947
44.5k
  for (i = 0; i < n; i++) {
2948
31.1k
    if (!jtransform_request_workspace(dinfo, &xinfo[i]))
2949
31.1k
      THROW("Transform is not perfect");
2950
2951
31.1k
    if (xinfo[i].crop) {
2952
7.78k
      int dstSubsamp = getDstSubsamp(srcSubsamp, &t[i]);
2953
2954
7.78k
      if (dstSubsamp == TJSAMP_UNKNOWN)
2955
7.78k
        THROW("Could not determine subsampling level of destination image");
2956
7.78k
      if ((t[i].r.x % tjMCUWidth[dstSubsamp]) != 0 ||
2957
7.78k
          (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.78k
               "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
2960
7.78k
               tjMCUHeight[dstSubsamp]);
2961
7.78k
    }
2962
31.1k
  }
2963
2964
13.3k
  srccoefs = jpeg_read_coefficients(dinfo);
2965
2966
32.2k
  for (i = 0; i < n; i++) {
2967
18.8k
    if (this->noRealloc) alloc = FALSE;
2968
18.8k
    if (!(t[i].options & TJXOPT_NOOUTPUT))
2969
18.8k
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2970
18.8k
    jpeg_copy_critical_parameters(dinfo, cinfo);
2971
18.8k
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
2972
18.8k
    if (this->optimize || t[i].options & TJXOPT_OPTIMIZE)
2973
3.73k
      cinfo->optimize_coding = TRUE;
2974
18.8k
#ifdef C_PROGRESSIVE_SUPPORTED
2975
18.8k
    if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE)
2976
8.70k
      jpeg_simple_progression(cinfo);
2977
18.8k
#endif
2978
18.8k
    if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) {
2979
4.26k
      cinfo->arith_code = TRUE;
2980
4.26k
      cinfo->optimize_coding = FALSE;
2981
4.26k
    }
2982
18.8k
    cinfo->restart_interval = this->restartIntervalBlocks;
2983
18.8k
    cinfo->restart_in_rows = this->restartIntervalRows;
2984
18.8k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
2985
16.7k
      jpeg_write_coefficients(cinfo, dstcoefs);
2986
16.7k
      jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
2987
8.17k
                                          JCOPYOPT_NONE :
2988
16.7k
                                          (JCOPY_OPTION)this->saveMarkers);
2989
16.7k
      if (this->iccBuf != NULL && this->iccSize != 0)
2990
0
        jpeg_write_icc_profile(cinfo, this->iccBuf,
2991
0
                               (unsigned int)this->iccSize);
2992
16.7k
    } else
2993
2.14k
      jinit_c_master_control(cinfo, TRUE);
2994
18.8k
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
2995
18.8k
    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
18.8k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
3025
18.8k
  }
3026
3027
13.3k
  jpeg_finish_decompress(dinfo);
3028
3029
31.1k
bailout:
3030
31.1k
  if (cinfo->global_state > CSTATE_START) {
3031
3.32k
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
3032
3.32k
    jpeg_abort_compress(cinfo);
3033
3.32k
  }
3034
31.1k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
3035
31.1k
  free(xinfo);
3036
31.1k
  if (this->jerr.warning) retval = -1;
3037
31.1k
  return retval;
3038
13.3k
}
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
}