Coverage Report

Created: 2026-05-30 07:16

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.60M
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
55
330k
#define IS_POW2(x)  (((x) & (x - 1)) == 0)
56
57
58
/* Error handling (based on example in example.c) */
59
60
static THREAD_LOCAL char errStr[JMSG_LENGTH_MAX] = "No error";
61
62
struct my_error_mgr {
63
  struct jpeg_error_mgr pub;
64
  jmp_buf setjmp_buffer;
65
  void (*emit_message) (j_common_ptr, int);
66
  boolean warning, stopOnWarning;
67
};
68
typedef struct my_error_mgr *my_error_ptr;
69
70
#define JMESSAGE(code, string)  string,
71
static const char *turbojpeg_message_table[] = {
72
#include "cderror.h"
73
  NULL
74
};
75
76
static void my_error_exit(j_common_ptr cinfo)
77
446k
{
78
446k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
79
80
446k
  (*cinfo->err->output_message) (cinfo);
81
446k
  longjmp(myerr->setjmp_buffer, 1);
82
446k
}
83
84
/* Based on output_message() in jerror.c */
85
86
static void my_output_message(j_common_ptr cinfo)
87
310k
{
88
310k
  (*cinfo->err->format_message) (cinfo, errStr);
89
310k
}
90
91
static void my_emit_message(j_common_ptr cinfo, int msg_level)
92
666M
{
93
666M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
94
95
666M
  myerr->emit_message(cinfo, msg_level);
96
666M
  if (msg_level < 0) {
97
457M
    myerr->warning = TRUE;
98
457M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
99
457M
  }
100
666M
}
101
102
103
/********************** Global structures, macros, etc. **********************/
104
105
enum { COMPRESS = 1, DECOMPRESS = 2 };
106
107
typedef struct _tjinstance {
108
  struct jpeg_compress_struct cinfo;
109
  struct jpeg_decompress_struct dinfo;
110
  struct my_error_mgr jerr;
111
  int init;
112
  char errStr[JMSG_LENGTH_MAX];
113
  boolean isInstanceError;
114
  /* Parameters */
115
  boolean bottomUp;
116
  boolean noRealloc;
117
  int quality;
118
  int subsamp;
119
  int jpegWidth;
120
  int jpegHeight;
121
  int precision;
122
  int colorspace;
123
  boolean fastUpsample;
124
  boolean fastDCT;
125
  boolean optimize;
126
  boolean progressive;
127
  int scanLimit;
128
  boolean arithmetic;
129
  boolean lossless;
130
  int losslessPSV;
131
  int losslessPt;
132
  int restartIntervalBlocks;
133
  int restartIntervalRows;
134
  int xDensity;
135
  int yDensity;
136
  int densityUnits;
137
  tjscalingfactor scalingFactor;
138
  tjregion croppingRegion;
139
  int maxMemory;
140
  int maxPixels;
141
} 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
492M
{
154
492M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
155
492M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
156
157
492M
  if (dinfo->is_decompressor) {
158
492M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
159
160
492M
    if (scan_no > myprog->this->scanLimit) {
161
2.11k
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
162
2.11k
               "Progressive JPEG image has more than %d scans",
163
2.11k
               myprog->this->scanLimit);
164
2.11k
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
165
2.11k
               "Progressive JPEG image has more than %d scans",
166
2.11k
               myprog->this->scanLimit);
167
2.11k
      myprog->this->isInstanceError = TRUE;
168
2.11k
      myerr->warning = FALSE;
169
2.11k
      longjmp(myerr->setjmp_buffer, 1);
170
2.11k
    }
171
492M
  }
172
492M
}
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.14M
#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
596k
#define CATCH_LIBJPEG(this) { \
279
596k
  if (setjmp(this->jerr.setjmp_buffer)) { \
280
127k
    /* If we get here, the JPEG code has signaled an error. */ \
281
127k
    retval = -1;  goto bailout; \
282
127k
  } \
283
596k
}
284
285
#define GET_INSTANCE(handle) \
286
0
  tjinstance *this = (tjinstance *)handle; \
287
0
  j_compress_ptr cinfo = NULL; \
288
0
  j_decompress_ptr dinfo = NULL; \
289
0
  \
290
0
  if (!this) { \
291
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
292
0
    return -1; \
293
0
  } \
294
0
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
295
0
  this->jerr.warning = FALSE; \
296
0
  this->isInstanceError = FALSE;
297
298
#define GET_CINSTANCE(handle) \
299
89.2k
  tjinstance *this = (tjinstance *)handle; \
300
89.2k
  j_compress_ptr cinfo = NULL; \
301
89.2k
  \
302
89.2k
  if (!this) { \
303
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
304
0
    return -1; \
305
0
  } \
306
89.2k
  cinfo = &this->cinfo; \
307
89.2k
  this->jerr.warning = FALSE; \
308
89.2k
  this->isInstanceError = FALSE;
309
310
#define GET_DINSTANCE(handle) \
311
172k
  tjinstance *this = (tjinstance *)handle; \
312
172k
  j_decompress_ptr dinfo = NULL; \
313
172k
  \
314
172k
  if (!this) { \
315
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
316
0
    return -1; \
317
0
  } \
318
172k
  dinfo = &this->dinfo; \
319
172k
  this->jerr.warning = FALSE; \
320
172k
  this->isInstanceError = FALSE;
321
322
#define GET_TJINSTANCE(handle, errorReturn) \
323
1.25M
  tjinstance *this = (tjinstance *)handle; \
324
1.25M
  \
325
1.25M
  if (!this) { \
326
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
327
0
    return errorReturn; \
328
0
  } \
329
1.25M
  this->jerr.warning = FALSE; \
330
1.25M
  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
259k
{
353
259k
  int colorspace = yuv ? -1 : this->colorspace;
354
355
259k
  this->cinfo.in_color_space = pf2cs[pixelFormat];
356
259k
  this->cinfo.input_components = tjPixelSize[pixelFormat];
357
259k
  jpeg_set_defaults(&this->cinfo);
358
359
259k
  this->cinfo.restart_interval = this->restartIntervalBlocks;
360
259k
  this->cinfo.restart_in_rows = this->restartIntervalRows;
361
259k
  this->cinfo.X_density = (UINT16)this->xDensity;
362
259k
  this->cinfo.Y_density = (UINT16)this->yDensity;
363
259k
  this->cinfo.density_unit = (UINT8)this->densityUnits;
364
259k
  this->cinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
365
366
259k
  if (this->lossless && !yuv) {
367
83.1k
#ifdef C_LOSSLESS_SUPPORTED
368
83.1k
    jpeg_enable_lossless(&this->cinfo, this->losslessPSV, this->losslessPt);
369
83.1k
#endif
370
83.1k
    return;
371
83.1k
  }
372
373
176k
  jpeg_set_quality(&this->cinfo, this->quality, TRUE);
374
176k
  this->cinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
375
376
176k
  switch (colorspace) {
377
10.7k
  case TJCS_RGB:
378
10.7k
    jpeg_set_colorspace(&this->cinfo, JCS_RGB);  break;
379
18.8k
  case TJCS_YCbCr:
380
18.8k
    jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);  break;
381
14.5k
  case TJCS_GRAY:
382
14.5k
    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.4k
  case TJCS_YCCK:
386
10.4k
    jpeg_set_colorspace(&this->cinfo, JCS_YCCK);  break;
387
121k
  default:
388
121k
    if (this->subsamp == TJSAMP_GRAY)
389
40.1k
      jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);
390
81.3k
    else if (pixelFormat == TJPF_CMYK)
391
4.17k
      jpeg_set_colorspace(&this->cinfo, JCS_YCCK);
392
77.1k
    else
393
77.1k
      jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);
394
176k
  }
395
396
176k
  if (this->cinfo.data_precision == 8)
397
127k
    this->cinfo.optimize_coding = this->optimize;
398
176k
#ifdef C_PROGRESSIVE_SUPPORTED
399
176k
  if (this->progressive) jpeg_simple_progression(&this->cinfo);
400
176k
#endif
401
176k
  this->cinfo.arith_code = this->arithmetic;
402
403
176k
  this->cinfo.comp_info[0].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
404
176k
  this->cinfo.comp_info[1].h_samp_factor = 1;
405
176k
  this->cinfo.comp_info[2].h_samp_factor = 1;
406
176k
  if (this->cinfo.num_components > 3)
407
14.6k
    this->cinfo.comp_info[3].h_samp_factor = tjMCUWidth[this->subsamp] / 8;
408
176k
  this->cinfo.comp_info[0].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
409
176k
  this->cinfo.comp_info[1].v_samp_factor = 1;
410
176k
  this->cinfo.comp_info[2].v_samp_factor = 1;
411
176k
  if (this->cinfo.num_components > 3)
412
14.6k
    this->cinfo.comp_info[3].v_samp_factor = tjMCUHeight[this->subsamp] / 8;
413
176k
}
414
415
416
static int getSubsamp(j_decompress_ptr dinfo)
417
263k
{
418
263k
  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
263k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
425
124k
    return TJSAMP_GRAY;
426
427
762k
  for (i = 0; i < TJ_NUMSAMP; i++) {
428
704k
    if (i == TJSAMP_GRAY) continue;
429
430
634k
    if (dinfo->num_components == 3 ||
431
61.6k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
432
54.9k
          dinfo->jpeg_color_space == JCS_CMYK) &&
433
625k
         dinfo->num_components == 4)) {
434
625k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
435
268k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
436
124k
        int match = 0;
437
438
380k
        for (k = 1; k < dinfo->num_components; k++) {
439
256k
          int href = 1, vref = 1;
440
441
256k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
442
253k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
443
7.90k
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
444
7.90k
          }
445
256k
          if (dinfo->comp_info[k].h_samp_factor == href &&
446
223k
              dinfo->comp_info[k].v_samp_factor == vref)
447
183k
            match++;
448
256k
        }
449
124k
        if (match == dinfo->num_components - 1) {
450
76.8k
          retval = i;  break;
451
76.8k
        }
452
124k
      }
453
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
454
         in non-standard ways. */
455
548k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
456
324k
          dinfo->comp_info[0].v_samp_factor == 2 &&
457
163k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
458
72.8k
        int match = 0;
459
460
220k
        for (k = 1; k < dinfo->num_components; k++) {
461
147k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
462
463
147k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
464
146k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
465
2.35k
            href = vref = 2;
466
2.35k
          }
467
147k
          if (dinfo->comp_info[k].h_samp_factor == href &&
468
126k
              dinfo->comp_info[k].v_samp_factor == vref)
469
12.2k
            match++;
470
147k
        }
471
72.8k
        if (match == dinfo->num_components - 1) {
472
4.12k
          retval = i;  break;
473
4.12k
        }
474
72.8k
      }
475
      /* Handle 4:4:4 images whose sampling factors are specified in
476
         non-standard ways. */
477
544k
      if (dinfo->comp_info[0].h_samp_factor *
478
544k
          dinfo->comp_info[0].v_samp_factor <=
479
544k
          D_MAX_BLOCKS_IN_MCU / 3 && i == TJSAMP_444) {
480
46.3k
        int match = 0;
481
143k
        for (k = 1; k < dinfo->num_components; k++) {
482
98.3k
          if (dinfo->comp_info[k].h_samp_factor ==
483
98.3k
              dinfo->comp_info[0].h_samp_factor &&
484
24.3k
              dinfo->comp_info[k].v_samp_factor ==
485
24.3k
              dinfo->comp_info[0].v_samp_factor)
486
7.24k
            match++;
487
98.3k
          if (match == dinfo->num_components - 1) {
488
1.50k
            retval = i;  break;
489
1.50k
          }
490
98.3k
        }
491
46.3k
      }
492
544k
    }
493
634k
  }
494
138k
  return retval;
495
263k
}
496
497
498
static void setDecompParameters(tjinstance *this)
499
229k
{
500
229k
  this->subsamp = getSubsamp(&this->dinfo);
501
229k
  this->jpegWidth = this->dinfo.image_width;
502
229k
  this->jpegHeight = this->dinfo.image_height;
503
229k
  this->precision = this->dinfo.data_precision;
504
229k
  switch (this->dinfo.jpeg_color_space) {
505
104k
  case JCS_GRAYSCALE:  this->colorspace = TJCS_GRAY;  break;
506
49.5k
  case JCS_RGB:        this->colorspace = TJCS_RGB;  break;
507
67.4k
  case JCS_YCbCr:      this->colorspace = TJCS_YCbCr;  break;
508
6.30k
  case JCS_CMYK:       this->colorspace = TJCS_CMYK;  break;
509
1.04k
  case JCS_YCCK:       this->colorspace = TJCS_YCCK;  break;
510
555
  default:             this->colorspace = -1;  break;
511
229k
  }
512
229k
  this->progressive = this->dinfo.progressive_mode;
513
229k
  this->arithmetic = this->dinfo.arith_code;
514
229k
  this->lossless = this->dinfo.master->lossless;
515
229k
  this->losslessPSV = this->dinfo.Ss;
516
229k
  this->losslessPt = this->dinfo.Al;
517
229k
  this->xDensity = this->dinfo.X_density;
518
229k
  this->yDensity = this->dinfo.Y_density;
519
229k
  this->densityUnits = this->dinfo.density_unit;
520
229k
}
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
292k
{
558
292k
  static const char FUNCTION_NAME[] = "tj3Init";
559
292k
  tjinstance *this = NULL;
560
292k
  tjhandle retval = NULL;
561
562
292k
  if (initType < 0 || initType >= TJ_NUMINIT)
563
292k
    THROWG("Invalid argument", NULL);
564
565
292k
  if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL)
