Coverage Report

Created: 2026-06-10 06:18

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