Coverage Report

Created: 2025-07-01 06:27

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