566
292k
    THROWG("Memory allocation failure", NULL);
567
292k
  memset(this, 0, sizeof(tjinstance));
568
292k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
569
570
292k
  this->quality = -1;
571
292k
  this->subsamp = TJSAMP_UNKNOWN;
572
292k
  this->jpegWidth = -1;
573
292k
  this->jpegHeight = -1;
574
292k
  this->precision = 8;
575
292k
  this->colorspace = -1;
576
292k
  this->losslessPSV = 1;
577
292k
  this->xDensity = 1;
578
292k
  this->yDensity = 1;
579
292k
  this->scalingFactor = TJUNSCALED;
580
581
292k
  switch (initType) {
582
258k
  case TJINIT_COMPRESS:  return _tjInitCompress(this);
583
27.3k
  case TJINIT_DECOMPRESS:  return _tjInitDecompress(this);
584
6.17k
  case TJINIT_TRANSFORM:
585
6.17k
    retval = _tjInitCompress(this);
586
6.17k
    if (!retval) return NULL;
587
6.17k
    retval = _tjInitDecompress(this);
588
6.17k
    return retval;
589
292k
  }
590
591
0
bailout:
592
0
  return retval;
593
292k
}
594
595
596
/* TurboJPEG 3+ */
597
DLLEXPORT void tj3Destroy(tjhandle handle)
598
621k
{
599
621k
  tjinstance *this = (tjinstance *)handle;
600
621k
  j_compress_ptr cinfo = NULL;
601
621k
  j_decompress_ptr dinfo = NULL;
602
603
621k
  if (!this) return;
604
605
621k
  cinfo = &this->cinfo;  dinfo = &this->dinfo;
606
621k
  this->jerr.warning = FALSE;
607
621k
  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
621k
  if (setjmp(this->jerr.setjmp_buffer)) goto destroy_decompress;
612
621k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
613
621k
destroy_decompress:
614
621k
  if (setjmp(this->jerr.setjmp_buffer)) goto bailout;
615
621k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
616
621k
bailout:
617
621k
  free(this);
618
621k
}
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
167k
{
640
167k
  tjinstance *this = (tjinstance *)handle;
641
642
167k
  if (this && this->isInstanceError) {
643
64.9k
    this->isInstanceError = FALSE;
644
64.9k
    return this->errStr;
645
64.9k
  } else
646
102k
    return errStr;
647
167k
}
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
366k
#define SET_PARAM(field, minValue, maxValue) { \
679
366k
  if (value < minValue || (maxValue > 0 && value > maxValue)) \
680
366k
    THROW("Parameter value out of range"); \
681
366k
  this->field = value; \
682
366k
}
683
684
588k
#define SET_BOOL_PARAM(field) { \
685
588k
  if (value < 0 || value > 1) \
686
588k
    THROW("Parameter value out of range"); \
687
588k
  this->field = (boolean)value; \
688
588k
}
689
690
/* TurboJPEG 3+ */
691
DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
692
955k
{
693
955k
  static const char FUNCTION_NAME[] = "tj3Set";
694
955k
  int retval = 0;
695
696
955k
  GET_TJINSTANCE(handle, -1);
697
698
955k
  switch (param) {
699
0
  case TJPARAM_STOPONWARNING:
700
0
    SET_BOOL_PARAM(jerr.stopOnWarning);
701
0
    break;
702
144k
  case TJPARAM_BOTTOMUP:
703
144k
    SET_BOOL_PARAM(bottomUp);
704
144k
    break;
705
110k
  case TJPARAM_NOREALLOC:
706
110k
    if (!(this->init & COMPRESS))
707
110k
      THROW("TJPARAM_NOREALLOC is not applicable to decompression instances.");
708
110k
    SET_BOOL_PARAM(noRealloc);
709
110k
    break;
710
40.0k
  case TJPARAM_QUALITY:
711
40.0k
    if (!(this->init & COMPRESS))
712
40.0k
      THROW("TJPARAM_QUALITY is not applicable to decompression instances.");
713
40.0k
    SET_PARAM(quality, 1, 100);
714
40.0k
    break;
715
40.0k
  case TJPARAM_SUBSAMP:
716
40.0k
    SET_PARAM(subsamp, 0, TJ_NUMSAMP - 1);
717
40.0k
    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.0k
  case TJPARAM_FASTUPSAMPLE:
739
34.0k
    if (!(this->init & DECOMPRESS))
740
34.0k
      THROW("TJPARAM_FASTUPSAMPLE is not applicable to compression instances.");
741
34.0k
    SET_BOOL_PARAM(fastUpsample);
742
34.0k
    break;
743
97.1k
  case TJPARAM_FASTDCT:
744
97.1k
    SET_BOOL_PARAM(fastDCT);
745
97.1k
    break;
746
49.1k
  case TJPARAM_OPTIMIZE:
747
49.1k
    if (!(this->init & COMPRESS))
748
49.1k
      THROW("TJPARAM_OPTIMIZE is not applicable to decompression instances.");
749
49.1k
    SET_BOOL_PARAM(optimize);
750
49.1k
    break;
751
70.0k
  case TJPARAM_PROGRESSIVE:
752
70.0k
    if (!(this->init & COMPRESS))
753
70.0k
      THROW("TJPARAM_PROGRESSIVE is read-only in decompression instances.");
754
70.0k
    SET_BOOL_PARAM(progressive);
755
70.0k
    break;
756
38.7k
  case TJPARAM_SCANLIMIT:
757
38.7k
    if (!(this->init & DECOMPRESS))
758
38.7k
      THROW("TJPARAM_SCANLIMIT is not applicable to compression instances.");
759
38.7k
    SET_PARAM(scanLimit, 0, -1);
760
38.7k
    break;
761
70.0k
  case TJPARAM_ARITHMETIC:
762
70.0k
    if (!(this->init & COMPRESS))
763
70.0k
      THROW("TJPARAM_ARITHMETIC is read-only in decompression instances.");
764
70.0k
    SET_BOOL_PARAM(arithmetic);
765
70.0k
    break;
766
13.4k
  case TJPARAM_LOSSLESS:
767
13.4k
    if (!(this->init & COMPRESS))
768
13.4k
      THROW("TJPARAM_LOSSLESS is read-only in decompression instances.");
769
13.4k
    SET_BOOL_PARAM(lossless);
770
13.4k
    break;
771
13.4k
  case TJPARAM_LOSSLESSPSV:
772
13.4k
    if (!(this->init & COMPRESS))
773
13.4k
      THROW("TJPARAM_LOSSLESSPSV is read-only in decompression instances.");
774
13.4k
    SET_PARAM(losslessPSV, 1, 7);
775
13.4k
    break;
776
13.4k
  case TJPARAM_LOSSLESSPT:
777
13.4k
    if (!(this->init & COMPRESS))
778
13.4k
      THROW("TJPARAM_LOSSLESSPT is read-only in decompression instances.");
779
13.4k
    SET_PARAM(losslessPt, 0, 15);
780
13.4k
    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
88.9k
  case TJPARAM_RESTARTROWS:
788
88.9k
    if (!(this->init & COMPRESS))
789
88.9k
      THROW("TJPARAM_RESTARTROWS is not applicable to decompression instances.");
790
88.9k
    SET_PARAM(restartIntervalRows, 0, 65535);
791
88.9k
    if (value != 0) this->restartIntervalBlocks = 0;
792
88.9k
    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
110k
  case TJPARAM_MAXPIXELS:
812
110k
    SET_PARAM(maxPixels, 0, -1);
813
110k
    break;
814
0
  default:
815
0
    THROW("Invalid parameter");
816
955k
  }
817
818
955k
bailout:
819
955k
  return retval;
820
955k
}
821
822
823
/* TurboJPEG 3+ */
824
DLLEXPORT int tj3Get(tjhandle handle, int param)
825
121k
{
826
121k
  tjinstance *this = (tjinstance *)handle;
827
121k
  if (!this) return -1;
828
829
121k
  switch (param) {
830
0
  case TJPARAM_STOPONWARNING:
831
0
    return this->jerr.stopOnWarning;
832
0
  case TJPARAM_BOTTOMUP:
833
0
    return this->bottomUp;
834
41.8k
  case TJPARAM_NOREALLOC:
835
41.8k
    return this->noRealloc;
836
0
  case TJPARAM_QUALITY:
837
0
    return this->quality;
838
6.28k
  case TJPARAM_SUBSAMP:
839
6.28k
    return this->subsamp;
840
13.5k
  case TJPARAM_JPEGWIDTH:
841
13.5k
    return this->jpegWidth;
842
13.5k
  case TJPARAM_JPEGHEIGHT:
843
13.5k
    return this->jpegHeight;
844
7.29k
  case TJPARAM_PRECISION:
845
7.29k
    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
38.7k
  case TJPARAM_LOSSLESS:
861
38.7k
    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
121k
  }
881
882
0
  return -1;
883
121k
}
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
409k
{
894
409k
  return MALLOC(bytes);
895
409k
}
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
884k
{
907
884k
  free(buf);
908
884k
}
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
296k
{
920
296k
  static const char FUNCTION_NAME[] = "tj3JPEGBufSize";
921
296k
  unsigned long long retval = 0;
922
296k
  int mcuw, mcuh, chromasf;
923
924
296k
  if (width < 1 || height < 1 || jpegSubsamp < TJSAMP_UNKNOWN ||
925
296k
      jpegSubsamp >= TJ_NUMSAMP)
926
296k
    THROWG("Invalid argument", 0);
927
928
296k
  if (jpegSubsamp == TJSAMP_UNKNOWN)
929
16.6k
    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
296k
  mcuw = tjMCUWidth[jpegSubsamp];
935
296k
  mcuh = tjMCUHeight[jpegSubsamp];
936
296k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
937
296k
  retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
938
#if ULLONG_MAX > ULONG_MAX
939
  if (retval > (unsigned long long)((unsigned long)-1))
940
    THROWG("Image is too large", 0);
941
#endif
942
943
296k
bailout:
944
296k
  return (size_t)retval;
945
296k
}
946
947
/* TurboJPEG 1.2+ */
948
DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
949
0
{
950
0
  static const char FUNCTION_NAME[] = "tjBufSize";
951
0
  size_t retval;
952
953
0
  if (jpegSubsamp < 0)
954
0
    THROWG("Invalid argument", 0);
955
956
0
  retval = tj3JPEGBufSize(width, height, jpegSubsamp);
957
958
0
bailout:
959
0
  return (retval == 0) ? (unsigned long)-1 : (unsigned long)retval;
960
0
}
961
962
/* TurboJPEG 1.0+ */
963
DLLEXPORT unsigned long TJBUFSIZE(int width, int height)
964
0
{
965
0
  static const char FUNCTION_NAME[] = "TJBUFSIZE";
966
0
  unsigned long long retval = 0;
967
968
0
  if (width < 1 || height < 1)
969
0
    THROWG("Invalid argument", (unsigned long)-1);
970
971
  /* This allows for rare corner cases in which a JPEG image can actually be
972
     larger than the uncompressed input (we wouldn't mention it if it hadn't
973
     happened before.) */
974
0
  retval = PAD(width, 16) * PAD(height, 16) * 6ULL + 2048ULL;
975
#if ULLONG_MAX > ULONG_MAX
976
  if (retval > (unsigned long long)((unsigned long)-1))
977
    THROWG("Image is too large", (unsigned long)-1);
978
#endif
979
980
0
bailout:
981
0
  return (unsigned long)retval;
982
0
}
983
984
985
/* TurboJPEG 3+ */
986
DLLEXPORT size_t tj3YUVBufSize(int width, int align, int height, int subsamp)
987
84.7k
{
988
84.7k
  static const char FUNCTION_NAME[] = "tj3YUVBufSize";
989
84.7k
  unsigned long long retval = 0;
990
84.7k
  int nc, i;
991
992
84.7k
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
993
83.9k
    THROWG("Invalid argument", 0);
994
995
83.9k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
996
272k
  for (i = 0; i < nc; i++) {
997
188k
    int pw = tj3YUVPlaneWidth(i, width, subsamp);
998
188k
    int stride = PAD(pw, align);
999
188k
    int ph = tj3YUVPlaneHeight(i, height, subsamp);
1000
1001
188k
    if (pw == 0 || ph == 0) return 0;
1002
188k
    else retval += (unsigned long long)stride * ph;
1003
188k
  }
1004
#if ULLONG_MAX > ULONG_MAX
1005
  if (retval > (unsigned long long)((unsigned long)-1))
1006
    THROWG("Image is too large", 0);
1007
#endif
1008
1009
84.7k
bailout:
1010
84.7k
  return (size_t)retval;
1011
83.9k
}
1012
1013
/* TurboJPEG 1.4+ */
1014
DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
1015
                                      int subsamp)
