Coverage Report

Created: 2026-02-26 07:10

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