1016
0
{
1017
0
  size_t retval = tj3YUVBufSize(width, align, height, subsamp);
1018
0
  return (retval == 0) ? (unsigned long)-1 : (unsigned long)retval;
1019
0
}
1020
1021
/* TurboJPEG 1.2+ */
1022
DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
1023
0
{
1024
0
  return tjBufSizeYUV2(width, 4, height, subsamp);
1025
0
}
1026
1027
/* TurboJPEG 1.1+ */
1028
DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
1029
0
{
1030
0
  return tjBufSizeYUV(width, height, subsamp);
1031
0
}
1032
1033
1034
/* TurboJPEG 3+ */
1035
DLLEXPORT size_t tj3YUVPlaneSize(int componentID, int width, int stride,
1036
                                 int height, int subsamp)
1037
0
{
1038
0
  static const char FUNCTION_NAME[] = "tj3YUVPlaneSize";
1039
0
  unsigned long long retval = 0;
1040
0
  int pw, ph;
1041
1042
0
  if (width < 1 || height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1043
0
    THROWG("Invalid argument", 0);
1044
1045
0
  pw = tj3YUVPlaneWidth(componentID, width, subsamp);
1046
0
  ph = tj3YUVPlaneHeight(componentID, height, subsamp);
1047
0
  if (pw == 0 || ph == 0) return 0;
1048
1049
0
  if (stride == 0) stride = pw;
1050
0
  else stride = abs(stride);
1051
1052
0
  retval = (unsigned long long)stride * (ph - 1) + pw;
1053
#if ULLONG_MAX > ULONG_MAX
1054
  if (retval > (unsigned long long)((unsigned long)-1))
1055
    THROWG("Image is too large", 0);
1056
#endif
1057
1058
0
bailout:
1059
0
  return (size_t)retval;
1060
0
}
1061
1062
/* TurboJPEG 1.4+ */
1063
DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
1064
                                       int height, int subsamp)
1065
0
{
1066
0
  size_t retval = tj3YUVPlaneSize(componentID, width, stride, height, subsamp);
1067
0
  return (retval == 0) ? -1 : (unsigned long)retval;
1068
0
}
1069
1070
1071
/* TurboJPEG 3+ */
1072
DLLEXPORT int tj3YUVPlaneWidth(int componentID, int width, int subsamp)
1073
492k
{
1074
492k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneWidth";
1075
492k
  unsigned long long pw, retval = 0;
1076
492k
  int nc;
1077
1078
492k
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1079
492k
    THROWG("Invalid argument", 0);
1080
492k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1081
492k
  if (componentID < 0 || componentID >= nc)
1082
492k
    THROWG("Invalid argument", 0);
1083
1084
492k
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
1085
492k
  if (componentID == 0)
1086
254k
    retval = pw;
1087
238k
  else
1088
238k
    retval = pw * 8 / tjMCUWidth[subsamp];
1089
1090
492k
  if (retval > (unsigned long long)INT_MAX)
1091
492k
    THROWG("Width is too large", 0);
1092
1093
492k
bailout:
1094
492k
  return (int)retval;
1095
492k
}
1096
1097
/* TurboJPEG 1.4+ */
1098
DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
1099
23.7k
{
1100
23.7k
  int retval = tj3YUVPlaneWidth(componentID, width, subsamp);
1101
23.7k
  return (retval == 0) ? -1 : retval;
1102
23.7k
}
1103
1104
1105
/* TurboJPEG 3+ */
1106
DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp)
1107
492k
{
1108
492k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneHeight";
1109
492k
  unsigned long long ph, retval = 0;
1110
492k
  int nc;
1111
1112
492k
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1113
492k
    THROWG("Invalid argument", 0);
1114
492k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1115
492k
  if (componentID < 0 || componentID >= nc)
1116
492k
    THROWG("Invalid argument", 0);
1117
1118
492k
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
1119
492k
  if (componentID == 0)
1120
254k
    retval = ph;
1121
238k
  else
1122
238k
    retval = ph * 8 / tjMCUHeight[subsamp];
1123
1124
492k
  if (retval > (unsigned long long)INT_MAX)
1125
492k
    THROWG("Height is too large", 0);
1126
1127
492k
bailout:
1128
492k
  return (int)retval;
1129
492k
}
1130
1131
/* TurboJPEG 1.4+ */
1132
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
1133
23.7k
{
1134
23.7k
  int retval = tj3YUVPlaneHeight(componentID, height, subsamp);
1135
23.7k
  return (retval == 0) ? -1 : retval;
1136
23.7k
}
1137
1138
1139
/******************************** Compressor *********************************/
1140
1141
static tjhandle _tjInitCompress(tjinstance *this)
1142
580k
{
1143
580k
  static unsigned char buffer[1];
1144
580k
  unsigned char *buf = buffer;
1145
580k
  size_t size = 1;
1146
1147
  /* This is also straight out of example.c */
1148
580k
  this->cinfo.err = jpeg_std_error(&this->jerr.pub);
1149
580k
  this->jerr.pub.error_exit = my_error_exit;
1150
580k
  this->jerr.pub.output_message = my_output_message;
1151
580k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1152
580k
  this->jerr.pub.emit_message = my_emit_message;
1153
580k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1154
580k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1155
580k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1156
1157
580k
  if (setjmp(this->jerr.setjmp_buffer)) {
1158
    /* If we get here, the JPEG code has signaled an error. */
1159
0
    free(this);
1160
0
    return NULL;
1161
0
  }
1162
1163
580k
  jpeg_create_compress(&this->cinfo);
1164
  /* Make an initial call so it will create the destination manager */
1165
580k
  jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
1166
1167
580k
  this->init |= COMPRESS;
1168
580k
  return (tjhandle)this;
1169
580k
}
1170
1171
/* TurboJPEG 1.0+ */
1172
DLLEXPORT tjhandle tjInitCompress(void)
1173
0
{
1174
0
  return tj3Init(TJINIT_COMPRESS);
1175
0
}
1176
1177
1178
/* tj3Compress*() is implemented in turbojpeg-mp.c */
1179
67.3k
#define BITS_IN_JSAMPLE  8
1180
#include "turbojpeg-mp.c"
1181
#undef BITS_IN_JSAMPLE
1182
46.3k
#define BITS_IN_JSAMPLE  12
1183
#include "turbojpeg-mp.c"
1184
#undef BITS_IN_JSAMPLE
1185
13.8k
#define BITS_IN_JSAMPLE  16
1186
#include "turbojpeg-mp.c"
1187
#undef BITS_IN_JSAMPLE
1188
1189
/* TurboJPEG 1.2+ */
1190
DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
1191
                          int width, int pitch, int height, int pixelFormat,
1192
                          unsigned char **jpegBuf, unsigned long *jpegSize,
1193
                          int jpegSubsamp, int jpegQual, int flags)
1194
0
{
1195
0
  static const char FUNCTION_NAME[] = "tjCompress2";
1196
0
  int retval = 0;
1197
0
  size_t size;
1198
1199
0
  GET_TJINSTANCE(handle, -1);
1200
1201
0
  if (jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP ||
1202
0
      jpegQual < 0 || jpegQual > 100)
1203
0
    THROW("Invalid argument");
1204
1205
0
  this->quality = jpegQual;
1206
0
  this->subsamp = jpegSubsamp;
1207
0
  processFlags(handle, flags, COMPRESS);
1208
1209
0
  size = (size_t)(*jpegSize);
1210
0
  retval = tj3Compress8(handle, srcBuf, width, pitch, height, pixelFormat,
1211
0
                        jpegBuf, &size);
1212
0
  *jpegSize = (unsigned long)size;
1213
1214
0
bailout:
1215
0
  return retval;
1216
0
}
1217
1218
/* TurboJPEG 1.0+ */
1219
DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
1220
                         int pitch, int height, int pixelSize,
1221
                         unsigned char *jpegBuf, unsigned long *jpegSize,
1222
                         int jpegSubsamp, int jpegQual, int flags)
1223
0
{
1224
0
  int retval = 0;
1225
0
  unsigned long size = jpegSize ? *jpegSize : 0;
1226
1227
0
  if (flags & TJ_YUV) {
1228
0
    size = tjBufSizeYUV(width, height, jpegSubsamp);
1229
0
    retval = tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1230
0
                          getPixelFormat(pixelSize, flags), jpegBuf,
1231
0
                          jpegSubsamp, flags);
1232
0
  } else {
1233
0
    retval = tjCompress2(handle, srcBuf, width, pitch, height,
1234
0
                         getPixelFormat(pixelSize, flags), &jpegBuf, &size,
1235
0
                         jpegSubsamp, jpegQual, flags | TJFLAG_NOREALLOC);
1236
0
  }
1237
0
  *jpegSize = size;
1238
0
  return retval;
1239
0
}
1240
1241
1242
/* TurboJPEG 3+ */
1243
DLLEXPORT int tj3CompressFromYUVPlanes8(tjhandle handle,
1244
                                        const unsigned char * const *srcPlanes,
1245
                                        int width, const int *strides,
1246
                                        int height, unsigned char **jpegBuf,
1247
                                        size_t *jpegSize)
1248
11.5k
{
1249
11.5k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUVPlanes8";
1250
11.5k
  int i, row, retval = 0;
1251
11.5k
  boolean alloc = TRUE;
1252
11.5k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1253
11.5k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1254
11.5k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1255
11.5k
  JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1256
1257
11.5k
  GET_CINSTANCE(handle)
1258
1259
127k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1260
115k
    tmpbuf[i] = NULL;  inbuf[i] = NULL;
1261
115k
  }
1262
1263
11.5k
  if ((this->init & COMPRESS) == 0)
1264
11.5k
    THROW("Instance has not been initialized for compression");
1265
1266
11.5k
  if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
1267
11.5k
      jpegBuf == NULL || jpegSize == NULL)
1268
11.5k
    THROW("Invalid argument");
1269
11.5k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1270
11.5k
    THROW("Invalid argument");
1271
1272
11.5k
  if (this->quality == -1)
1273
11.5k
    THROW("TJPARAM_QUALITY must be specified");
1274
11.5k
  if (this->subsamp == TJSAMP_UNKNOWN)
1275
11.5k
    THROW("TJPARAM_SUBSAMP must be specified");
1276
1277
11.5k
  CATCH_LIBJPEG(this);
1278
1279
11.5k
  cinfo->image_width = width;
1280
11.5k
  cinfo->image_height = height;
1281
11.5k
  cinfo->data_precision = 8;
1282
1283
11.5k
  if (this->noRealloc) {
1284
11.5k
    alloc = FALSE;  *jpegSize = tj3JPEGBufSize(width, height, this->subsamp);
1285
11.5k
  }
1286
11.5k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1287
11.5k
  setCompDefaults(this, TJPF_RGB, TRUE);
1288
11.5k
  cinfo->raw_data_in = TRUE;
1289
1290
11.5k
  jpeg_start_compress(cinfo, TRUE);
1291
38.9k
  for (i = 0; i < cinfo->num_components; i++) {
1292
27.3k
    jpeg_component_info *compptr = &cinfo->comp_info[i];
1293
27.3k
    int ih;
1294
1295
27.3k
    iw[i] = compptr->width_in_blocks * DCTSIZE;
1296
27.3k
    ih = compptr->height_in_blocks * DCTSIZE;
1297
27.3k
    pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
1298
27.3k
            compptr->h_samp_factor / cinfo->max_h_samp_factor;
1299
27.3k
    ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
1300
27.3k
            compptr->v_samp_factor / cinfo->max_v_samp_factor;
1301
27.3k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1302
27.3k
    th[i] = compptr->v_samp_factor * DCTSIZE;
1303
27.3k
    tmpbufsize += iw[i] * th[i];
1304
27.3k
    if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1305
27.3k
      THROW("Memory allocation failure");
1306
27.3k
    ptr = (JSAMPLE *)srcPlanes[i];
1307
80.5M
    for (row = 0; row < ph[i]; row++) {
1308
80.5M
      inbuf[i][row] = ptr;
1309
80.5M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1310
80.5M
    }
1311
27.3k
  }
1312
11.5k
  if (usetmpbuf) {
1313
11.4k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1314
11.4k
      THROW("Memory allocation failure");
1315
11.4k
    ptr = _tmpbuf;
1316
38.7k
    for (i = 0; i < cinfo->num_components; i++) {
1317
27.2k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1318
27.2k
        THROW("Memory allocation failure");
1319
260k
      for (row = 0; row < th[i]; row++) {
1320
233k
        tmpbuf[i][row] = ptr;
1321
233k
        ptr += iw[i];
1322
233k
      }
1323
27.2k
    }
1324
11.4k
  }
1325
1326
11.5k
  CATCH_LIBJPEG(this);
1327
1328
4.25M
  for (row = 0; row < (int)cinfo->image_height;
1329
4.24M
       row += cinfo->max_v_samp_factor * DCTSIZE) {
1330
4.24M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1331
4.24M
    int crow[MAX_COMPONENTS];
1332
1333
13.9M
    for (i = 0; i < cinfo->num_components; i++) {
1334
9.69M
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1335
1336
9.69M
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1337
9.69M
      if (usetmpbuf) {
1338
9.69M
        int j, k;
1339
1340
90.1M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1341
80.5M
          memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1342
          /* Duplicate last sample in row to fill out MCU */
1343
611M
          for (k = pw[i]; k < iw[i]; k++)
1344
530M
            tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1345
80.5M
        }
1346
        /* Duplicate last row to fill out MCU */
1347
9.84M
        for (j = ph[i] - crow[i]; j < th[i]; j++)
1348
150k
          memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1349
9.69M
        yuvptr[i] = tmpbuf[i];
1350
9.69M
      } else
1351
366
        yuvptr[i] = &inbuf[i][crow[i]];
1352
9.69M
    }
1353
4.24M
    jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1354
4.24M
  }
1355
11.5k
  jpeg_finish_compress(cinfo);
1356
1357
11.5k
bailout:
1358
11.5k
  if (cinfo->global_state > CSTATE_START && alloc)
1359
0
    (*cinfo->dest->term_destination) (cinfo);
1360
11.5k
  if (cinfo->global_state > CSTATE_START || retval == -1)
1361
0
    jpeg_abort_compress(cinfo);
1362
127k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1363
115k
    free(tmpbuf[i]);
1364
115k
    free(inbuf[i]);
1365
115k
  }
1366
11.5k
  free(_tmpbuf);
1367
11.5k
  if (this->jerr.warning) retval = -1;
1368
11.5k
  return retval;
1369
11.5k
}
1370
1371
/* TurboJPEG 1.4+ */
1372
DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
1373
                                      const unsigned char **srcPlanes,
1374
                                      int width, const int *strides,
1375
                                      int height, int subsamp,
1376
                                      unsigned char **jpegBuf,
1377
                                      unsigned long *jpegSize, int jpegQual,
1378
                                      int flags)
1379
0
{
1380
0
  static const char FUNCTION_NAME[] = "tjCompressFromYUVPlanes";
1381
0
  int retval = 0;
1382
0
  size_t size;
1383
1384
0
  GET_TJINSTANCE(handle, -1);
1385
1386
0
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP || jpegSize == NULL ||
1387
0
      jpegQual < 0 || jpegQual > 100)
1388
0
    THROW("Invalid argument");
1389
1390
0
  this->quality = jpegQual;
1391
0
  this->subsamp = subsamp;
1392
0
  processFlags(handle, flags, COMPRESS);
1393
1394
0
  size = (size_t)(*jpegSize);
1395
0
  retval = tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
1396
0
                                     jpegBuf, &size);
1397
0
  *jpegSize = (unsigned long)size;
1398
1399
0
bailout:
1400
0
  return retval;
1401
0
}
1402
1403
1404
/* TurboJPEG 3+ */
1405
DLLEXPORT int tj3CompressFromYUV8(tjhandle handle,
1406
                                  const unsigned char *srcBuf, int width,
1407
                                  int align, int height,
1408
                                  unsigned char **jpegBuf, size_t *jpegSize)
1409
35.7k
{
1410
35.7k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUV8";
1411
35.7k
  const unsigned char *srcPlanes[3];
1412
35.7k
  int pw0, ph0, strides[3], retval = -1;
1413
1414
35.7k
  GET_TJINSTANCE(handle, -1);
1415
1416
35.7k
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1417
35.7k
      height <= 0)
1418
35.7k
    THROW("Invalid argument");
1419
1420
35.7k
  if (this->subsamp == TJSAMP_UNKNOWN)
1421
35.7k
    THROW("TJPARAM_SUBSAMP must be specified");
1422
1423
35.7k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1424
35.7k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1425
35.7k
  srcPlanes[0] = srcBuf;
1426
35.7k
  strides[0] = PAD(pw0, align);
1427
35.7k
  if (this->subsamp == TJSAMP_GRAY) {
1428
12.0k
    strides[1] = strides[2] = 0;
1429
12.0k
    srcPlanes[1] = srcPlanes[2] = NULL;
1430
23.7k
  } else {
1431
23.7k
    int pw1 = tjPlaneWidth(1, width, this->subsamp);
1432
23.7k
    int ph1 = tjPlaneHeight(1, height, this->subsamp);
1433
1434
23.7k
    strides[1] = strides[2] = PAD(pw1, align);
1435
23.7k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1436
23.7k
        (unsigned long long)INT_MAX ||
1437
23.7k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1438
23.7k
        (unsigned long long)INT_MAX)
1439
23.7k
      THROW("Image or row alignment is too large");
1440
23.7k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1441
23.7k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1442
23.7k
  }
1443
1444
35.7k
  return tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
1445
35.7k
                                   jpegBuf, jpegSize);
1446
1447
0
bailout:
1448
0
  return retval;
1449
35.7k
}
1450
1451
/* TurboJPEG 1.4+ */
1452
DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
1453
                                int width, int align, int height, int subsamp,
1454
                                unsigned char **jpegBuf,
1455
                                unsigned long *jpegSize, int jpegQual,
1456
                                int flags)
1457
0
{
1458
0
  static const char FUNCTION_NAME[] = "tjCompressFromYUV";
1459
0
  int retval = -1;
1460
0
  size_t size;
1461
1462
0
  GET_TJINSTANCE(handle, -1);
1463
1464
0
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
1465
0
    THROW("Invalid argument");
1466
1467
0
  this->quality = jpegQual;
1468
0
  this->subsamp = subsamp;
1469
0
  processFlags(handle, flags, COMPRESS);
1470
1471
0
  size = (size_t)(*jpegSize);
1472
0
  retval = tj3CompressFromYUV8(handle, srcBuf, width, align, height, jpegBuf,
1473
0
                               &size);
1474
0
  *jpegSize = (unsigned long)size;
1475
1476
0
bailout:
1477
0
  return retval;
1478
0
}
1479
1480
1481
/* TurboJPEG 3+ */
1482
DLLEXPORT int tj3EncodeYUVPlanes8(tjhandle handle, const unsigned char *srcBuf,
1483
                                  int width, int pitch, int height,
1484
                                  int pixelFormat, unsigned char **dstPlanes,
1485
                                  int *strides)
1486
35.7k
{
1487
35.7k
  static const char FUNCTION_NAME[] = "tj3EncodeYUVPlanes8";
1488
35.7k
  JSAMPROW *row_pointer = NULL;
1489
35.7k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
1490
35.7k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
1491
35.7k
  JSAMPROW *outbuf[MAX_COMPONENTS];
1492
35.7k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1493
35.7k
  JSAMPLE *ptr;
1494
35.7k
  jpeg_component_info *compptr;
1495
1496
35.7k
  GET_CINSTANCE(handle)
1497
1498
393k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1499
357k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
1500
357k
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
1501
357k
  }
1502
1503
35.7k
  if ((this->init & COMPRESS) == 0)
1504
35.7k
    THROW("Instance has not been initialized for compression");
1505
1506
35.7k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1507
35.7k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
1508
35.7k
      !dstPlanes[0])
1509
35.7k
    THROW("Invalid argument");
1510
35.7k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1511
35.7k
    THROW("Invalid argument");
1512
1513
35.7k
  if (this->subsamp == TJSAMP_UNKNOWN)
1514
35.7k
    THROW("TJPARAM_SUBSAMP must be specified");
1515
35.7k
  if (pixelFormat == TJPF_CMYK)
1516
35.7k
    THROW("Cannot generate YUV images from packed-pixel CMYK images");
1517
1518
35.7k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1519
0
  else if (pitch < width * tjPixelSize[pixelFormat])
1520
35.7k
    THROW("Invalid argument");
1521
1522
35.7k
  CATCH_LIBJPEG(this);
1523
1524
35.7k
  cinfo->image_width = width;
1525
35.7k
  cinfo->image_height = height;
1526
35.7k
  cinfo->data_precision = 8;
1527
1528
35.7k
  setCompDefaults(this, pixelFormat, TRUE);
1529
1530
  /* Execute only the parts of jpeg_start_compress() that we need.  If we
1531
     were to call the whole jpeg_start_compress() function, then it would try
1532
     to write the file headers, which could overflow the output buffer if the
1533
     YUV image were very small. */
1534
35.7k
  if (cinfo->global_state != CSTATE_START)
1535
35.7k
    THROW("libjpeg API is in the wrong state");
1536
35.7k
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
1537
35.7k
  jinit_c_master_control(cinfo, FALSE);
1538
35.7k
  jinit_color_converter(cinfo);
1539
35.7k
  jinit_downsampler(cinfo);
1540
35.7k
  (*cinfo->cconvert->start_pass) (cinfo);
1541
1542
35.7k
  pw0 = PAD(width, cinfo->max_h_samp_factor);
1543
35.7k
  ph0 = PAD(height, cinfo->max_v_samp_factor);
1544
1545
35.7k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1546
35.7k
    THROW("Memory allocation failure");
1547
98.3M
  for (i = 0; i < height; i++) {
1548
98.3M
    if (this->bottomUp)
1549
16.2M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
1550
82.1M
    else
1551
82.1M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
1552
98.3M
  }
1553
35.7k
  if (height < ph0)
1554
6.36k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1555
1556
119k
  for (i = 0; i < cinfo->num_components; i++) {
1557
83.2k
    compptr = &cinfo->comp_info[i];
1558
83.2k
    _tmpbuf[i] = (JSAMPLE *)MALLOC(
1559
83.2k
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1560
83.2k
          compptr->h_samp_factor, 32) *
1561
83.2k
      cinfo->max_v_samp_factor + 32);
1562
83.2k
    if (!_tmpbuf[i])
1563
83.2k
      THROW("Memory allocation failure");
1564
83.2k
    tmpbuf[i] =
1565
83.2k
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
1566
83.2k
    if (!tmpbuf[i])
1567
83.2k
      THROW("Memory allocation failure");
1568
184k
    for (row = 0; row < cinfo->max_v_samp_factor; row++) {
1569
101k
      unsigned char *_tmpbuf_aligned =
1570
101k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
1571
1572
101k
      tmpbuf[i][row] = &_tmpbuf_aligned[
1573
101k
        PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1574
101k
            compptr->h_samp_factor, 32) * row];
1575
101k
    }
1576
83.2k
    _tmpbuf2[i] =
1577
83.2k
      (JSAMPLE *)MALLOC(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1578
83.2k
                        compptr->v_samp_factor + 32);
1579
83.2k
    if (!_tmpbuf2[i])
1580
83.2k
      THROW("Memory allocation failure");
1581
83.2k
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1582
83.2k
    if (!tmpbuf2[i])
1583
83.2k
      THROW("Memory allocation failure");
1584
172k
    for (row = 0; row < compptr->v_samp_factor; row++) {
1585
89.2k
      unsigned char *_tmpbuf2_aligned =
1586
89.2k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
1587
1588
89.2k
      tmpbuf2[i][row] =
1589
89.2k
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1590
89.2k
    }
1591
83.2k
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
1592
83.2k
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1593
83.2k
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1594
83.2k
    if (!outbuf[i])
1595
83.2k
      THROW("Memory allocation failure");
1596
83.2k
    ptr = dstPlanes[i];
1597
213M
    for (row = 0; row < ph[i]; row++) {
1598
213M
      outbuf[i][row] = ptr;
1599
213M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1600
213M
    }
1601
83.2k
  }
1602
1603
35.7k
  CATCH_LIBJPEG(this);
1604
1605
90.1M
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
1606
90.0M
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
1607
90.0M
                                       cinfo->max_v_samp_factor);
1608
90.0M
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
1609
295M
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
1610
205M
         i++, compptr++)
1611
205M
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
1612
205M
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
1613
205M
        compptr->v_samp_factor, pw[i]);
1614
90.0M
  }
1615
35.7k
  cinfo->next_scanline += height;
1616
35.7k
  jpeg_abort_compress(cinfo);
1617
1618
35.7k
bailout:
1619
35.7k
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1620
35.7k
  free(row_pointer);
1621
393k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1622
357k
    free(tmpbuf[i]);
1623
357k
    free(_tmpbuf[i]);
1624
357k
    free(tmpbuf2[i]);
1625
357k
    free(_tmpbuf2[i]);
1626
357k
    free(outbuf[i]);
1627
357k
  }
1628
35.7k
  if (this->jerr.warning) retval = -1;
1629
35.7k
  return retval;
1630
35.7k
}
1631
1632
/* TurboJPEG 1.4+ */
1633
DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
1634
                                int width, int pitch, int height,
1635
                                int pixelFormat, unsigned char **dstPlanes,
1636
                                int *strides, int subsamp, int flags)
1637
0
{
1638
0
  static const char FUNCTION_NAME[] = "tjEncodeYUVPlanes";
1639
0
  int retval = 0;
1640
1641
0
  GET_TJINSTANCE(handle, -1);
1642
1643
0
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
1644
0
    THROW("Invalid argument");
1645
1646
0
  this->subsamp = subsamp;
1647
0
  processFlags(handle, flags, COMPRESS);
1648
1649
0
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1650
0
                             dstPlanes, strides);
1651
1652
0
bailout:
1653
0
  return retval;
1654
0
}
1655
1656
1657
/* TurboJPEG 3+ */
1658
DLLEXPORT int tj3EncodeYUV8(tjhandle handle, const unsigned char *srcBuf,
1659
                            int width, int pitch, int height, int pixelFormat,
1660
                            unsigned char *dstBuf, int align)
1661
35.7k
{
1662
35.7k
  static const char FUNCTION_NAME[] = "tj3EncodeYUV8";
1663
35.7k
  unsigned char *dstPlanes[3];
1664
35.7k
  int pw0, ph0, strides[3], retval = -1;
1665
1666
35.7k
  GET_TJINSTANCE(handle, -1);
1667
1668
35.7k
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
1669
35.7k
      !IS_POW2(align))
1670
35.7k
    THROW("Invalid argument");
1671
1672
35.7k
  if (this->subsamp == TJSAMP_UNKNOWN)
1673
35.7k
    THROW("TJPARAM_SUBSAMP must be specified");
1674
1675
35.7k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1676
35.7k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1677
35.7k
  dstPlanes[0] = dstBuf;
1678
35.7k
  strides[0] = PAD(pw0, align);
1679
35.7k
  if (this->subsamp == TJSAMP_GRAY) {
1680
12.0k
    strides[1] = strides[2] = 0;
1681
12.0k
    dstPlanes[1] = dstPlanes[2] = NULL;
1682
23.7k
  } else {
1683
23.7k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
1684
23.7k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
1685
1686
23.7k
    strides[1] = strides[2] = PAD(pw1, align);
1687
23.7k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1688
23.7k
        (unsigned long long)INT_MAX ||
1689
23.7k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1690
23.7k
        (unsigned long long)INT_MAX)
1691
23.7k
      THROW("Image or row alignment is too large");
1692
23.7k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1693
23.7k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1694
23.7k
  }
1695
1696
35.7k
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1697
35.7k
                             dstPlanes, strides);
1698
1699
0
bailout:
1700
0
  return retval;
1701
35.7k
}
1702
1703
/* TurboJPEG 1.4+ */
1704
DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
1705
                           int width, int pitch, int height, int pixelFormat,
1706
                           unsigned char *dstBuf, int align, int subsamp,
1707
                           int flags)
1708
0
{
1709
0
  static const char FUNCTION_NAME[] = "tjEncodeYUV3";
1710
0
  int retval = 0;
1711
1712
0
  GET_TJINSTANCE(handle, -1);
1713
1714
0
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
1715
0
    THROW("Invalid argument");
1716
1717
0
  this->subsamp = subsamp;
1718
0
  processFlags(handle, flags, COMPRESS);
1719
1720
0
  return tj3EncodeYUV8(handle, srcBuf, width, pitch, height, pixelFormat,
1721
0
                       dstBuf, align);
1722
1723
0
bailout:
1724
0
  return retval;
1725
0
}
1726
1727
/* TurboJPEG 1.2+ */
1728
DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
1729
                           int pitch, int height, int pixelFormat,
1730
                           unsigned char *dstBuf, int subsamp, int flags)
1731
0
{
1732
0
  return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1733
0
                      dstBuf, 4, subsamp, flags);
1734
0
}
1735
1736
/* TurboJPEG 1.1+ */
1737
DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
1738
                          int pitch, int height, int pixelSize,
1739
                          unsigned char *dstBuf, int subsamp, int flags)
1740
0
{
1741
0
  return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1742
0
                      getPixelFormat(pixelSize, flags), dstBuf, subsamp,
1743
0
                      flags);
1744
0
}
1745
1746
1747
/******************************* Decompressor ********************************/
1748
1749
static tjhandle _tjInitDecompress(tjinstance *this)
1750
53.2k
{
1751
53.2k
  static unsigned char buffer[1];
1752
1753
  /* This is also straight out of example.c */
1754
53.2k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1755
53.2k
  this->jerr.pub.error_exit = my_error_exit;
1756
53.2k
  this->jerr.pub.output_message = my_output_message;
1757
53.2k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1758
53.2k
  this->jerr.pub.emit_message = my_emit_message;
1759
53.2k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1760
53.2k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1761
53.2k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1762
1763
53.2k
  if (setjmp(this->jerr.setjmp_buffer)) {
1764
    /* If we get here, the JPEG code has signaled an error. */
1765
0
    free(this);
1766
0
    return NULL;
1767
0
  }
1768
1769
53.2k
  jpeg_create_decompress(&this->dinfo);
1770
  /* Make an initial call so it will create the source manager */
1771
53.2k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1772
1773
53.2k
  this->init |= DECOMPRESS;
1774
53.2k
  return (tjhandle)this;
1775
53.2k
}
1776
1777
/* TurboJPEG 1.0+ */
1778
DLLEXPORT tjhandle tjInitDecompress(void)
1779
0
{
1780
0
  return tj3Init(TJINIT_DECOMPRESS);
1781
0
}
1782
1783
1784
/* TurboJPEG 3+ */
1785
DLLEXPORT int tj3DecompressHeader(tjhandle handle,
1786
                                  const unsigned char *jpegBuf,
1787
                                  size_t jpegSize)
1788
13.5k
{
1789
13.5k
  static const char FUNCTION_NAME[] = "tj3DecompressHeader";
1790
13.5k
  int retval = 0;
1791
1792
13.5k
  GET_DINSTANCE(handle);
1793
13.5k
  if ((this->init & DECOMPRESS) == 0)
1794
13.5k
    THROW("Instance has not been initialized for decompression");
1795
1796
13.5k
  if (jpegBuf == NULL || jpegSize <= 0)
1797
13.5k
    THROW("Invalid argument");
1798
1799
13.5k
  CATCH_LIBJPEG(this);
1800
1801
12.2k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1802
1803
  /* jpeg_read_header() calls jpeg_abort() and returns JPEG_HEADER_TABLES_ONLY
1804
     if the datastream is a tables-only datastream.  Since we aren't using a
1805
     suspending data source, the only other value it can return is
1806
     JPEG_HEADER_OK. */
1807
12.2k
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1808
1.13k
    return 0;
1809
1810
11.1k
  setDecompParameters(this);
1811
1812
11.1k
  jpeg_abort_decompress(dinfo);
1813
1814
11.1k
  if (this->colorspace < 0)
1815
11.1k
    THROW("Could not determine colorspace of JPEG image");
1816
11.1k
  if (this->jpegWidth < 1 || this->jpegHeight < 1)
1817
11.1k
    THROW("Invalid data returned in header");
1818
1819
12.4k
bailout:
1820
12.4k
  if (this->jerr.warning) retval = -1;
1821
12.4k
  return retval;
1822
11.1k
}
1823
1824
/* TurboJPEG 1.4+ */
1825
DLLEXPORT int tjDecompressHeader3(tjhandle handle,
1826
                                  const unsigned char *jpegBuf,
1827
                                  unsigned long jpegSize, int *width,
1828
                                  int *height, int *jpegSubsamp,
1829
                                  int *jpegColorspace)
1830
0
{
1831
0
  static const char FUNCTION_NAME[] = "tjDecompressHeader3";
1832
0
  int retval = 0;
1833
1834
0
  GET_TJINSTANCE(handle, -1);
1835
1836
0
  if (width == NULL || height == NULL || jpegSubsamp == NULL ||
1837
0
      jpegColorspace == NULL)
1838
0
    THROW("Invalid argument");
1839
1840
0
  retval = tj3DecompressHeader(handle, jpegBuf, jpegSize);
1841
1842
0
  *width = tj3Get(handle, TJPARAM_JPEGWIDTH);
1843
0
  *height = tj3Get(handle, TJPARAM_JPEGHEIGHT);
1844
0
  *jpegSubsamp = tj3Get(handle, TJPARAM_SUBSAMP);
1845
0
  if (*jpegSubsamp == TJSAMP_UNKNOWN)
1846
0
    THROW("Could not determine subsampling level of JPEG image");
1847
0
  *jpegColorspace = tj3Get(handle, TJPARAM_COLORSPACE);
1848
1849
0
bailout:
1850
0
  return retval;
1851
0
}
1852
1853
/* TurboJPEG 1.1+ */
1854
DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
1855
                                  unsigned long jpegSize, int *width,
1856
                                  int *height, int *jpegSubsamp)
1857
0
{
1858
0
  int jpegColorspace;
1859
1860
0
  return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1861
0
                             jpegSubsamp, &jpegColorspace);
1862
0
}
1863
1864
/* TurboJPEG 1.0+ */
1865
DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
1866
                                 unsigned long jpegSize, int *width,
1867
                                 int *height)
1868
0
{
1869
0
  int jpegSubsamp;
1870
1871
0
  return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1872
0
                             &jpegSubsamp);
1873
0
}
1874
1875
1876
/* TurboJPEG 3+ */
1877
DLLEXPORT tjscalingfactor *tj3GetScalingFactors(int *numScalingFactors)
1878
0
{
1879
0
  static const char FUNCTION_NAME[] = "tj3GetScalingFactors";
1880
0
  tjscalingfactor *retval = (tjscalingfactor *)sf;
1881
1882
0
  if (numScalingFactors == NULL)
1883
0
    THROWG("Invalid argument", NULL);
1884
1885
0
  *numScalingFactors = NUMSF;
1886
1887
0
bailout:
1888
0
  return retval;
1889
0
}
1890
1891
/* TurboJPEG 1.2+ */
1892
DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numScalingFactors)
1893
0
{
1894
0
  return tj3GetScalingFactors(numScalingFactors);
1895
0
}
1896
1897
1898
/* TurboJPEG 3+ */
1899
DLLEXPORT int tj3SetScalingFactor(tjhandle handle,
1900
                                  tjscalingfactor scalingFactor)
1901
97.2k
{
1902
97.2k
  static const char FUNCTION_NAME[] = "tj3SetScalingFactor";
1903
97.2k
  int i, retval = 0;
1904
1905
97.2k
  GET_TJINSTANCE(handle, -1);
1906
97.2k
  if ((this->init & DECOMPRESS) == 0)
1907
97.2k
    THROW("Instance has not been initialized for decompression");
1908
1909
1.04M
  for (i = 0; i < NUMSF; i++) {
1910
1.04M
    if (scalingFactor.num == sf[i].num && scalingFactor.denom == sf[i].denom)
1911
97.2k
      break;
1912
1.04M
  }
1913
97.2k
  if (i >= NUMSF)
1914
97.2k
    THROW("Unsupported scaling factor");
1915
1916
97.2k
  this->scalingFactor = scalingFactor;
1917
1918
97.2k
bailout:
1919
97.2k
  return retval;
1920
97.2k
}
1921
1922
1923
/* TurboJPEG 3+ */
1924
DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion)
1925
16.9k
{
1926
16.9k
  static const char FUNCTION_NAME[] = "tj3SetCroppingRegion";
1927
16.9k
  int retval = 0, scaledWidth, scaledHeight;
1928
1929
16.9k
  GET_TJINSTANCE(handle, -1);
1930
16.9k
  if ((this->init & DECOMPRESS) == 0)
1931
16.9k
    THROW("Instance has not been initialized for decompression");
1932
1933
16.9k
  if (croppingRegion.x == 0 && croppingRegion.y == 0 &&
1934
15.9k
      croppingRegion.w == 0 && croppingRegion.h == 0) {
1935
15.9k
    this->croppingRegion = croppingRegion;
1936
15.9k
    return 0;
1937
15.9k
  }
1938
1939
1.00k
  if (croppingRegion.x < 0 || croppingRegion.y < 0 || croppingRegion.w < 0 ||
1940
1.00k
      croppingRegion.h < 0)
1941
1.00k
    THROW("Invalid cropping region");
1942
1.00k
  if (this->jpegWidth < 0 || this->jpegHeight < 0)
1943
1.00k
    THROW("JPEG header has not yet been read");
1944
1.00k
  if (this->precision == 16 || this->lossless)
1945
999
    THROW("Cannot partially decompress lossless JPEG images");
1946
999
  if (this->subsamp == TJSAMP_UNKNOWN)
1947
892
    THROW("Could not determine subsampling level of JPEG image");
1948
1949
892
  scaledWidth = TJSCALED(this->jpegWidth, this->scalingFactor);
1950
892
  scaledHeight = TJSCALED(this->jpegHeight, this->scalingFactor);
1951
1952
892
  if (croppingRegion.x %
1953
892
      TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor) != 0)
1954
0
    THROWI("The left boundary of the cropping region (%d) is not\n"
1955
892
           "divisible by the scaled iMCU width (%d)",
1956
892
           croppingRegion.x,
1957
892
           TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor));
1958
892
  if (croppingRegion.w == 0)
1959
0
    croppingRegion.w = scaledWidth - croppingRegion.x;
1960
892
  if (croppingRegion.h == 0)
1961
0
    croppingRegion.h = scaledHeight - croppingRegion.y;
1962
892
  if (croppingRegion.w <= 0 || croppingRegion.h <= 0 ||
1963
892
      croppingRegion.x + croppingRegion.w > scaledWidth ||
1964
892
      croppingRegion.y + croppingRegion.h > scaledHeight)
1965
892
    THROW("The cropping region exceeds the scaled image dimensions");
1966
1967
892
  this->croppingRegion = croppingRegion;
1968
1969
1.00k
bailout:
1970
1.00k
  return retval;
1971
892
}
1972
1973
1974
/* tj3Decompress*() is implemented in turbojpeg-mp.c */
1975
1976
/* TurboJPEG 1.2+ */
1977
DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
1978
                            unsigned long jpegSize, unsigned char *dstBuf,
1979
                            int width, int pitch, int height, int pixelFormat,
1980
                            int flags)
1981
0
{
1982
0
  static const char FUNCTION_NAME[] = "tjDecompress2";
1983
0
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
1984
1985
0
  GET_DINSTANCE(handle);
1986
0
  if ((this->init & DECOMPRESS) == 0)
1987
0
    THROW("Instance has not been initialized for decompression");
1988
1989
0
  if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
1990
0
    THROW("Invalid argument");
1991
1992
0
  CATCH_LIBJPEG(this);
1993
1994
0
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1995
0
  jpeg_read_header(dinfo, TRUE);
1996
0
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1997
0
  if (width == 0) width = jpegwidth;
1998
0
  if (height == 0) height = jpegheight;
1999
0
  for (i = 0; i < NUMSF; i++) {
2000
0
    scaledw = TJSCALED(jpegwidth, sf[i]);
2001
0
    scaledh = TJSCALED(jpegheight, sf[i]);
2002
0
    if (scaledw <= width && scaledh <= height)
2003
0
      break;
2004
0
  }
2005
0
  if (i >= NUMSF)
2006
0
    THROW("Could not scale down to desired image dimensions");
2007
0
  if (dinfo->master->lossless && ((JDIMENSION)scaledw != dinfo->image_width ||
2008
0
                                  (JDIMENSION)scaledh != dinfo->image_height))
2009
0
    THROW("Cannot use decompression scaling with lossless JPEG images");
2010
2011
0
  processFlags(handle, flags, DECOMPRESS);
2012
2013
0
  if (tj3SetScalingFactor(handle, sf[i]) == -1)
2014
0
    return -1;
2015
0
  if (tj3SetCroppingRegion(handle, TJUNCROPPED) == -1)
2016
0
    return -1;
2017
0
  return tj3Decompress8(handle, jpegBuf, jpegSize, dstBuf, pitch, pixelFormat);
2018
2019
0
bailout:
2020
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2021
0
  if (this->jerr.warning) retval = -1;
2022
0
  return retval;
2023
0
}
2024
2025
/* TurboJPEG 1.0+ */
2026
DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
2027
                           unsigned long jpegSize, unsigned char *dstBuf,
2028
                           int width, int pitch, int height, int pixelSize,
2029
                           int flags)
2030
0
{
2031
0
  if (flags & TJ_YUV)
2032
0
    return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
2033
0
  else
2034
0
    return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
2035
0
                         height, getPixelFormat(pixelSize, flags), flags);
2036
0
}
2037
2038
2039
/* TurboJPEG 3+ */
2040
DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle,
2041
                                        const unsigned char *jpegBuf,
2042
                                        size_t jpegSize,
2043
                                        unsigned char **dstPlanes,
2044
                                        int *strides)
2045
31.5k
{
2046
31.5k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUVPlanes8";
2047
31.5k
  int i, row, retval = 0;
2048
31.5k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
2049
31.5k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
2050
31.5k
  JSAMPLE *_tmpbuf = NULL, *ptr;
2051
31.5k
  JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
2052
31.5k
  int dctsize;
2053
31.5k
  struct my_progress_mgr progress;
2054
2055
31.5k
  GET_DINSTANCE(handle);
2056
2057
346k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2058
315k
    tmpbuf[i] = NULL;  outbuf[i] = NULL;
2059
315k
  }
2060
2061
31.5k
  if ((this->init & DECOMPRESS) == 0)
2062
31.5k
    THROW("Instance has not been initialized for decompression");
2063
2064
31.5k
  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0])
2065
31.5k
    THROW("Invalid argument");
2066
2067
31.5k
  if (this->scanLimit) {
2068
31.5k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2069
31.5k
    progress.pub.progress_monitor = my_progress_monitor;
2070
31.5k
    progress.this = this;
2071
31.5k
    dinfo->progress = &progress.pub;
2072
31.5k
  } else
2073
0
    dinfo->progress = NULL;
2074
2075
31.5k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2076
2077
31.5k
  CATCH_LIBJPEG(this);
2078
2079
31.5k
  if (dinfo->global_state <= DSTATE_INHEADER) {
2080
0
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2081
0
    jpeg_read_header(dinfo, TRUE);
2082
0
  }
2083
31.5k
  setDecompParameters(this);
2084
31.5k
  if (this->maxPixels &&
2085
0
      (unsigned long long)this->jpegWidth * this->jpegHeight >
2086
0
      (unsigned long long)this->maxPixels)
2087
31.5k
    THROW("Image is too large");
2088
31.5k
  if (this->subsamp == TJSAMP_UNKNOWN)
2089
31.5k
    THROW("Could not determine subsampling level of JPEG image");
2090
2091
31.5k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
2092
31.5k
    THROW("Invalid argument");
2093
2094
31.5k
  if (dinfo->num_components > 3)
2095
31.4k
    THROW("JPEG image must have 3 or fewer components");
2096
2097
31.4k
  dinfo->scale_num = this->scalingFactor.num;
2098
31.4k
  dinfo->scale_denom = this->scalingFactor.denom;
2099
31.4k
  jpeg_calc_output_dimensions(dinfo);
2100
2101
31.4k
  dctsize = DCTSIZE * this->scalingFactor.num / this->scalingFactor.denom;
2102
2103
104k
  for (i = 0; i < dinfo->num_components; i++) {
2104
73.1k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
2105
73.1k
    int ih;
2106
2107
73.1k
    iw[i] = compptr->width_in_blocks * dctsize;
2108
73.1k
    ih = compptr->height_in_blocks * dctsize;
2109
73.1k
    pw[i] = tj3YUVPlaneWidth(i, dinfo->output_width, this->subsamp);
2110
73.1k
    ph[i] = tj3YUVPlaneHeight(i, dinfo->output_height, this->subsamp);
2111
73.1k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
2112
73.1k
    th[i] = compptr->v_samp_factor * dctsize;
2113
73.1k
    tmpbufsize += iw[i] * th[i];
2114
73.1k
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
2115
73.1k
      THROW("Memory allocation failure");
2116
73.1k
    ptr = dstPlanes[i];
2117
333M
    for (row = 0; row < ph[i]; row++) {
2118
333M
      outbuf[i][row] = ptr;
2119
333M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2120
333M
    }
2121
73.1k
  }
2122
31.4k
  if (usetmpbuf) {
2123
26.8k
    if ((_tmpbuf = (JSAMPLE *)MALLOC(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
2124
26.8k
      THROW("Memory allocation failure");
2125
26.8k
    ptr = _tmpbuf;
2126
89.3k
    for (i = 0; i < dinfo->num_components; i++) {
2127
62.4k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
2128
62.4k
        THROW("Memory allocation failure");
2129
741k
      for (row = 0; row < th[i]; row++) {
2130
679k
        tmpbuf[i][row] = ptr;
2131
679k
        ptr += iw[i];
2132
679k
      }
2133
62.4k
    }
2134
26.8k
  }
2135
2136
31.4k
  CATCH_LIBJPEG(this);
2137
2138
10.6k
  dinfo->do_fancy_upsampling = !this->fastUpsample;
2139
10.6k
  dinfo->dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2140
10.6k
  dinfo->raw_data_out = TRUE;
2141
2142
10.6k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2143
2144
10.6k
  jpeg_start_decompress(dinfo);
2145
3.79M
  for (row = 0; row < (int)dinfo->output_height;
2146
3.78M
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
2147
3.78M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
2148
3.78M
    int crow[MAX_COMPONENTS];
2149
2150
10.5M
    for (i = 0; i < dinfo->num_components; i++) {
2151
6.76M
      jpeg_component_info *compptr = &dinfo->comp_info[i];
2152
2153
6.76M
      if (this->subsamp == TJSAMP_420) {
2154
        /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
2155
           to be clever and use the IDCT to perform upsampling on the U and V
2156
           planes.  For instance, if the output image is to be scaled by 1/2
2157
           relative to the JPEG image, then the scaling factor and upsampling
2158
           effectively cancel each other, so a normal 8x8 IDCT can be used.
2159
           However, this is not desirable when using the decompress-to-YUV
2160
           functionality in TurboJPEG, since we want to output the U and V
2161
           planes in their subsampled form.  Thus, we have to override some
2162
           internal libjpeg parameters to force it to use the "scaled" IDCT
2163
           functions on the U and V planes. */
2164
1.20M
        compptr->_DCT_scaled_size = dctsize;
2165
1.20M
        compptr->MCU_sample_width = tjMCUWidth[this->subsamp] *
2166
1.20M
          this->scalingFactor.num / this->scalingFactor.denom *
2167
1.20M
          compptr->h_samp_factor / dinfo->max_h_samp_factor;
2168
1.20M
        dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
2169
1.20M
      }
2170
6.76M
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2171
6.76M
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
2172
1.21M
      else yuvptr[i] = &outbuf[i][crow[i]];
2173
6.76M
    }
2174
3.78M
    jpeg_read_raw_data(dinfo, yuvptr,
2175
3.78M
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
2176
3.78M
    if (usetmpbuf) {
2177
3.01M
      int j;
2178
2179
8.54M
      for (i = 0; i < dinfo->num_components; i++) {
2180
57.9M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
2181
52.3M
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
2182
52.3M
        }
2183
5.53M
      }
2184
3.01M
    }
2185
3.78M
  }
2186
10.6k
  jpeg_finish_decompress(dinfo);
2187
2188
31.5k
bailout:
2189
31.5k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2190
346k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2191
315k
    free(tmpbuf[i]);
2192
315k
    free(outbuf[i]);
2193
315k
  }
2194
31.5k
  free(_tmpbuf);
2195
31.5k
  if (this->jerr.warning) retval = -1;
2196
31.5k
  return retval;
2197
10.6k
}
2198
2199
/* TurboJPEG 1.4+ */
2200
DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
2201
                                      const unsigned char *jpegBuf,
2202
                                      unsigned long jpegSize,
2203
                                      unsigned char **dstPlanes, int width,
2204
                                      int *strides, int height, int flags)
2205
0
{
2206
0
  static const char FUNCTION_NAME[] = "tjDecompressToYUVPlanes";
2207
0
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
2208
2209
0
  GET_DINSTANCE(handle);
2210
0
  if ((this->init & DECOMPRESS) == 0)
2211
0
    THROW("Instance has not been initialized for decompression");
2212
2213
0
  if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
2214
0
    THROW("Invalid argument");
2215
2216
0
  CATCH_LIBJPEG(this);
2217
2218
0
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2219
0
  jpeg_read_header(dinfo, TRUE);
2220
0
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
2221
0
  if (width == 0) width = jpegwidth;
2222
0
  if (height == 0) height = jpegheight;
2223
0
  for (i = 0; i < NUMSF; i++) {
2224
0
    scaledw = TJSCALED(jpegwidth, sf[i]);
2225
0
    scaledh = TJSCALED(jpegheight, sf[i]);
2226
0
    if (scaledw <= width && scaledh <= height)
2227
0
      break;
2228
0
  }
2229
0
  if (i >= NUMSF)
2230
0
    THROW("Could not scale down to desired image dimensions");
2231
2232
0
  processFlags(handle, flags, DECOMPRESS);
2233
2234
0
  if (tj3SetScalingFactor(handle, sf[i]) == -1)
2235
0
    return -1;
2236
0
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2237
0
                                   strides);
2238
2239
0
bailout:
2240
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2241
0
  if (this->jerr.warning) retval = -1;
2242
0
  return retval;
2243
0
}
2244
2245
2246
/* TurboJPEG 3+ */
2247
DLLEXPORT int tj3DecompressToYUV8(tjhandle handle,
2248
                                  const unsigned char *jpegBuf,
2249
                                  size_t jpegSize,
2250
                                  unsigned char *dstBuf, int align)
2251
48.9k
{
2252
48.9k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUV8";
2253
48.9k
  unsigned char *dstPlanes[3];
2254
48.9k
  int pw0, ph0, strides[3], retval = -1;
2255
48.9k
  int width, height;
2256
2257
48.9k
  GET_DINSTANCE(handle);
2258
2259
48.9k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || align < 1 ||
2260
48.9k
      !IS_POW2(align))
2261
48.9k
    THROW("Invalid argument");
2262
2263
48.9k
  CATCH_LIBJPEG(this);
2264
2265
48.9k
  if (dinfo->global_state <= DSTATE_INHEADER) {
2266
48.9k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2267
48.9k
    jpeg_read_header(dinfo, TRUE);
2268
48.9k
  }
2269
48.9k
  setDecompParameters(this);
2270
48.9k
  if (this->subsamp == TJSAMP_UNKNOWN)
2271
48.2k
    THROW("Could not determine subsampling level of JPEG image");
2272
2273
48.2k
  width = TJSCALED(dinfo->image_width, this->scalingFactor);
2274
48.2k
  height = TJSCALED(dinfo->image_height, this->scalingFactor);
2275
2276
48.2k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2277
48.2k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2278
48.2k
  dstPlanes[0] = dstBuf;
2279
48.2k
  strides[0] = PAD(pw0, align);
2280
48.2k
  if (this->subsamp == TJSAMP_GRAY) {
2281
19.7k
    strides[1] = strides[2] = 0;
2282
19.7k
    dstPlanes[1] = dstPlanes[2] = NULL;
2283
28.4k
  } else {
2284
28.4k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2285
28.4k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2286
2287
28.4k
    strides[1] = strides[2] = PAD(pw1, align);
2288
28.4k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2289
28.4k
        (unsigned long long)INT_MAX ||
2290
28.4k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2291
28.4k
        (unsigned long long)INT_MAX)
2292
28.4k
      THROW("Image or row alignment is too large");
2293
28.4k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
2294
28.4k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
2295
28.4k
  }
2296
2297
48.2k
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2298
48.2k
                                   strides);
2299
2300
791
bailout:
2301
791
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2302
791
  if (this->jerr.warning) retval = -1;
2303
791
  return retval;
2304
48.2k
}
2305
2306
/* TurboJPEG 1.4+ */
2307
DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
2308
                                 unsigned long jpegSize, unsigned char *dstBuf,
2309
                                 int width, int align, int height, int flags)
2310
0
{
2311
0
  static const char FUNCTION_NAME[] = "tjDecompressToYUV2";
2312
0
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
2313
2314
0
  GET_DINSTANCE(handle);
2315
0
  if ((this->init & DECOMPRESS) == 0)
2316
0
    THROW("Instance has not been initialized for decompression");
2317
2318
0
  if (jpegBuf == NULL || jpegSize <= 0 || width < 0 || height < 0)
2319
0
    THROW("Invalid argument");
2320
2321
0
  CATCH_LIBJPEG(this);
2322
2323
0
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2324
0
  jpeg_read_header(dinfo, TRUE);
2325
0
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
2326
0
  if (width == 0) width = jpegwidth;
2327
0
  if (height == 0) height = jpegheight;
2328
0
  for (i = 0; i < NUMSF; i++) {
2329
0
    scaledw = TJSCALED(jpegwidth, sf[i]);
2330
0
    scaledh = TJSCALED(jpegheight, sf[i]);
2331
0
    if (scaledw <= width && scaledh <= height)
2332
0
      break;
2333
0
  }
2334
0
  if (i >= NUMSF)
2335
0
    THROW("Could not scale down to desired image dimensions");
2336
2337
0
  width = scaledw;  height = scaledh;
2338
2339
0
  processFlags(handle, flags, DECOMPRESS);
2340
2341
0
  if (tj3SetScalingFactor(handle, sf[i]) == -1)
2342
0
    return -1;
2343
0
  return tj3DecompressToYUV8(handle, jpegBuf, (size_t)jpegSize, dstBuf, align);
2344
2345
0
bailout:
2346
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2347
0
  if (this->jerr.warning) retval = -1;
2348
0
  return retval;
2349
0
}
2350
2351
/* TurboJPEG 1.1+ */
2352
DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
2353
                                unsigned long jpegSize, unsigned char *dstBuf,
2354
                                int flags)
2355
0
{
2356
0
  return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
2357
0
}
2358
2359
2360
static void setDecodeDefaults(tjinstance *this, int pixelFormat)
2361
2.40k
{
2362
2.40k
  int i;
2363
2364
2.40k
  this->dinfo.scale_num = this->dinfo.scale_denom = 1;
2365
2366
2.40k
  if (this->subsamp == TJSAMP_GRAY) {
2367
890
    this->dinfo.num_components = this->dinfo.comps_in_scan = 1;
2368
890
    this->dinfo.jpeg_color_space = JCS_GRAYSCALE;
2369
1.51k
  } else {
2370
1.51k
    this->dinfo.num_components = this->dinfo.comps_in_scan = 3;
2371
1.51k
    this->dinfo.jpeg_color_space = JCS_YCbCr;
2372
1.51k
  }
2373
2374
2.40k
  this->dinfo.comp_info = (jpeg_component_info *)
2375
2.40k
    (*this->dinfo.mem->alloc_small) ((j_common_ptr)&this->dinfo, JPOOL_IMAGE,
2376
2.40k
                                     this->dinfo.num_components *
2377
2.40k
                                     sizeof(jpeg_component_info));
2378
2379
7.84k
  for (i = 0; i < this->dinfo.num_components; i++) {
2380
5.43k
    jpeg_component_info *compptr = &this->dinfo.comp_info[i];
2381
2382
5.43k
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[this->subsamp] / 8 : 1;
2383
5.43k
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[this->subsamp] / 8 : 1;
2384
5.43k
    compptr->component_index = i;
2385
5.43k
    compptr->component_id = i + 1;
2386
5.43k
    compptr->quant_tbl_no = compptr->dc_tbl_no =
2387
5.43k
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
2388
5.43k
    this->dinfo.cur_comp_info[i] = compptr;
2389
5.43k
  }
2390
2.40k
  this->dinfo.data_precision = 8;
2391
7.21k
  for (i = 0; i < 2; i++) {
2392
4.81k
    if (this->dinfo.quant_tbl_ptrs[i] == NULL)
2393
598
      this->dinfo.quant_tbl_ptrs[i] =
2394
598
        jpeg_alloc_quant_table((j_common_ptr)&this->dinfo);
2395
4.81k
  }
2396
2397
2.40k
  this->dinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2398
2.40k
}
2399
2400
2401
static int my_read_markers(j_decompress_ptr dinfo)
2402
2.40k
{
2403
2.40k
  return JPEG_REACHED_SOS;
2404
2.40k
}
2405
2406
static void my_reset_marker_reader(j_decompress_ptr dinfo)
2407
2.40k
{
2408
2.40k
}
2409
2410
/* TurboJPEG 3+ */
2411
DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle,
2412
                                  const unsigned char * const *srcPlanes,
2413
                                  const int *strides, unsigned char *dstBuf,
2414
                                  int width, int pitch, int height,
2415
                                  int pixelFormat)
2416
2.40k
{
2417
2.40k
  static const char FUNCTION_NAME[] = "tj3DecodeYUVPlanes8";
2418
2.40k
  JSAMPROW *row_pointer = NULL;
2419
2.40k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS];
2420
2.40k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
2421
2.40k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
2422
2.40k
  JSAMPLE *ptr;
2423
2.40k
  jpeg_component_info *compptr;
2424
2.40k
  int (*old_read_markers) (j_decompress_ptr) = NULL;
2425
2.40k
  void (*old_reset_marker_reader) (j_decompress_ptr) = NULL;
2426
2427
2.40k
  GET_DINSTANCE(handle);
2428
2429
26.4k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2430
24.0k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;  inbuf[i] = NULL;
2431
24.0k
  }
2432
2433
2.40k
  if ((this->init & DECOMPRESS) == 0)
2434
2.40k
    THROW("Instance has not been initialized for decompression");
2435
2436
2.40k
  if (!srcPlanes || !srcPlanes[0] || dstBuf == NULL || width <= 0 ||
2437
2.40k
      pitch < 0 || height <= 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
2438
2.40k
    THROW("Invalid argument");
2439
2.40k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
2440
2.40k
    THROW("Invalid argument");
2441
2442
2.40k
  if (this->subsamp == TJSAMP_UNKNOWN)
2443
2.40k
    THROW("TJPARAM_SUBSAMP must be specified");
2444
2.40k
  if (pixelFormat == TJPF_CMYK)
2445
2.40k
    THROW("Cannot decode YUV images into packed-pixel CMYK images.");
2446
2447
2.40k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
2448
0
  else if (pitch < width * tjPixelSize[pixelFormat])
2449
2.40k
    THROW("Invalid argument");
2450
2.40k
  dinfo->image_width = width;
2451
2.40k
  dinfo->image_height = height;
2452
2453
2.40k
  dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
2454
2.40k
  dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
2455
2.40k
  dinfo->Se = DCTSIZE2 - 1;
2456
2.40k
  setDecodeDefaults(this, pixelFormat);
2457
2.40k
  old_read_markers = dinfo->marker->read_markers;
2458
2.40k
  dinfo->marker->read_markers = my_read_markers;
2459
2.40k
  old_reset_marker_reader = dinfo->marker->reset_marker_reader;
2460
2.40k
  dinfo->marker->reset_marker_reader = my_reset_marker_reader;
2461
2.40k
  CATCH_LIBJPEG(this);
2462
2.38k
  jpeg_read_header(dinfo, TRUE);
2463
2.38k
  dinfo->marker->read_markers = old_read_markers;
2464
2.38k
  dinfo->marker->reset_marker_reader = old_reset_marker_reader;
2465
2466
2.38k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
2467
2.38k
  this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2468
2.38k
  dinfo->do_fancy_upsampling = FALSE;
2469
2.38k
  dinfo->Se = DCTSIZE2 - 1;
2470
2.38k
  jinit_master_decompress(dinfo);
2471
2.38k
  (*dinfo->upsample->start_pass) (dinfo);
2472
2473
2.38k
  pw0 = PAD(width, dinfo->max_h_samp_factor);
2474
2.38k
  ph0 = PAD(height, dinfo->max_v_samp_factor);
2475
2476
2.38k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
2477
2478
2.38k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
2479
2.38k
    THROW("Memory allocation failure");
2480
13.6M
  for (i = 0; i < height; i++) {
2481
13.6M
    if (this->bottomUp)
2482
4.74M
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
2483
8.88M
    else
2484
8.88M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
2485
13.6M
  }
2486
2.38k
  if (height < ph0)
2487
1.18k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
2488
2489
7.74k
  for (i = 0; i < dinfo->num_components; i++) {
2490
5.36k
    compptr = &dinfo->comp_info[i];
2491
5.36k
    _tmpbuf[i] =
2492
5.36k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
2493
5.36k
                        compptr->v_samp_factor + 32);
2494
5.36k
    if (!_tmpbuf[i])
2495
5.36k
      THROW("Memory allocation failure");
2496
5.36k
    tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
2497
5.36k
    if (!tmpbuf[i])
2498
5.36k
      THROW("Memory allocation failure");
2499
11.9k
    for (row = 0; row < compptr->v_samp_factor; row++) {
2500
6.63k
      unsigned char *_tmpbuf_aligned =
2501
6.63k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
2502
2503
6.63k
      tmpbuf[i][row] =
2504
6.63k
        &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
2505
6.63k
    }
2506
5.36k
    pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
2507
5.36k
    ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2508
5.36k
    inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
2509
5.36k
    if (!inbuf[i])
2510
5.36k
      THROW("Memory allocation failure");
2511
5.36k
    ptr = (JSAMPLE *)srcPlanes[i];
2512
24.7M
    for (row = 0; row < ph[i]; row++) {
2513
24.7M
      inbuf[i][row] = ptr;
2514
24.7M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2515
24.7M
    }
2516
5.36k
  }
2517
2518
2.38k
  CATCH_LIBJPEG(this);
2519
2520
11.8M
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
2521
11.8M
    JDIMENSION inrow = 0, outrow = 0;
2522
2523
34.8M
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
2524
22.9M
         i++, compptr++)
2525
22.9M
      jcopy_sample_rows(inbuf[i],
2526
22.9M
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
2527
22.9M
        compptr->v_samp_factor, pw[i]);
2528
11.8M
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
2529
11.8M
                                 dinfo->max_v_samp_factor, &row_pointer[row],
2530
11.8M
                                 &outrow, dinfo->max_v_samp_factor);
2531
11.8M
  }
2532
2.38k
  jpeg_abort_decompress(dinfo);
2533
2534
2.40k
bailout:
2535
2.40k
  if (old_read_markers)
2536
2.40k
    dinfo->marker->read_markers = old_read_markers;
2537
2.40k
  if (old_reset_marker_reader)
2538
2.40k
    dinfo->marker->reset_marker_reader = old_reset_marker_reader;
2539
2.40k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2540
2.40k
  free(row_pointer);
2541
26.4k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2542
24.0k
    free(tmpbuf[i]);
2543
24.0k
    free(_tmpbuf[i]);
2544
24.0k
    free(inbuf[i]);
2545
24.0k
  }
2546
2.40k
  if (this->jerr.warning) retval = -1;
2547
2.40k
  return retval;
2548
2.38k
}
2549
2550
/* TurboJPEG 1.4+ */
2551
DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
2552
                                const unsigned char **srcPlanes,
2553
                                const int *strides, int subsamp,
2554
                                unsigned char *dstBuf, int width, int pitch,
2555
                                int height, int pixelFormat, int flags)
2556
0
{
2557
0
  static const char FUNCTION_NAME[] = "tjDecodeYUVPlanes";
2558
0
  int retval = 0;
2559
2560
0
  GET_TJINSTANCE(handle, -1);
2561
2562
0
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
2563
0
    THROW("Invalid argument");
2564
2565
0
  this->subsamp = subsamp;
2566
0
  processFlags(handle, flags, DECOMPRESS);
2567
2568
0
  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
2569
0
                             height, pixelFormat);
2570
2571
0
bailout:
2572
0
  return retval;
2573
0
}
2574
2575
2576
/* TurboJPEG 3+ */
2577
DLLEXPORT int tj3DecodeYUV8(tjhandle handle, const unsigned char *srcBuf,
2578
                            int align, unsigned char *dstBuf, int width,
2579
                            int pitch, int height, int pixelFormat)
2580
2.40k
{
2581
2.40k
  static const char FUNCTION_NAME[] = "tj3DecodeYUV8";
2582
2.40k
  const unsigned char *srcPlanes[3];
2583
2.40k
  int pw0, ph0, strides[3], retval = -1;
2584
2585
2.40k
  GET_TJINSTANCE(handle, -1);
2586
2587
2.40k
  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || width <= 0 ||
2588
2.40k
      height <= 0)
2589
2.40k
    THROW("Invalid argument");
2590
2591
2.40k
  if (this->subsamp == TJSAMP_UNKNOWN)
2592
2.40k
    THROW("TJPARAM_SUBSAMP must be specified");
2593
2594
2.40k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2595
2.40k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2596
2.40k
  srcPlanes[0] = srcBuf;
2597
2.40k
  strides[0] = PAD(pw0, align);
2598
2.40k
  if (this->subsamp == TJSAMP_GRAY) {
2599
890
    strides[1] = strides[2] = 0;
2600
890
    srcPlanes[1] = srcPlanes[2] = NULL;
2601
1.51k
  } else {
2602
1.51k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2603
1.51k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2604
2605
1.51k
    strides[1] = strides[2] = PAD(pw1, align);
2606
1.51k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2607
1.51k
        (unsigned long long)INT_MAX ||
2608
1.51k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2609
1.51k
        (unsigned long long)INT_MAX)
2610
1.51k
      THROW("Image or row alignment is too large");
2611
1.51k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
2612
1.51k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
2613
1.51k
  }
2614
2615
2.40k
  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
2616
2.40k
                             height, pixelFormat);
2617
2618
0
bailout:
2619
0
  return retval;
2620
2.40k
}
2621
2622
/* TurboJPEG 1.4+ */
2623
DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
2624
                          int align, int subsamp, unsigned char *dstBuf,
2625
                          int width, int pitch, int height, int pixelFormat,
2626
                          int flags)
2627
0
{
2628
0
  static const char FUNCTION_NAME[] = "tjDecodeYUV";
2629
0
  int retval = -1;
2630
2631
0
  GET_TJINSTANCE(handle, -1);
2632
2633
0
  if (subsamp < 0 || subsamp >= TJ_NUMSAMP)
2634
0
    THROW("Invalid argument");
2635
2636
0
  this->subsamp = subsamp;
2637
0
  processFlags(handle, flags, DECOMPRESS);
2638
2639
0
  return tj3DecodeYUV8(handle, srcBuf, align, dstBuf, width, pitch, height,
2640
0
                       pixelFormat);
2641
2642
0
bailout:
2643
0
  return retval;
2644
0
}
2645
2646
2647
/******************************** Transformer ********************************/
2648
2649
/* TurboJPEG 1.2+ */
2650
DLLEXPORT tjhandle tjInitTransform(void)
2651
0
{
2652
0
  return tj3Init(TJINIT_TRANSFORM);
2653
0
}
2654
2655
2656
/* TurboJPEG 3+ */
2657
DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
2658
                           size_t jpegSize, int n, unsigned char **dstBufs,
2659
                           size_t *dstSizes, const tjtransform *t)
2660
0
{
2661
0
  static const char FUNCTION_NAME[] = "tj3Transform";
2662
0
  int retval = 0;
2663
2664
0
#if TRANSFORMS_SUPPORTED
2665
2666
0
  jpeg_transform_info *xinfo = NULL;
2667
0
  jvirt_barray_ptr *srccoefs, *dstcoefs;
2668
0
  int i, saveMarkers = 0, srcSubsamp;
2669
0
  boolean alloc = TRUE;
2670
0
  struct my_progress_mgr progress;
2671
2672
0
  GET_INSTANCE(handle);
2673
0
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2674
0
    THROW("Instance has not been initialized for transformation");
2675
2676
0
  if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
2677
0
      dstSizes == NULL || t == NULL)
2678
0
    THROW("Invalid argument");
2679
2680
0
  if (this->scanLimit) {
2681
0
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2682
0
    progress.pub.progress_monitor = my_progress_monitor;
2683
0
    progress.this = this;
2684
0
    dinfo->progress = &progress.pub;
2685
0
  } else
2686
0
    dinfo->progress = NULL;
2687
2688
0
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2689
2690
0
  if ((xinfo =
2691
0
       (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
2692
0
    THROW("Memory allocation failure");
2693
0
  memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
2694
2695
0
  CATCH_LIBJPEG(this);
2696
2697
0
  if (dinfo->global_state <= DSTATE_INHEADER)
2698
0
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2699
2700
0
  for (i = 0; i < n; i++) {
2701
0
    if (t[i].op < 0 || t[i].op >= TJ_NUMXOP)
2702
0
      THROW("Invalid transform operation");
2703
0
    xinfo[i].transform = xformtypes[t[i].op];
2704
0
    xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
2705
0
    xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
2706
0
    xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
2707
0
    xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
2708
0
    if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
2709
0
    else xinfo[i].slow_hflip = 0;
2710
2711
0
    if (xinfo[i].crop) {
2712
0
      if (t[i].r.x < 0 || t[i].r.y < 0 || t[i].r.w < 0 || t[i].r.h < 0)
2713
0
        THROW("Invalid cropping region");
2714
0
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
2715
0
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
2716
0
      if (t[i].r.w != 0) {
2717
0
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
2718
0
      } else
2719
0
        xinfo[i].crop_width = JCROP_UNSET;
2720
0
      if (t[i].r.h != 0) {
2721
0
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
2722
0
      } else
2723
0
        xinfo[i].crop_height = JCROP_UNSET;
2724
0
    }
2725
0
    if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
2726
0
  }
2727
2728
0
  jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
2729
0
  if (dinfo->global_state <= DSTATE_INHEADER)
2730
0
    jpeg_read_header(dinfo, TRUE);
2731
0
  if (this->maxPixels &&
2732
0
      (unsigned long long)dinfo->image_width * dinfo->image_height >
2733
0
      (unsigned long long)this->maxPixels)
2734
0
    THROW("Image is too large");
2735
0
  srcSubsamp = getSubsamp(&this->dinfo);
2736
2737
0
  for (i = 0; i < n; i++) {
2738
0
    if (!jtransform_request_workspace(dinfo, &xinfo[i]))
2739
0
      THROW("Transform is not perfect");
2740
2741
0
    if (xinfo[i].crop) {
2742
0
      int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2743
2744
0
      if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2745
0
          t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2746
0
        if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2747
0
        else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2748
0
        else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2749
0
        else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2750
0
      }
2751
0
      if (dstSubsamp == TJSAMP_UNKNOWN)
2752
0
        THROW("Could not determine subsampling level of destination image");
2753
0
      if ((t[i].r.x % tjMCUWidth[dstSubsamp]) != 0 ||
2754
0
          (t[i].r.y % tjMCUHeight[dstSubsamp]) != 0)
2755
0
        THROWI("To crop this JPEG image, x must be a multiple of %d\n"
2756
0
               "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
2757
0
               tjMCUHeight[dstSubsamp]);
2758
0
    }
2759
0
  }
2760
2761
0
  srccoefs = jpeg_read_coefficients(dinfo);
2762
2763
0
  for (i = 0; i < n; i++) {
2764
0
    JDIMENSION dstWidth = dinfo->image_width, dstHeight = dinfo->image_height;
2765
2766
0
    if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2767
0
        t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2768
0
      dstWidth = dinfo->image_height;  dstHeight = dinfo->image_width;
2769
0
    }
2770
2771
0
    if (xinfo[i].crop) {
2772
0
      if ((JDIMENSION)t[i].r.x >= dstWidth ||
2773
0
          t[i].r.x + xinfo[i].crop_width > dstWidth ||
2774
0
          (JDIMENSION)t[i].r.y >= dstHeight ||
2775
0
          t[i].r.y + xinfo[i].crop_height > dstHeight)
2776
0
        THROW("The cropping region exceeds the destination image dimensions");
2777
0
      dstWidth = xinfo[i].crop_width;  dstHeight = xinfo[i].crop_height;
2778
0
    }
2779
0
    if (this->noRealloc) {
2780
0
      int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2781
2782
0
      if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2783
0
          t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2784
0
        if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2785
0
        else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2786
0
        else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2787
0
        else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2788
0
      }
2789
0
      if (dstSubsamp == TJSAMP_UNKNOWN)
2790
0
        THROW("Could not determine subsampling level of destination image");
2791
0
      alloc = FALSE;
2792
0
      dstSizes[i] = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
2793
0
    }
2794
0
    if (!(t[i].options & TJXOPT_NOOUTPUT))
2795
0
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2796
0
    jpeg_copy_critical_parameters(dinfo, cinfo);
2797
0
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
2798
0
    if (this->optimize || t[i].options & TJXOPT_OPTIMIZE)
2799
0
      cinfo->optimize_coding = TRUE;
2800
0
#ifdef C_PROGRESSIVE_SUPPORTED
2801
0
    if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE)
2802
0
      jpeg_simple_progression(cinfo);
2803
0
#endif
2804
0
    if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) {
2805
0
      cinfo->arith_code = TRUE;
2806
0
      cinfo->optimize_coding = FALSE;
2807
0
    }
2808
0
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
2809
0
      jpeg_write_coefficients(cinfo, dstcoefs);
2810
0
      jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
2811
0
                                          JCOPYOPT_NONE : JCOPYOPT_ALL);
2812
0
    } else
2813
0
      jinit_c_master_control(cinfo, TRUE);
2814
0
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
2815
0
    if (t[i].customFilter) {
2816
0
      int ci, y;
2817
0
      JDIMENSION by;
2818
2819
0
      for (ci = 0; ci < cinfo->num_components; ci++) {
2820
0
        jpeg_component_info *compptr = &cinfo->comp_info[ci];
2821
0
        tjregion arrayRegion = { 0, 0, 0, 0 };
2822
0
        tjregion planeRegion = { 0, 0, 0, 0 };
2823
2824
0
        arrayRegion.w = compptr->width_in_blocks * DCTSIZE;
2825
0
        arrayRegion.h = DCTSIZE;
2826
0
        planeRegion.w = compptr->width_in_blocks * DCTSIZE;
2827
0
        planeRegion.h = compptr->height_in_blocks * DCTSIZE;
2828
2829
0
        for (by = 0; by < compptr->height_in_blocks;
2830
0
             by += compptr->v_samp_factor) {
2831
0
          JBLOCKARRAY barray = (dinfo->mem->access_virt_barray)
2832
0
            ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2833
0
             TRUE);
2834
2835
0
          for (y = 0; y < compptr->v_samp_factor; y++) {
2836
0
            if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
2837
0
                                  i, (tjtransform *)&t[i]) == -1)
2838
0
              THROW("Error in custom filter");
2839
0
            arrayRegion.y += DCTSIZE;
2840
0
          }
2841
0
        }
2842
0
      }
2843
0
    }
2844
0
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2845
0
  }
2846
2847
0
  jpeg_finish_decompress(dinfo);
2848
2849
0
bailout:
2850
0
  if (cinfo->global_state > CSTATE_START) {
2851
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
2852
0
    jpeg_abort_compress(cinfo);
2853
0
  }
2854
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2855
0
  free(xinfo);
2856
0
  if (this->jerr.warning) retval = -1;
2857
0
  return retval;
2858
2859
#else /* TRANSFORMS_SUPPORTED */
2860
2861
  GET_TJINSTANCE(handle, -1)
2862
  THROW("Lossless transformations were disabled at build time")
2863
bailout:
2864
  return retval;
2865
2866
#endif
2867
0
}
2868
2869
/* TurboJPEG 1.2+ */
2870
DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
2871
                          unsigned long jpegSize, int n,
2872
                          unsigned char **dstBufs, unsigned long *dstSizes,
2873
                          tjtransform *t, int flags)
2874
0
{
2875
0
  static const char FUNCTION_NAME[] = "tjTransform";
2876
0
  int i, retval = 0;
2877
0
  size_t *sizes = NULL;
2878
2879
0
  GET_TJINSTANCE(handle, -1);
2880
0
  if ((this->init & DECOMPRESS) == 0)
2881
0
    THROW("Instance has not been initialized for decompression");
2882
2883
0
  if (n < 1 || dstSizes == NULL)
2884
0
    THROW("Invalid argument");
2885
2886
0
  if ((sizes = (size_t *)malloc(n * sizeof(size_t))) == NULL)
2887
0
    THROW("Memory allocation failure");
2888
0
  for (i = 0; i < n; i++)
2889
0
    sizes[i] = (size_t)dstSizes[i];
2890
0
  retval = tj3Transform(handle, jpegBuf, (size_t)jpegSize, n, dstBufs, sizes,
2891
0
                        t);
2892
0
  for (i = 0; i < n; i++)
2893
0
    dstSizes[i] = (unsigned long)sizes[i];
2894
2895
0
bailout:
2896
0
  free(sizes);
2897
0
  return retval;
2898
0
}
2899
2900
2901
/*************************** Packed-Pixel Image I/O **************************/
2902
2903
/* tj3LoadImage*() is implemented in turbojpeg-mp.c */
2904
2905
/* TurboJPEG 2.0+ */
2906
DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
2907
                                     int align, int *height,
2908
                                     int *pixelFormat, int flags)
2909
0
{
2910
0
  tjhandle handle = NULL;
2911
0
  unsigned char *dstBuf = NULL;
2912
2913
0
  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) return NULL;
2914
2915
0
  processFlags(handle, flags, COMPRESS);
2916
2917
0
  dstBuf = tj3LoadImage8(handle, filename, width, align, height, pixelFormat);
2918
2919
0
  tj3Destroy(handle);
2920
0
  return dstBuf;
2921
0
}
2922
2923
2924
/* tj3SaveImage*() is implemented in turbojpeg-mp.c */
2925
2926
/* TurboJPEG 2.0+ */
2927
DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
2928
                          int width, int pitch, int height, int pixelFormat,
2929
                          int flags)
2930
0
{
2931
0
  tjhandle handle = NULL;
2932
0
  int retval = -1;
2933
2934
0
  if ((handle = tj3Init(TJINIT_DECOMPRESS)) == NULL) return -1;
2935
2936
0
  processFlags(handle, flags, DECOMPRESS);
2937
2938
0
  retval = tj3SaveImage8(handle, filename, buffer, width, pitch, height,
2939
0
                         pixelFormat);
2940
2941
0
  tj3Destroy(handle);
2942
0
  return retval;
2943
0
}