Coverage Report

Created: 2025-10-10 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjpeg-turbo.3.0.x/turbojpeg.c
Line
Count
Source
1
/*
2
 * Copyright (C)2009-2025 D. R. Commander.  All Rights Reserved.
3
 * Copyright (C)2021 Alex Richardson.  All Rights Reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * - Redistributions of source code must retain the above copyright notice,
9
 *   this list of conditions and the following disclaimer.
10
 * - Redistributions in binary form must reproduce the above copyright notice,
11
 *   this list of conditions and the following disclaimer in the documentation
12
 *   and/or other materials provided with the distribution.
13
 * - Neither the name of the libjpeg-turbo Project nor the names of its
14
 *   contributors may be used to endorse or promote products derived from this
15
 *   software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
18
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
21
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
 * POSSIBILITY OF SUCH DAMAGE.
28
 */
29
30
/* TurboJPEG/LJT:  this implements the TurboJPEG API using libjpeg or
31
   libjpeg-turbo */
32
33
#include <ctype.h>
34
#include <limits.h>
35
#if !defined(_MSC_VER) || _MSC_VER > 1600
36
#include <stdint.h>
37
#endif
38
#include "jinclude.h"
39
#define JPEG_INTERNALS
40
#include "jpeglib.h"
41
#include "jerror.h"
42
#include <setjmp.h>
43
#include <errno.h>
44
#include "turbojpeg.h"
45
#include "tjutil.h"
46
#include "transupp.h"
47
#include "jpegapicomp.h"
48
#include "cdjpeg.h"
49
50
extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, size_t *,
51
                             boolean);
52
extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *, size_t);
53
54
1.87M
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
55
212k
#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
215k
{
78
215k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
79
80
215k
  (*cinfo->err->output_message) (cinfo);
81
215k
  longjmp(myerr->setjmp_buffer, 1);
82
215k
}
83
84
/* Based on output_message() in jerror.c */
85
86
static void my_output_message(j_common_ptr cinfo)
87
311k
{
88
311k
  (*cinfo->err->format_message) (cinfo, errStr);
89
311k
}
90
91
static void my_emit_message(j_common_ptr cinfo, int msg_level)
92
604M
{
93
604M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
94
95
604M
  myerr->emit_message(cinfo, msg_level);
96
604M
  if (msg_level < 0) {
97
408M
    myerr->warning = TRUE;
98
408M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
99
408M
  }
100
604M
}
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
342M
{
154
342M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
155
342M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
156
157
342M
  if (dinfo->is_decompressor) {
158
342M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
159
160
342M
    if (scan_no > myprog->this->scanLimit) {
161
71
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
162
71
               "Progressive JPEG image has more than %d scans",
163
71
               myprog->this->scanLimit);
164
71
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
165
71
               "Progressive JPEG image has more than %d scans",
166
71
               myprog->this->scanLimit);
167
71
      myprog->this->isInstanceError = TRUE;
168
71
      myerr->warning = FALSE;
169
71
      longjmp(myerr->setjmp_buffer, 1);
170
71
    }
171
342M
  }
172
342M
}
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
316k
#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
15.4k
  tjinstance *this = (tjinstance *)handle; \
265
15.4k
  j_compress_ptr cinfo = NULL; \
266
15.4k
  j_decompress_ptr dinfo = NULL; \
267
15.4k
  \
268
15.4k
  if (!this) { \
269
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
270
0
    return -1; \
271
0
  } \
272
15.4k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
273
15.4k
  this->jerr.warning = FALSE; \
274
15.4k
  this->isInstanceError = FALSE;
275
276
#define GET_CINSTANCE(handle) \
277
82.2k
  tjinstance *this = (tjinstance *)handle; \
278
82.2k
  j_compress_ptr cinfo = NULL; \
279
82.2k
  \
280
82.2k
  if (!this) { \
281
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
282
0
    return -1; \
283
0
  } \
284
82.2k
  cinfo = &this->cinfo; \
285
82.2k
  this->jerr.warning = FALSE; \
286
82.2k
  this->isInstanceError = FALSE;
287
288
#define GET_DINSTANCE(handle) \
289
73.4k
  tjinstance *this = (tjinstance *)handle; \
290
73.4k
  j_decompress_ptr dinfo = NULL; \
291
73.4k
  \
292
73.4k
  if (!this) { \
293
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
294
0
    return -1; \
295
0
  } \
296
73.4k
  dinfo = &this->dinfo; \
297
73.4k
  this->jerr.warning = FALSE; \
298
73.4k
  this->isInstanceError = FALSE;
299
300
#define GET_TJINSTANCE(handle, errorReturn) \
301
1.06M
  tjinstance *this = (tjinstance *)handle; \
302
1.06M
  \
303
1.06M
  if (!this) { \
304
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
305
0
    return errorReturn; \
306
0
  } \
307
1.06M
  this->jerr.warning = FALSE; \
308
1.06M
  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
180k
{
331
180k
  int subsamp = this->subsamp;
332
333
180k
  this->cinfo.in_color_space = pf2cs[pixelFormat];
334
180k
  this->cinfo.input_components = tjPixelSize[pixelFormat];
335
180k
  jpeg_set_defaults(&this->cinfo);
336
337
180k
  this->cinfo.restart_interval = this->restartIntervalBlocks;
338
180k
  this->cinfo.restart_in_rows = this->restartIntervalRows;
339
180k
  this->cinfo.X_density = (UINT16)this->xDensity;
340
180k
  this->cinfo.Y_density = (UINT16)this->yDensity;
341
180k
  this->cinfo.density_unit = (UINT8)this->densityUnits;
342
180k
  this->cinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
343
344
180k
  if (this->lossless) {
345
37.0k
#ifdef C_LOSSLESS_SUPPORTED
346
37.0k
    jpeg_enable_lossless(&this->cinfo, this->losslessPSV, this->losslessPt);
347
37.0k
#endif
348
37.0k
    if (pixelFormat == TJPF_GRAY)
349
4.56k
      subsamp = TJSAMP_GRAY;
350
32.4k
    else if (subsamp != TJSAMP_GRAY)
351
32.4k
      subsamp = TJSAMP_444;
352
37.0k
    return;
353
37.0k
  }
354
355
143k
  jpeg_set_quality(&this->cinfo, this->quality, TRUE);
356
143k
  this->cinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
357
358
143k
  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
143k
  default:
370
143k
    if (subsamp == TJSAMP_GRAY)
371
41.4k
      jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);
372
101k
    else if (pixelFormat == TJPF_CMYK)
373
11.5k
      jpeg_set_colorspace(&this->cinfo, JCS_YCCK);
374
90.3k
    else
375
90.3k
      jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);
376
143k
  }
377
378
143k
  if (this->cinfo.data_precision == 8)
379
104k
    this->cinfo.optimize_coding = this->optimize;
380
143k
#ifdef C_PROGRESSIVE_SUPPORTED
381
143k
  if (this->progressive) jpeg_simple_progression(&this->cinfo);
382
143k
#endif
383
143k
  this->cinfo.arith_code = this->arithmetic;
384
385
143k
  this->cinfo.comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
386
143k
  this->cinfo.comp_info[1].h_samp_factor = 1;
387
143k
  this->cinfo.comp_info[2].h_samp_factor = 1;
388
143k
  if (this->cinfo.num_components > 3)
389
11.5k
    this->cinfo.comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
390
143k
  this->cinfo.comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
391
143k
  this->cinfo.comp_info[1].v_samp_factor = 1;
392
143k
  this->cinfo.comp_info[2].v_samp_factor = 1;
393
143k
  if (this->cinfo.num_components > 3)
394
11.5k
    this->cinfo.comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
395
143k
}
396
397
398
static int getSubsamp(j_decompress_ptr dinfo)
399
141k
{
400
141k
  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
141k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
407
74.4k
    return TJSAMP_GRAY;
408
409
353k
  for (i = 0; i < TJ_NUMSAMP; i++) {
410
324k
    if (i == TJSAMP_GRAY) continue;
411
412
288k
    if (dinfo->num_components == 3 ||
413
30.4k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
414
29.2k
          dinfo->jpeg_color_space == JCS_CMYK) &&
415
281k
         dinfo->num_components == 4)) {
416
281k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
417
120k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
418
57.5k
        int match = 0;
419
420
177k
        for (k = 1; k < dinfo->num_components; k++) {
421
119k
          int href = 1, vref = 1;
422
423
119k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
424
118k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
425
4.48k
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
426
4.48k
          }
427
119k
          if (dinfo->comp_info[k].h_samp_factor == href &&
428
97.1k
              dinfo->comp_info[k].v_samp_factor == vref)
429
83.6k
            match++;
430
119k
        }
431
57.5k
        if (match == dinfo->num_components - 1) {
432
34.8k
          retval = i;  break;
433
34.8k
        }
434
57.5k
      }
435
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
436
         in non-standard ways. */
437
246k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
438
142k
          dinfo->comp_info[0].v_samp_factor == 2 &&
439
76.0k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
440
34.7k
        int match = 0;
441
442
104k
        for (k = 1; k < dinfo->num_components; k++) {
443
70.0k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
444
445
70.0k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
446
69.6k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
447
568
            href = vref = 2;
448
568
          }
449
70.0k
          if (dinfo->comp_info[k].h_samp_factor == href &&
450
57.1k
              dinfo->comp_info[k].v_samp_factor == vref)
451
9.35k
            match++;
452
70.0k
        }
453
34.7k
        if (match == dinfo->num_components - 1) {
454
3.52k
          retval = i;  break;
455
3.52k
        }
456
34.7k
      }
457
      /* Handle 4:4:4 images whose sampling factors are specified in
458
         non-standard ways. */
459
243k
      if (dinfo->comp_info[0].h_samp_factor *
460
243k
          dinfo->comp_info[0].v_samp_factor <=
461
243k
          D_MAX_BLOCKS_IN_MCU / 3 && i == TJSAMP_444) {
462
20.9k
        int match = 0;
463
62.7k
        for (k = 1; k < dinfo->num_components; k++) {
464
43.7k
          if (dinfo->comp_info[k].h_samp_factor ==
465
43.7k
              dinfo->comp_info[0].h_samp_factor &&
466
15.4k
              dinfo->comp_info[k].v_samp_factor ==
467
15.4k
              dinfo->comp_info[0].v_samp_factor)
468
8.50k
            match++;
469
43.7k
          if (match == dinfo->num_components - 1) {
470
1.98k
            retval = i;  break;
471
1.98k
          }
472
43.7k
        }
473
20.9k
      }
474
243k
    }
475
288k
  }
476
67.1k
  return retval;
477
141k
}
478
479
480
static void setDecompParameters(tjinstance *this)
481
95.4k
{
482
95.4k
  this->subsamp = getSubsamp(&this->dinfo);
483
95.4k
  this->jpegWidth = this->dinfo.image_width;
484
95.4k
  this->jpegHeight = this->dinfo.image_height;
485
95.4k
  this->precision = this->dinfo.data_precision;
486
95.4k
  switch (this->dinfo.jpeg_color_space) {
487
44.5k
  case JCS_GRAYSCALE:  this->colorspace = TJCS_GRAY;  break;
488
20.2k
  case JCS_RGB:        this->colorspace = TJCS_RGB;  break;
489
29.0k
  case JCS_YCbCr:      this->colorspace = TJCS_YCbCr;  break;
490
1.13k
  case JCS_CMYK:       this->colorspace = TJCS_CMYK;  break;
491
133
  case JCS_YCCK:       this->colorspace = TJCS_YCCK;  break;
492
332
  default:             this->colorspace = -1;  break;
493
95.4k
  }
494
95.4k
  this->progressive = this->dinfo.progressive_mode;
495
95.4k
  this->arithmetic = this->dinfo.arith_code;
496
95.4k
  this->lossless = this->dinfo.master->lossless;
497
95.4k
  this->losslessPSV = this->dinfo.Ss;
498
95.4k
  this->losslessPt = this->dinfo.Al;
499
95.4k
  this->xDensity = this->dinfo.X_density;
500
95.4k
  this->yDensity = this->dinfo.Y_density;
501
95.4k
  this->densityUnits = this->dinfo.density_unit;
502
95.4k
}
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
417k
{
540
417k
  static const char FUNCTION_NAME[] = "tj3Init";
541
417k
  tjinstance *this = NULL;
542
417k
  tjhandle retval = NULL;
543
544
417k
  if (initType < 0 || initType >= TJ_NUMINIT)
545
417k
    THROWG("Invalid argument", NULL);
546
547
417k
  if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL)
548
417k
    THROWG("Memory allocation failure", NULL);
549
417k
  memset(this, 0, sizeof(tjinstance));
550
417k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
551
552
417k
  this->quality = -1;
553
417k
  this->subsamp = TJSAMP_UNKNOWN;
554
417k
  this->jpegWidth = -1;
555
417k
  this->jpegHeight = -1;
556
417k
  this->precision = 8;
557
417k
  this->colorspace = -1;
558
417k
  this->losslessPSV = 1;
559
417k
  this->xDensity = 1;
560
417k
  this->yDensity = 1;
561
417k
  this->scalingFactor = TJUNSCALED;
562
563
417k
  switch (initType) {
564
364k
  case TJINIT_COMPRESS:  return _tjInitCompress(this);
565
37.3k
  case TJINIT_DECOMPRESS:  return _tjInitDecompress(this);
566
15.6k
  case TJINIT_TRANSFORM:
567
15.6k
    retval = _tjInitCompress(this);
568
15.6k
    if (!retval) return NULL;
569
15.6k
    retval = _tjInitDecompress(this);
570
15.6k
    return retval;
571
417k
  }
572
573
0
bailout:
574
0
  return retval;
575
417k
}
576
577
578
/* TurboJPEG 3+ */
579
DLLEXPORT void tj3Destroy(tjhandle handle)
580
417k
{
581
417k
  tjinstance *this = (tjinstance *)handle;
582
417k
  j_compress_ptr cinfo = NULL;
583
417k
  j_decompress_ptr dinfo = NULL;
584
585
417k
  if (!this) return;
586
587
417k
  cinfo = &this->cinfo;  dinfo = &this->dinfo;
588
417k
  this->jerr.warning = FALSE;
589
417k
  this->isInstanceError = FALSE;
590
591
417k
  if (setjmp(this->jerr.setjmp_buffer)) return;
592
417k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
593
417k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
594
417k
  free(this);
595
417k
}
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
324k
#define SET_PARAM(field, minValue, maxValue) { \
656
324k
  if (value < minValue || (maxValue > 0 && value > maxValue)) \
657
324k
    THROW("Parameter value out of range"); \
658
324k
  this->field = value; \
659
324k
}
660
661
527k
#define SET_BOOL_PARAM(field) { \
662
527k
  if (value < 0 || value > 1) \
663
527k
    THROW("Parameter value out of range"); \
664
527k
  this->field = (boolean)value; \
665
527k
}
666
667
/* TurboJPEG 3+ */
668
DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
669
851k
{
670
851k
  static const char FUNCTION_NAME[] = "tj3Set";
671
851k
  int retval = 0;
672
673
851k
  GET_TJINSTANCE(handle, -1);
674
675
851k
  switch (param) {
676
0
  case TJPARAM_STOPONWARNING:
677
0
    SET_BOOL_PARAM(jerr.stopOnWarning);
678
0
    break;
679
117k
  case TJPARAM_BOTTOMUP:
680
117k
    SET_BOOL_PARAM(bottomUp);
681
117k
    break;
682
113k
  case TJPARAM_NOREALLOC:
683
113k
    if (!(this->init & COMPRESS))
684
113k
      THROW("TJPARAM_NOREALLOC is not applicable to decompression instances.");
685
113k
    SET_BOOL_PARAM(noRealloc);
686
113k
    break;
687
37.3k
  case TJPARAM_QUALITY:
688
37.3k
    if (!(this->init & COMPRESS))
689
37.3k
      THROW("TJPARAM_QUALITY is not applicable to decompression instances.");
690
37.3k
    SET_PARAM(quality, 1, 100);
691
37.3k
    break;
692
37.3k
  case TJPARAM_SUBSAMP:
693
37.3k
    SET_PARAM(subsamp, 0, TJ_NUMSAMP - 1);
694
37.3k
    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.4k
  case TJPARAM_FASTUPSAMPLE:
716
11.4k
    if (!(this->init & DECOMPRESS))
717
11.4k
      THROW("TJPARAM_FASTUPSAMPLE is not applicable to compression instances.");
718
11.4k
    SET_BOOL_PARAM(fastUpsample);
719
11.4k
    break;
720
76.9k
  case TJPARAM_FASTDCT:
721
76.9k
    SET_BOOL_PARAM(fastDCT);
722
76.9k
    break;
723
52.3k
  case TJPARAM_OPTIMIZE:
724
52.3k
    if (!(this->init & COMPRESS))
725
52.3k
      THROW("TJPARAM_OPTIMIZE is not applicable to decompression instances.");
726
52.3k
    SET_BOOL_PARAM(optimize);
727
52.3k
    break;
728
72.0k
  case TJPARAM_PROGRESSIVE:
729
72.0k
    if (!(this->init & COMPRESS))
730
72.0k
      THROW("TJPARAM_PROGRESSIVE is read-only in decompression instances.");
731
72.0k
    SET_BOOL_PARAM(progressive);
732
72.0k
    break;
733
13.3k
  case TJPARAM_SCANLIMIT:
734
13.3k
    if (!(this->init & DECOMPRESS))
735
13.3k
      THROW("TJPARAM_SCANLIMIT is not applicable to compression instances.");
736
13.3k
    SET_PARAM(scanLimit, 0, -1);
737
13.3k
    break;
738
72.0k
  case TJPARAM_ARITHMETIC:
739
72.0k
    if (!(this->init & COMPRESS))
740
72.0k
      THROW("TJPARAM_ARITHMETIC is read-only in decompression instances.");
741
72.0k
    SET_BOOL_PARAM(arithmetic);
742
72.0k
    break;
743
12.5k
  case TJPARAM_LOSSLESS:
744
12.5k
    if (!(this->init & COMPRESS))
745
12.5k
      THROW("TJPARAM_LOSSLESS is read-only in decompression instances.");
746
12.5k
    SET_BOOL_PARAM(lossless);
747
12.5k
    break;
748
12.5k
  case TJPARAM_LOSSLESSPSV:
749
12.5k
    if (!(this->init & COMPRESS))
750
12.5k
      THROW("TJPARAM_LOSSLESSPSV is read-only in decompression instances.");
751
12.5k
    SET_PARAM(losslessPSV, 1, 7);
752
12.5k
    break;
753
12.5k
  case TJPARAM_LOSSLESSPT:
754
12.5k
    if (!(this->init & COMPRESS))
755
12.5k
      THROW("TJPARAM_LOSSLESSPT is read-only in decompression instances.");
756
12.5k
    SET_PARAM(losslessPt, 0, 15);
757
12.5k
    break;
758
20.9k
  case TJPARAM_RESTARTBLOCKS:
759
20.9k
    if (!(this->init & COMPRESS))
760
20.9k
      THROW("TJPARAM_RESTARTBLOCKS is not applicable to decompression instances.");
761
20.9k
    SET_PARAM(restartIntervalBlocks, 0, 65535);
762
20.9k
    if (value != 0) this->restartIntervalRows = 0;
763
20.9k
    break;
764
84.6k
  case TJPARAM_RESTARTROWS:
765
84.6k
    if (!(this->init & COMPRESS))
766
84.6k
      THROW("TJPARAM_RESTARTROWS is not applicable to decompression instances.");
767
84.6k
    SET_PARAM(restartIntervalRows, 0, 65535);
768
84.6k
    if (value != 0) this->restartIntervalBlocks = 0;
769
84.6k
    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
105k
  case TJPARAM_MAXPIXELS:
789
105k
    SET_PARAM(maxPixels, 0, -1);
790
105k
    break;
791
0
  default:
792
0
    THROW("Invalid parameter");
793
851k
  }
794
795
851k
bailout:
796
851k
  return retval;
797
851k
}
798
799
800
/* TurboJPEG 3+ */
801
DLLEXPORT int tj3Get(tjhandle handle, int param)
802
102k
{
803
102k
  tjinstance *this = (tjinstance *)handle;
804
102k
  if (!this) return -1;
805
806
102k
  switch (param) {
807
0
  case TJPARAM_STOPONWARNING:
808
0
    return this->jerr.stopOnWarning;
809
0
  case TJPARAM_BOTTOMUP:
810
0
    return this->bottomUp;
811
38.9k
  case TJPARAM_NOREALLOC:
812
38.9k
    return this->noRealloc;
813
0
  case TJPARAM_QUALITY:
814
0
    return this->quality;
815
10.6k
  case TJPARAM_SUBSAMP:
816
10.6k
    return this->subsamp;
817
17.1k
  case TJPARAM_JPEGWIDTH:
818
17.1k
    return this->jpegWidth;
819
17.1k
  case TJPARAM_JPEGHEIGHT:
820
17.1k
    return this->jpegHeight;
821
6.46k
  case TJPARAM_PRECISION:
822
6.46k
    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
12.6k
  case TJPARAM_LOSSLESS:
838
12.6k
    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
102k
  }
858
859
0
  return -1;
860
102k
}
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
219k
{
871
219k
  return MALLOC(bytes);
872
219k
}
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
194k
{
884
194k
  free(buf);
885
194k
}
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
244k
{
897
244k
  static const char FUNCTION_NAME[] = "tj3JPEGBufSize";
898
244k
  unsigned long long retval = 0;
899
244k
  int mcuw, mcuh, chromasf;
900
901
244k
  if (width < 1 || height < 1 || jpegSubsamp < TJSAMP_UNKNOWN ||
902
244k
      jpegSubsamp >= TJ_NUMSAMP)
903
244k
    THROWG("Invalid argument", 0);
904
905
244k
  if (jpegSubsamp == TJSAMP_UNKNOWN)
906
12.9k
    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
244k
  mcuw = tjMCUWidth[jpegSubsamp];
912
244k
  mcuh = tjMCUHeight[jpegSubsamp];
913
244k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
914
244k
  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
244k
bailout:
921
244k
  return (size_t)retval;
922
244k
}
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
47.4k
{
965
47.4k
  static const char FUNCTION_NAME[] = "tj3YUVBufSize";
966
47.4k
  unsigned long long retval = 0;
967
47.4k
  int nc, i;
968
969
47.4k
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
970
47.2k
    THROWG("Invalid argument", 0);
971
972
47.2k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
973
154k
  for (i = 0; i < nc; i++) {
974
107k
    int pw = tj3YUVPlaneWidth(i, width, subsamp);
975
107k
    int stride = PAD(pw, align);
976
107k
    int ph = tj3YUVPlaneHeight(i, height, subsamp);
977
978
107k
    if (pw == 0 || ph == 0) return 0;
979
107k
    else retval += (unsigned long long)stride * ph;
980
107k
  }
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
47.4k
bailout:
987
47.4k
  return (size_t)retval;
988
47.2k
}
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
273k
{
1051
273k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneWidth";
1052
273k
  unsigned long long pw, retval = 0;
1053
273k
  int nc;
1054
1055
273k
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1056
273k
    THROWG("Invalid argument", 0);
1057
273k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1058
273k
  if (componentID < 0 || componentID >= nc)
1059
273k
    THROWG("Invalid argument", 0);
1060
1061
273k
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
1062
273k
  if (componentID == 0)
1063
144k
    retval = pw;
1064
128k
  else
1065
128k
    retval = pw * 8 / tjMCUWidth[subsamp];
1066
1067
273k
  if (retval > (unsigned long long)INT_MAX)
1068
273k
    THROWG("Width is too large", 0);
1069
1070
273k
bailout:
1071
273k
  return (int)retval;
1072
273k
}
1073
1074
/* TurboJPEG 1.4+ */
1075
DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
1076
22.0k
{
1077
22.0k
  int retval = tj3YUVPlaneWidth(componentID, width, subsamp);
1078
22.0k
  return (retval == 0) ? -1 : retval;
1079
22.0k
}
1080
1081
1082
/* TurboJPEG 3+ */
1083
DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp)
1084
273k
{
1085
273k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneHeight";
1086
273k
  unsigned long long ph, retval = 0;
1087
273k
  int nc;
1088
1089
273k
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1090
273k
    THROWG("Invalid argument", 0);
1091
273k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1092
273k
  if (componentID < 0 || componentID >= nc)
1093
273k
    THROWG("Invalid argument", 0);
1094
1095
273k
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
1096
273k
  if (componentID == 0)
1097
144k
    retval = ph;
1098
128k
  else
1099
128k
    retval = ph * 8 / tjMCUHeight[subsamp];
1100
1101
273k
  if (retval > (unsigned long long)INT_MAX)
1102
273k
    THROWG("Height is too large", 0);
1103
1104
273k
bailout:
1105
273k
  return (int)retval;
1106
273k
}
1107
1108
/* TurboJPEG 1.4+ */
1109
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
1110
22.0k
{
1111
22.0k
  int retval = tj3YUVPlaneHeight(componentID, height, subsamp);
1112
22.0k
  return (retval == 0) ? -1 : retval;
1113
22.0k
}
1114
1115
1116
/******************************** Compressor *********************************/
1117
1118
static tjhandle _tjInitCompress(tjinstance *this)
1119
379k
{
1120
379k
  static unsigned char buffer[1];
1121
379k
  unsigned char *buf = buffer;
1122
379k
  size_t size = 1;
1123
1124
  /* This is also straight out of example.c */
1125
379k
  this->cinfo.err = jpeg_std_error(&this->jerr.pub);
1126
379k
  this->jerr.pub.error_exit = my_error_exit;
1127
379k
  this->jerr.pub.output_message = my_output_message;
1128
379k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1129
379k
  this->jerr.pub.emit_message = my_emit_message;
1130
379k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1131
379k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1132
379k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1133
1134
379k
  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
379k
  jpeg_create_compress(&this->cinfo);
1141
  /* Make an initial call so it will create the destination manager */
1142
379k
  jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
1143
1144
379k
  this->init |= COMPRESS;
1145
379k
  return (tjhandle)this;
1146
379k
}
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
64.1k
#define BITS_IN_JSAMPLE  8
1157
#include "turbojpeg-mp.c"
1158
#undef BITS_IN_JSAMPLE
1159
43.0k
#define BITS_IN_JSAMPLE  12
1160
#include "turbojpeg-mp.c"
1161
#undef BITS_IN_JSAMPLE
1162
13.0k
#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
10.9k
{
1226
10.9k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUVPlanes8";
1227
10.9k
  int i, row, retval = 0;
1228
10.9k
  boolean alloc = TRUE;
1229
10.9k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1230
10.9k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1231
10.9k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1232
10.9k
  JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1233
1234
10.9k
  GET_CINSTANCE(handle)
1235
1236
120k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1237
109k
    tmpbuf[i] = NULL;  inbuf[i] = NULL;
1238
109k
  }
1239
1240
10.9k
  if ((this->init & COMPRESS) == 0)
1241
10.9k
    THROW("Instance has not been initialized for compression");
1242
1243
10.9k
  if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
1244
10.9k
      jpegBuf == NULL || jpegSize == NULL)
1245
10.9k
    THROW("Invalid argument");
1246
10.9k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1247
10.9k
    THROW("Invalid argument");
1248
1249
10.9k
  if (this->quality == -1)
1250
10.9k
    THROW("TJPARAM_QUALITY must be specified");
1251
10.9k
  if (this->subsamp == TJSAMP_UNKNOWN)
1252
10.9k
    THROW("TJPARAM_SUBSAMP must be specified");
1253
1254
10.9k
  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
10.9k
  cinfo->image_width = width;
1260
10.9k
  cinfo->image_height = height;
1261
10.9k
  cinfo->data_precision = 8;
1262
1263
10.9k
  if (this->noRealloc) {
1264
10.9k
    alloc = FALSE;  *jpegSize = tj3JPEGBufSize(width, height, this->subsamp);
1265
10.9k
  }
1266
10.9k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1267
10.9k
  setCompDefaults(this, TJPF_RGB);
1268
10.9k
  cinfo->raw_data_in = TRUE;
1269
1270
10.9k
  jpeg_start_compress(cinfo, TRUE);
1271
36.7k
  for (i = 0; i < cinfo->num_components; i++) {
1272
25.8k
    jpeg_component_info *compptr = &cinfo->comp_info[i];
1273
25.8k
    int ih;
1274
1275
25.8k
    iw[i] = compptr->width_in_blocks * DCTSIZE;
1276
25.8k
    ih = compptr->height_in_blocks * DCTSIZE;
1277
25.8k
    pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
1278
25.8k
            compptr->h_samp_factor / cinfo->max_h_samp_factor;
1279
25.8k
    ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
1280
25.8k
            compptr->v_samp_factor / cinfo->max_v_samp_factor;
1281
25.8k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1282
25.8k
    th[i] = compptr->v_samp_factor * DCTSIZE;
1283
25.8k
    tmpbufsize += iw[i] * th[i];
1284
25.8k
    if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1285
25.8k
      THROW("Memory allocation failure");
1286
25.8k
    ptr = (JSAMPLE *)srcPlanes[i];
1287
78.1M
    for (row = 0; row < ph[i]; row++) {
1288
78.0M
      inbuf[i][row] = ptr;
1289
78.0M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1290
78.0M
    }
1291
25.8k
  }
1292
10.9k
  if (usetmpbuf) {
1293
10.8k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1294
10.8k
      THROW("Memory allocation failure");
1295
10.8k
    ptr = _tmpbuf;
1296
36.5k
    for (i = 0; i < cinfo->num_components; i++) {
1297
25.7k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1298
25.7k
        THROW("Memory allocation failure");
1299
246k
      for (row = 0; row < th[i]; row++) {
1300
220k
        tmpbuf[i][row] = ptr;
1301
220k
        ptr += iw[i];
1302
220k
      }
1303
25.7k
    }
1304
10.8k
  }
1305
1306
10.9k
  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
4.13M
  for (row = 0; row < (int)cinfo->image_height;
1312
4.12M
       row += cinfo->max_v_samp_factor * DCTSIZE) {
1313
4.12M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1314
4.12M
    int crow[MAX_COMPONENTS];
1315
1316
13.5M
    for (i = 0; i < cinfo->num_components; i++) {
1317
9.39M
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1318
1319
9.39M
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1320
9.39M
      if (usetmpbuf) {
1321
9.39M
        int j, k;
1322
1323
87.4M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1324
78.0M
          memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1325
          /* Duplicate last sample in row to fill out MCU */
1326
592M
          for (k = pw[i]; k < iw[i]; k++)
1327
514M
            tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1328
78.0M
        }
1329
        /* Duplicate last row to fill out MCU */
1330
9.53M
        for (j = ph[i] - crow[i]; j < th[i]; j++)
1331
137k
          memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1332
9.39M
        yuvptr[i] = tmpbuf[i];
1333
9.39M
      } else
1334
366
        yuvptr[i] = &inbuf[i][crow[i]];
1335
9.39M
    }
1336
4.12M
    jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1337
4.12M
  }
1338
10.9k
  jpeg_finish_compress(cinfo);
1339
1340
10.9k
bailout:
1341
10.9k
  if (cinfo->global_state > CSTATE_START && alloc)
1342
0
    (*cinfo->dest->term_destination) (cinfo);
1343
10.9k
  if (cinfo->global_state > CSTATE_START || retval == -1)
1344
0
    jpeg_abort_compress(cinfo);
1345
120k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1346
109k
    free(tmpbuf[i]);
1347
109k
    free(inbuf[i]);
1348
109k
  }
1349
10.9k
  free(_tmpbuf);
1350
10.9k
  if (this->jerr.warning) retval = -1;
1351
10.9k
  return retval;
1352
10.9k
}
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
32.3k
{
1393
32.3k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUV8";
1394
32.3k
  const unsigned char *srcPlanes[3];
1395
32.3k
  int pw0, ph0, strides[3], retval = -1;
1396
1397
32.3k
  GET_TJINSTANCE(handle, -1);
1398
1399
32.3k
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1400
32.3k
      height <= 0)
1401
32.3k
    THROW("Invalid argument");
1402
1403
32.3k
  if (this->subsamp == TJSAMP_UNKNOWN)
1404
32.3k
    THROW("TJPARAM_SUBSAMP must be specified");
1405
1406
32.3k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1407
32.3k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1408
32.3k
  srcPlanes[0] = srcBuf;
1409
32.3k
  strides[0] = PAD(pw0, align);
1410
32.3k
  if (this->subsamp == TJSAMP_GRAY) {
1411
10.2k
    strides[1] = strides[2] = 0;
1412
10.2k
    srcPlanes[1] = srcPlanes[2] = NULL;
1413
22.0k
  } else {
1414
22.0k
    int pw1 = tjPlaneWidth(1, width, this->subsamp);
1415
22.0k
    int ph1 = tjPlaneHeight(1, height, this->subsamp);
1416
1417
22.0k
    strides[1] = strides[2] = PAD(pw1, align);
1418
22.0k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1419
22.0k
        (unsigned long long)INT_MAX ||
1420
22.0k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1421
22.0k
        (unsigned long long)INT_MAX)
1422
22.0k
      THROW("Image or row alignment is too large");
1423
22.0k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1424
22.0k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1425
22.0k
  }
1426
1427
32.3k
  return tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
1428
32.3k
                                   jpegBuf, jpegSize);
1429
1430
0
bailout:
1431
0
  return retval;
1432
32.3k
}
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
32.4k
{
1470
32.4k
  static const char FUNCTION_NAME[] = "tj3EncodeYUVPlanes8";
1471
32.4k
  JSAMPROW *row_pointer = NULL;
1472
32.4k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
1473
32.4k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
1474
32.4k
  JSAMPROW *outbuf[MAX_COMPONENTS];
1475
32.4k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1476
32.4k
  JSAMPLE *ptr;
1477
32.4k
  jpeg_component_info *compptr;
1478
1479
32.4k
  GET_CINSTANCE(handle)
1480
1481
357k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1482
324k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
1483
324k
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
1484
324k
  }
1485
1486
32.4k
  if ((this->init & COMPRESS) == 0)
1487
32.4k
    THROW("Instance has not been initialized for compression");
1488
1489
32.4k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1490
32.4k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
1491
32.4k
      !dstPlanes[0])
1492
32.4k
    THROW("Invalid argument");
1493
32.4k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1494
32.4k
    THROW("Invalid argument");
1495
1496
32.4k
  if (this->subsamp == TJSAMP_UNKNOWN)
1497
32.4k
    THROW("TJPARAM_SUBSAMP must be specified");
1498
32.4k
  if (pixelFormat == TJPF_CMYK)
1499
32.4k
    THROW("Cannot generate YUV images from packed-pixel CMYK images");
1500
1501
32.4k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1502
1503
32.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
1504
    /* If we get here, the JPEG code has signaled an error. */
1505
161
    retval = -1;  goto bailout;
1506
161
  }
1507
1508
32.3k
  cinfo->image_width = width;
1509
32.3k
  cinfo->image_height = height;
1510
32.3k
  cinfo->data_precision = 8;
1511
1512
32.3k
  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
32.3k
  if (cinfo->global_state != CSTATE_START)
1519
32.3k
    THROW("libjpeg API is in the wrong state");
1520
32.3k
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
1521
32.3k
  jinit_c_master_control(cinfo, FALSE);
1522
32.3k
  jinit_color_converter(cinfo);
1523
32.3k
  jinit_downsampler(cinfo);
1524
32.3k
  (*cinfo->cconvert->start_pass) (cinfo);
1525
1526
32.3k
  pw0 = PAD(width, cinfo->max_h_samp_factor);
1527
32.3k
  ph0 = PAD(height, cinfo->max_v_samp_factor);
1528
1529
32.3k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1530
32.3k
    THROW("Memory allocation failure");
1531
102M
  for (i = 0; i < height; i++) {
1532
102M
    if (this->bottomUp)
1533
17.3M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
1534
85.2M
    else
1535
85.2M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
1536
102M
  }
1537
32.3k
  if (height < ph0)
1538
6.11k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1539
1540
108k
  for (i = 0; i < cinfo->num_components; i++) {
1541
76.4k
    compptr = &cinfo->comp_info[i];
1542
76.4k
    _tmpbuf[i] = (JSAMPLE *)MALLOC(
1543
76.4k
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1544
76.4k
          compptr->h_samp_factor, 32) *
1545
76.4k
      cinfo->max_v_samp_factor + 32);
1546
76.4k
    if (!_tmpbuf[i])
1547
76.4k
      THROW("Memory allocation failure");
1548
76.4k
    tmpbuf[i] =
1549
76.4k
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
1550
76.4k
    if (!tmpbuf[i])
1551
76.4k
      THROW("Memory allocation failure");
1552
169k
    for (row = 0; row < cinfo->max_v_samp_factor; row++) {
1553
93.0k
      unsigned char *_tmpbuf_aligned =
1554
93.0k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
1555
1556
93.0k
      tmpbuf[i][row] = &_tmpbuf_aligned[
1557
93.0k
        PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1558
93.0k
            compptr->h_samp_factor, 32) * row];
1559
93.0k
    }
1560
76.4k
    _tmpbuf2[i] =
1561
76.4k
      (JSAMPLE *)MALLOC(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1562
76.4k
                        compptr->v_samp_factor + 32);
1563
76.4k
    if (!_tmpbuf2[i])
1564
76.4k
      THROW("Memory allocation failure");
1565
76.4k
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1566
76.4k
    if (!tmpbuf2[i])
1567
76.4k
      THROW("Memory allocation failure");
1568
158k
    for (row = 0; row < compptr->v_samp_factor; row++) {
1569
81.9k
      unsigned char *_tmpbuf2_aligned =
1570
81.9k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
1571
1572
81.9k
      tmpbuf2[i][row] =
1573
81.9k
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1574
81.9k
    }
1575
76.4k
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
1576
76.4k
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1577
76.4k
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1578
76.4k
    if (!outbuf[i])
1579
76.4k
      THROW("Memory allocation failure");
1580
76.4k
    ptr = dstPlanes[i];
1581
224M
    for (row = 0; row < ph[i]; row++) {
1582
224M
      outbuf[i][row] = ptr;
1583
224M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1584
224M
    }
1585
76.4k
  }
1586
1587
32.3k
  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
93.9M
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
1593
93.9M
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
1594
93.9M
                                       cinfo->max_v_samp_factor);
1595
93.9M
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
1596
309M
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
1597
215M
         i++, compptr++)
1598
215M
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
1599
215M
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
1600
215M
        compptr->v_samp_factor, pw[i]);
1601
93.9M
  }
1602
32.3k
  cinfo->next_scanline += height;
1603
32.3k
  jpeg_abort_compress(cinfo);
1604
1605
32.4k
bailout:
1606
32.4k
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1607
32.4k
  free(row_pointer);
1608
357k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1609
324k
    free(tmpbuf[i]);
1610
324k
    free(_tmpbuf[i]);
1611
324k
    free(tmpbuf2[i]);
1612
324k
    free(_tmpbuf2[i]);
1613
324k
    free(outbuf[i]);
1614
324k
  }
1615
32.4k
  if (this->jerr.warning) retval = -1;
1616
32.4k
  return retval;
1617
32.3k
}
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
32.4k
{
1649
32.4k
  static const char FUNCTION_NAME[] = "tj3EncodeYUV8";
1650
32.4k
  unsigned char *dstPlanes[3];
1651
32.4k
  int pw0, ph0, strides[3], retval = -1;
1652
1653
32.4k
  GET_TJINSTANCE(handle, -1);
1654
1655
32.4k
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
1656
32.4k
      !IS_POW2(align))
1657
32.4k
    THROW("Invalid argument");
1658
1659
32.4k
  if (this->subsamp == TJSAMP_UNKNOWN)
1660
32.4k
    THROW("TJPARAM_SUBSAMP must be specified");
1661
1662
32.4k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1663
32.4k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1664
32.4k
  dstPlanes[0] = dstBuf;
1665
32.4k
  strides[0] = PAD(pw0, align);
1666
32.4k
  if (this->subsamp == TJSAMP_GRAY) {
1667
10.2k
    strides[1] = strides[2] = 0;
1668
10.2k
    dstPlanes[1] = dstPlanes[2] = NULL;
1669
22.2k
  } else {
1670
22.2k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
1671
22.2k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
1672
1673
22.2k
    strides[1] = strides[2] = PAD(pw1, align);
1674
22.2k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1675
22.2k
        (unsigned long long)INT_MAX ||
1676
22.2k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1677
22.2k
        (unsigned long long)INT_MAX)
1678
22.2k
      THROW("Image or row alignment is too large");
1679
22.2k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1680
22.2k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1681
22.2k
  }
1682
1683
32.4k
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1684
32.4k
                             dstPlanes, strides);
1685
1686
0
bailout:
1687
0
  return retval;
1688
32.4k
}
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
52.9k
{
1738
52.9k
  static unsigned char buffer[1];
1739
1740
  /* This is also straight out of example.c */
1741
52.9k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1742
52.9k
  this->jerr.pub.error_exit = my_error_exit;
1743
52.9k
  this->jerr.pub.output_message = my_output_message;
1744
52.9k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1745
52.9k
  this->jerr.pub.emit_message = my_emit_message;
1746
52.9k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1747
52.9k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1748
52.9k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1749
1750
52.9k
  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
52.9k
  jpeg_create_decompress(&this->dinfo);
1757
  /* Make an initial call so it will create the source manager */
1758
52.9k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1759
1760
52.9k
  this->init |= DECOMPRESS;
1761
52.9k
  return (tjhandle)this;
1762
52.9k
}
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
17.1k
{
1776
17.1k
  static const char FUNCTION_NAME[] = "tj3DecompressHeader";
1777
17.1k
  int retval = 0;
1778
1779
17.1k
  GET_DINSTANCE(handle);
1780
17.1k
  if ((this->init & DECOMPRESS) == 0)
1781
17.1k
    THROW("Instance has not been initialized for decompression");
1782
1783
17.1k
  if (jpegBuf == NULL || jpegSize <= 0)
1784
17.1k
    THROW("Invalid argument");
1785
1786
17.1k
  if (setjmp(this->jerr.setjmp_buffer)) {
1787
    /* If we get here, the JPEG code has signaled an error. */
1788
1.79k
    return -1;
1789
1.79k
  }
1790
1791
15.3k
  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
15.3k
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1798
1.72k
    return 0;
1799
1800
13.5k
  setDecompParameters(this);
1801
1802
13.5k
  jpeg_abort_decompress(dinfo);
1803
1804
13.5k
  if (this->colorspace < 0)
1805
13.5k
    THROW("Could not determine colorspace of JPEG image");
1806
13.5k
  if (this->jpegWidth < 1 || this->jpegHeight < 1)
1807
13.5k
    THROW("Invalid data returned in header");
1808
1809
13.5k
bailout:
1810
13.5k
  if (this->jerr.warning) retval = -1;
1811
13.5k
  return retval;
1812
13.5k
}
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
30.4k
{
1892
30.4k
  static const char FUNCTION_NAME[] = "tj3SetScalingFactor";
1893
30.4k
  int i, retval = 0;
1894
1895
30.4k
  GET_TJINSTANCE(handle, -1);
1896
30.4k
  if ((this->init & DECOMPRESS) == 0)
1897
30.4k
    THROW("Instance has not been initialized for decompression");
1898
1899
285k
  for (i = 0; i < NUMSF; i++) {
1900
285k
    if (scalingFactor.num == sf[i].num && scalingFactor.denom == sf[i].denom)
1901
30.4k
      break;
1902
285k
  }
1903
30.4k
  if (i >= NUMSF)
1904
30.4k
    THROW("Unsupported scaling factor");
1905
1906
30.4k
  this->scalingFactor = scalingFactor;
1907
1908
30.4k
bailout:
1909
30.4k
  return retval;
1910
30.4k
}
1911
1912
1913
/* TurboJPEG 3+ */
1914
DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion)
1915
6.22k
{
1916
6.22k
  static const char FUNCTION_NAME[] = "tj3SetCroppingRegion";
1917
6.22k
  int retval = 0, scaledWidth, scaledHeight;
1918
1919
6.22k
  GET_TJINSTANCE(handle, -1);
1920
6.22k
  if ((this->init & DECOMPRESS) == 0)
1921
6.22k
    THROW("Instance has not been initialized for decompression");
1922
1923
6.22k
  if (croppingRegion.x == 0 && croppingRegion.y == 0 &&
1924
6.09k
      croppingRegion.w == 0 && croppingRegion.h == 0) {
1925
6.09k
    this->croppingRegion = croppingRegion;
1926
6.09k
    return 0;
1927
6.09k
  }
1928
1929
129
  if (croppingRegion.x < 0 || croppingRegion.y < 0 || croppingRegion.w < 0 ||
1930
129
      croppingRegion.h < 0)
1931
129
    THROW("Invalid cropping region");
1932
129
  if (this->jpegWidth < 0 || this->jpegHeight < 0)
1933
129
    THROW("JPEG header has not yet been read");
1934
129
  if (this->precision == 16 || this->lossless)
1935
129
    THROW("Cannot partially decompress lossless JPEG images");
1936
129
  if (this->subsamp == TJSAMP_UNKNOWN)
1937
99
    THROW("Could not determine subsampling level of JPEG image");
1938
1939
99
  scaledWidth = TJSCALED(this->jpegWidth, this->scalingFactor);
1940
99
  scaledHeight = TJSCALED(this->jpegHeight, this->scalingFactor);
1941
1942
99
  if (croppingRegion.x %
1943
99
      TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor) != 0)
1944
0
    THROWI("The left boundary of the cropping region (%d) is not\n"
1945
99
           "divisible by the scaled iMCU width (%d)",
1946
99
           croppingRegion.x,
1947
99
           TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor));
1948
99
  if (croppingRegion.w == 0)
1949
0
    croppingRegion.w = scaledWidth - croppingRegion.x;
1950
99
  if (croppingRegion.h == 0)
1951
0
    croppingRegion.h = scaledHeight - croppingRegion.y;
1952
99
  if (croppingRegion.w <= 0 || croppingRegion.h <= 0 ||
1953
99
      croppingRegion.x + croppingRegion.w > scaledWidth ||
1954
99
      croppingRegion.y + croppingRegion.h > scaledHeight)
1955
99
    THROW("The cropping region exceeds the scaled image dimensions");
1956
1957
99
  this->croppingRegion = croppingRegion;
1958
1959
129
bailout:
1960
129
  return retval;
1961
99
}
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
14.7k
{
2036
14.7k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUVPlanes8";
2037
14.7k
  int i, row, retval = 0;
2038
14.7k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
2039
14.7k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
2040
14.7k
  JSAMPLE *_tmpbuf = NULL, *ptr;
2041
14.7k
  JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
2042
14.7k
  int dctsize;
2043
14.7k
  struct my_progress_mgr progress;
2044
2045
14.7k
  GET_DINSTANCE(handle);
2046
2047
162k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2048
147k
    tmpbuf[i] = NULL;  outbuf[i] = NULL;
2049
147k
  }
2050
2051
14.7k
  if ((this->init & DECOMPRESS) == 0)
2052
14.7k
    THROW("Instance has not been initialized for decompression");
2053
2054
14.7k
  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0])
2055
14.7k
    THROW("Invalid argument");
2056
2057
14.7k
  if (this->scanLimit) {
2058
14.7k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2059
14.7k
    progress.pub.progress_monitor = my_progress_monitor;
2060
14.7k
    progress.this = this;
2061
14.7k
    dinfo->progress = &progress.pub;
2062
14.7k
  } else
2063
0
    dinfo->progress = NULL;
2064
2065
14.7k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2066
2067
14.7k
  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
14.7k
  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
14.7k
  setDecompParameters(this);
2077
14.7k
  if (this->maxPixels &&
2078
0
      (unsigned long long)this->jpegWidth * this->jpegHeight >
2079
0
      (unsigned long long)this->maxPixels)
2080
14.7k
    THROW("Image is too large");
2081
14.7k
  if (this->subsamp == TJSAMP_UNKNOWN)
2082
14.7k
    THROW("Could not determine subsampling level of JPEG image");
2083
2084
14.7k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
2085
14.7k
    THROW("Invalid argument");
2086
2087
14.7k
  if (dinfo->num_components > 3)
2088
14.7k
    THROW("JPEG image must have 3 or fewer components");
2089
2090
14.7k
  dinfo->scale_num = this->scalingFactor.num;
2091
14.7k
  dinfo->scale_denom = this->scalingFactor.denom;
2092
14.7k
  jpeg_calc_output_dimensions(dinfo);
2093
2094
14.7k
  dctsize = DCTSIZE * this->scalingFactor.num / this->scalingFactor.denom;
2095
2096
44.9k
  for (i = 0; i < dinfo->num_components; i++) {
2097
30.1k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
2098
30.1k
    int ih;
2099
2100
30.1k
    iw[i] = compptr->width_in_blocks * dctsize;
2101
30.1k
    ih = compptr->height_in_blocks * dctsize;
2102
30.1k
    pw[i] = tj3YUVPlaneWidth(i, dinfo->output_width, this->subsamp);
2103
30.1k
    ph[i] = tj3YUVPlaneHeight(i, dinfo->output_height, this->subsamp);
2104
30.1k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
2105
30.1k
    th[i] = compptr->v_samp_factor * dctsize;
2106
30.1k
    tmpbufsize += iw[i] * th[i];
2107
30.1k
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
2108
30.1k
      THROW("Memory allocation failure");
2109
30.1k
    ptr = dstPlanes[i];
2110
185M
    for (row = 0; row < ph[i]; row++) {
2111
185M
      outbuf[i][row] = ptr;
2112
185M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2113
185M
    }
2114
30.1k
  }
2115
14.7k
  if (usetmpbuf) {
2116
13.1k
    if ((_tmpbuf = (JSAMPLE *)MALLOC(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
2117
13.1k
      THROW("Memory allocation failure");
2118
13.1k
    ptr = _tmpbuf;
2119
40.3k
    for (i = 0; i < dinfo->num_components; i++) {
2120
27.2k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
2121
27.2k
        THROW("Memory allocation failure");
2122
346k
      for (row = 0; row < th[i]; row++) {
2123
318k
        tmpbuf[i][row] = ptr;
2124
318k
        ptr += iw[i];
2125
318k
      }
2126
27.2k
    }
2127
13.1k
  }
2128
2129
14.7k
  if (setjmp(this->jerr.setjmp_buffer)) {
2130
    /* If we get here, the JPEG code has signaled an error. */
2131
7.33k
    retval = -1;  goto bailout;
2132
7.33k
  }
2133
2134
7.43k
  dinfo->do_fancy_upsampling = !this->fastUpsample;
2135
18.4E
  dinfo->dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2136
7.43k
  dinfo->raw_data_out = TRUE;
2137
2138
7.43k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2139
2140
7.43k
  jpeg_start_decompress(dinfo);
2141
3.29M
  for (row = 0; row < (int)dinfo->output_height;
2142
3.28M
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
2143
3.28M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
2144
3.28M
    int crow[MAX_COMPONENTS];
2145
2146
9.30M
    for (i = 0; i < dinfo->num_components; i++) {
2147
6.01M
      jpeg_component_info *compptr = &dinfo->comp_info[i];
2148
2149
6.01M
      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
1.55M
        compptr->_DCT_scaled_size = dctsize;
2161
1.55M
        compptr->MCU_sample_width = tjMCUWidth[this->subsamp] *
2162
1.55M
          this->scalingFactor.num / this->scalingFactor.denom *
2163
1.55M
          compptr->v_samp_factor / dinfo->max_v_samp_factor;
2164
1.55M
        dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
2165
1.55M
      }
2166
6.01M
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2167
6.01M
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
2168
590k
      else yuvptr[i] = &outbuf[i][crow[i]];
2169
6.01M
    }
2170
3.28M
    jpeg_read_raw_data(dinfo, yuvptr,
2171
3.28M
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
2172
3.28M
    if (usetmpbuf) {
2173
2.95M
      int j;
2174
2175
8.37M
      for (i = 0; i < dinfo->num_components; i++) {
2176
61.4M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
2177
56.0M
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
2178
56.0M
        }
2179
5.41M
      }
2180
2.95M
    }
2181
3.28M
  }
2182
7.43k
  jpeg_finish_decompress(dinfo);
2183
2184
14.7k
bailout:
2185
14.7k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2186
162k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2187
147k
    free(tmpbuf[i]);
2188
147k
    free(outbuf[i]);
2189
147k
  }
2190
14.7k
  free(_tmpbuf);
2191
14.7k
  if (this->jerr.warning) retval = -1;
2192
14.7k
  return retval;
2193
7.43k
}
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
14.9k
{
2251
14.9k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUV8";
2252
14.9k
  unsigned char *dstPlanes[3];
2253
14.9k
  int pw0, ph0, strides[3], retval = -1;
2254
14.9k
  int width, height;
2255
2256
14.9k
  GET_DINSTANCE(handle);
2257
2258
14.9k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || align < 1 ||
2259
14.9k
      !IS_POW2(align))
2260
14.9k
    THROW("Invalid argument");
2261
2262
14.9k
  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
14.9k
  if (dinfo->global_state <= DSTATE_INHEADER) {
2268
14.9k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2269
14.9k
    jpeg_read_header(dinfo, TRUE);
2270
14.9k
  }
2271
14.9k
  setDecompParameters(this);
2272
14.9k
  if (this->subsamp == TJSAMP_UNKNOWN)
2273
14.7k
    THROW("Could not determine subsampling level of JPEG image");
2274
2275
14.7k
  width = TJSCALED(dinfo->image_width, this->scalingFactor);
2276
14.7k
  height = TJSCALED(dinfo->image_height, this->scalingFactor);
2277
2278
14.7k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2279
14.7k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2280
14.7k
  dstPlanes[0] = dstBuf;
2281
14.7k
  strides[0] = PAD(pw0, align);
2282
14.7k
  if (this->subsamp == TJSAMP_GRAY) {
2283
7.06k
    strides[1] = strides[2] = 0;
2284
7.06k
    dstPlanes[1] = dstPlanes[2] = NULL;
2285
7.72k
  } else {
2286
7.72k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2287
7.72k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2288
2289
7.72k
    strides[1] = strides[2] = PAD(pw1, align);
2290
7.72k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2291
7.72k
        (unsigned long long)INT_MAX ||
2292
7.72k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2293
7.72k
        (unsigned long long)INT_MAX)
2294
7.72k
      THROW("Image or row alignment is too large");
2295
7.72k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
2296
7.72k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
2297
7.72k
  }
2298
2299
14.7k
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2300
14.7k
                                   strides);
2301
2302
160
bailout:
2303
160
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2304
160
  if (this->jerr.warning) retval = -1;
2305
160
  return retval;
2306
14.7k
}
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.91k
{
2367
2.91k
  int i;
2368
2369
2.91k
  this->dinfo.scale_num = this->dinfo.scale_denom = 1;
2370
2371
2.91k
  if (this->subsamp == TJSAMP_GRAY) {
2372
1.34k
    this->dinfo.num_components = this->dinfo.comps_in_scan = 1;
2373
1.34k
    this->dinfo.jpeg_color_space = JCS_GRAYSCALE;
2374
1.57k
  } else {
2375
1.57k
    this->dinfo.num_components = this->dinfo.comps_in_scan = 3;
2376
1.57k
    this->dinfo.jpeg_color_space = JCS_YCbCr;
2377
1.57k
  }
2378
2379
2.91k
  this->dinfo.comp_info = (jpeg_component_info *)
2380
2.91k
    (*this->dinfo.mem->alloc_small) ((j_common_ptr)&this->dinfo, JPOOL_IMAGE,
2381
2.91k
                                     this->dinfo.num_components *
2382
2.91k
                                     sizeof(jpeg_component_info));
2383
2384
8.98k
  for (i = 0; i < this->dinfo.num_components; i++) {
2385
6.06k
    jpeg_component_info *compptr = &this->dinfo.comp_info[i];
2386
2387
6.06k
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[this->subsamp] / 8 : 1;
2388
6.06k
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[this->subsamp] / 8 : 1;
2389
6.06k
    compptr->component_index = i;
2390
6.06k
    compptr->component_id = i + 1;
2391
6.06k
    compptr->quant_tbl_no = compptr->dc_tbl_no =
2392
6.06k
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
2393
6.06k
    this->dinfo.cur_comp_info[i] = compptr;
2394
6.06k
  }
2395
2.91k
  this->dinfo.data_precision = 8;
2396
8.75k
  for (i = 0; i < 2; i++) {
2397
5.83k
    if (this->dinfo.quant_tbl_ptrs[i] == NULL)
2398
977
      this->dinfo.quant_tbl_ptrs[i] =
2399
977
        jpeg_alloc_quant_table((j_common_ptr)&this->dinfo);
2400
5.83k
  }
2401
2402
2.91k
  this->dinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2403
2.91k
}
2404
2405
2406
static int my_read_markers(j_decompress_ptr dinfo)
2407
2.91k
{
2408
2.91k
  return JPEG_REACHED_SOS;
2409
2.91k
}
2410
2411
static void my_reset_marker_reader(j_decompress_ptr dinfo)
2412
2.91k
{
2413
2.91k
}
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.91k
{
2422
2.91k
  static const char FUNCTION_NAME[] = "tj3DecodeYUVPlanes8";
2423
2.91k
  JSAMPROW *row_pointer = NULL;
2424
2.91k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS];
2425
2.91k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
2426
2.91k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
2427
2.91k
  JSAMPLE *ptr;
2428
2.91k
  jpeg_component_info *compptr;
2429
2.91k
  int (*old_read_markers) (j_decompress_ptr);
2430
2.91k
  void (*old_reset_marker_reader) (j_decompress_ptr);
2431
2432
2.91k
  GET_DINSTANCE(handle);
2433
2434
32.0k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2435
29.1k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;  inbuf[i] = NULL;
2436
29.1k
  }
2437
2438
2.91k
  if ((this->init & DECOMPRESS) == 0)
2439
2.91k
    THROW("Instance has not been initialized for decompression");
2440
2441
2.91k
  if (!srcPlanes || !srcPlanes[0] || dstBuf == NULL || width <= 0 ||
2442
2.91k
      pitch < 0 || height <= 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
2443
2.91k
    THROW("Invalid argument");
2444
2.91k
  if (this->subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
2445
2.91k
    THROW("Invalid argument");
2446
2447
2.91k
  if (setjmp(this->jerr.setjmp_buffer)) {
2448
    /* If we get here, the JPEG code has signaled an error. */
2449
5
    retval = -1;  goto bailout;
2450
5
  }
2451
2452
2.91k
  if (this->subsamp == TJSAMP_UNKNOWN)
2453
2.91k
    THROW("TJPARAM_SUBSAMP must be specified");
2454
2.91k
  if (pixelFormat == TJPF_CMYK)
2455
2.91k
    THROW("Cannot decode YUV images into packed-pixel CMYK images.");
2456
2457
2.91k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
2458
2.91k
  dinfo->image_width = width;
2459
2.91k
  dinfo->image_height = height;
2460
2461
2.91k
  dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
2462
2.91k
  dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
2463
2.91k
  dinfo->Se = DCTSIZE2 - 1;
2464
2.91k
  setDecodeDefaults(this, pixelFormat);
2465
2.91k
  old_read_markers = dinfo->marker->read_markers;
2466
2.91k
  dinfo->marker->read_markers = my_read_markers;
2467
2.91k
  old_reset_marker_reader = dinfo->marker->reset_marker_reader;
2468
2.91k
  dinfo->marker->reset_marker_reader = my_reset_marker_reader;
2469
2.91k
  jpeg_read_header(dinfo, TRUE);
2470
2.91k
  dinfo->marker->read_markers = old_read_markers;
2471
2.91k
  dinfo->marker->reset_marker_reader = old_reset_marker_reader;
2472
2473
2.91k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
2474
2.91k
  this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2475
2.91k
  dinfo->do_fancy_upsampling = FALSE;
2476
2.91k
  dinfo->Se = DCTSIZE2 - 1;
2477
2.91k
  jinit_master_decompress(dinfo);
2478
2.91k
  (*dinfo->upsample->start_pass) (dinfo);
2479
2480
2.91k
  pw0 = PAD(width, dinfo->max_h_samp_factor);
2481
2.91k
  ph0 = PAD(height, dinfo->max_v_samp_factor);
2482
2483
2.91k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
2484
2485
2.91k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
2486
2.91k
    THROW("Memory allocation failure");
2487
14.6M
  for (i = 0; i < height; i++) {
2488
14.6M
    if (this->bottomUp)
2489
5.34M
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
2490
9.32M
    else
2491
9.32M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
2492
14.6M
  }
2493
2.91k
  if (height < ph0)
2494
1.04k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
2495
2496
8.96k
  for (i = 0; i < dinfo->num_components; i++) {
2497
6.05k
    compptr = &dinfo->comp_info[i];
2498
6.05k
    _tmpbuf[i] =
2499
6.05k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
2500
6.05k
                        compptr->v_samp_factor + 32);
2501
6.05k
    if (!_tmpbuf[i])
2502
6.05k
      THROW("Memory allocation failure");
2503
6.05k
    tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
2504
6.05k
    if (!tmpbuf[i])
2505
6.05k
      THROW("Memory allocation failure");
2506
13.2k
    for (row = 0; row < compptr->v_samp_factor; row++) {
2507
7.23k
      unsigned char *_tmpbuf_aligned =
2508
7.23k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
2509
2510
7.23k
      tmpbuf[i][row] =
2511
7.23k
        &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
2512
7.23k
    }
2513
6.05k
    pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
2514
6.05k
    ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2515
6.05k
    inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
2516
6.05k
    if (!inbuf[i])
2517
6.05k
      THROW("Memory allocation failure");
2518
6.05k
    ptr = (JSAMPLE *)srcPlanes[i];
2519
24.6M
    for (row = 0; row < ph[i]; row++) {
2520
24.6M
      inbuf[i][row] = ptr;
2521
24.6M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2522
24.6M
    }
2523
6.05k
  }
2524
2525
2.91k
  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
12.8M
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
2531
12.8M
    JDIMENSION inrow = 0, outrow = 0;
2532
2533
35.6M
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
2534
22.8M
         i++, compptr++)
2535
22.8M
      jcopy_sample_rows(inbuf[i],
2536
22.8M
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
2537
22.8M
        compptr->v_samp_factor, pw[i]);
2538
12.8M
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
2539
12.8M
                                 dinfo->max_v_samp_factor, &row_pointer[row],
2540
12.8M
                                 &outrow, dinfo->max_v_samp_factor);
2541
12.8M
  }
2542
2.91k
  jpeg_abort_decompress(dinfo);
2543
2544
2.91k
bailout:
2545
2.91k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2546
2.91k
  free(row_pointer);
2547
32.0k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2548
29.1k
    free(tmpbuf[i]);
2549
29.1k
    free(_tmpbuf[i]);
2550
29.1k
    free(inbuf[i]);
2551
29.1k
  }
2552
2.91k
  if (this->jerr.warning) retval = -1;
2553
2.91k
  return retval;
2554
2.91k
}
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.91k
{
2587
2.91k
  static const char FUNCTION_NAME[] = "tj3DecodeYUV8";
2588
2.91k
  const unsigned char *srcPlanes[3];
2589
2.91k
  int pw0, ph0, strides[3], retval = -1;
2590
2591
2.91k
  GET_TJINSTANCE(handle, -1);
2592
2593
2.91k
  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || width <= 0 ||
2594
2.91k
      height <= 0)
2595
2.91k
    THROW("Invalid argument");
2596
2597
2.91k
  if (this->subsamp == TJSAMP_UNKNOWN)
2598
2.91k
    THROW("TJPARAM_SUBSAMP must be specified");
2599
2600
2.91k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2601
2.91k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2602
2.91k
  srcPlanes[0] = srcBuf;
2603
2.91k
  strides[0] = PAD(pw0, align);
2604
2.91k
  if (this->subsamp == TJSAMP_GRAY) {
2605
1.34k
    strides[1] = strides[2] = 0;
2606
1.34k
    srcPlanes[1] = srcPlanes[2] = NULL;
2607
1.57k
  } else {
2608
1.57k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2609
1.57k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2610
2611
1.57k
    strides[1] = strides[2] = PAD(pw1, align);
2612
1.57k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2613
1.57k
        (unsigned long long)INT_MAX ||
2614
1.57k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2615
1.57k
        (unsigned long long)INT_MAX)
2616
1.57k
      THROW("Image or row alignment is too large");
2617
1.57k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
2618
1.57k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
2619
1.57k
  }
2620
2621
2.91k
  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
2622
2.91k
                             height, pixelFormat);
2623
2624
0
bailout:
2625
0
  return retval;
2626
2.91k
}
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
15.4k
{
2667
15.4k
  static const char FUNCTION_NAME[] = "tj3Transform";
2668
15.4k
  jpeg_transform_info *xinfo = NULL;
2669
15.4k
  jvirt_barray_ptr *srccoefs, *dstcoefs;
2670
15.4k
  int retval = 0, i, saveMarkers = 0, srcSubsamp;
2671
15.4k
  boolean alloc = TRUE;
2672
15.4k
  struct my_progress_mgr progress;
2673
2674
15.4k
  GET_INSTANCE(handle);
2675
15.4k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
2676
15.4k
    THROW("Instance has not been initialized for transformation");
2677
2678
15.4k
  if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
2679
15.4k
      dstSizes == NULL || t == NULL)
2680
15.4k
    THROW("Invalid argument");
2681
2682
15.4k
  if (this->scanLimit) {
2683
15.4k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2684
15.4k
    progress.pub.progress_monitor = my_progress_monitor;
2685
15.4k
    progress.this = this;
2686
15.4k
    dinfo->progress = &progress.pub;
2687
15.4k
  } else
2688
0
    dinfo->progress = NULL;
2689
2690
15.4k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2691
2692
15.4k
  if ((xinfo =
2693
15.4k
       (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
2694
15.4k
    THROW("Memory allocation failure");
2695
15.4k
  memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
2696
2697
15.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
2698
    /* If we get here, the JPEG code has signaled an error. */
2699
8.05k
    retval = -1;  goto bailout;
2700
8.05k
  }
2701
2702
7.41k
  if (dinfo->global_state <= DSTATE_INHEADER)
2703
15.4k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2704
2705
22.8k
  for (i = 0; i < n; i++) {
2706
15.4k
    if (t[i].op < 0 || t[i].op >= TJ_NUMXOP)
2707
15.4k
      THROW("Invalid transform operation");
2708
15.4k
    xinfo[i].transform = xformtypes[t[i].op];
2709
15.4k
    xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
2710
15.4k
    xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
2711
15.4k
    xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
2712
15.4k
    xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
2713
15.4k
    if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
2714
15.4k
    else xinfo[i].slow_hflip = 0;
2715
2716
15.4k
    if (xinfo[i].crop) {
2717
3.86k
      if (t[i].r.x < 0 || t[i].r.y < 0 || t[i].r.w < 0 || t[i].r.h < 0)
2718
3.86k
        THROW("Invalid cropping region");
2719
3.86k
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
2720
3.86k
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
2721
3.86k
      if (t[i].r.w != 0) {
2722
3.86k
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
2723
3.86k
      } else
2724
0
        xinfo[i].crop_width = JCROP_UNSET;
2725
3.86k
      if (t[i].r.h != 0) {
2726
3.86k
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
2727
3.86k
      } else
2728
0
        xinfo[i].crop_height = JCROP_UNSET;
2729
3.86k
    }
2730
15.4k
    if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
2731
15.4k
  }
2732
2733
18.4E
  jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
2734
7.41k
  if (dinfo->global_state <= DSTATE_INHEADER)
2735
15.4k
    jpeg_read_header(dinfo, TRUE);
2736
7.41k
  if (this->maxPixels &&
2737
0
      (unsigned long long)dinfo->image_width * dinfo->image_height >
2738
0
      (unsigned long long)this->maxPixels)
2739
7.41k
    THROW("Image is too large");
2740
7.41k
  srcSubsamp = getSubsamp(&this->dinfo);
2741
2742
22.8k
  for (i = 0; i < n; i++) {
2743
15.4k
    if (!jtransform_request_workspace(dinfo, &xinfo[i]))
2744
15.4k
      THROW("Transform is not perfect");
2745
2746
15.4k
    if (xinfo[i].crop) {
2747
3.86k
      int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2748
2749
3.86k
      if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2750
3.86k
          t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2751
3.86k
        if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2752
3.86k
        else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2753
3.86k
        else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2754
3.86k
        else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2755
3.86k
      }
2756
3.86k
      if (dstSubsamp == TJSAMP_UNKNOWN)
2757
3.86k
        THROW("Could not determine subsampling level of destination image");
2758
3.86k
      if ((t[i].r.x % tjMCUWidth[dstSubsamp]) != 0 ||
2759
3.86k
          (t[i].r.y % tjMCUHeight[dstSubsamp]) != 0)
2760
0
        THROWI("To crop this JPEG image, x must be a multiple of %d\n"
2761
3.86k
               "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
2762
3.86k
               tjMCUHeight[dstSubsamp]);
2763
3.86k
    }
2764
15.4k
  }
2765
2766
7.41k
  srccoefs = jpeg_read_coefficients(dinfo);
2767
2768
16.3k
  for (i = 0; i < n; i++) {
2769
9.87k
    JDIMENSION dstWidth = dinfo->image_width, dstHeight = dinfo->image_height;
2770
2771
9.87k
    if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2772
7.42k
        t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2773
4.90k
      dstWidth = dinfo->image_height;  dstHeight = dinfo->image_width;
2774
4.90k
    }
2775
2776
9.87k
    if (xinfo[i].crop) {
2777
2.45k
      if ((JDIMENSION)t[i].r.x >= dstWidth ||
2778
2.45k
          t[i].r.x + xinfo[i].crop_width > dstWidth ||
2779
2.45k
          (JDIMENSION)t[i].r.y >= dstHeight ||
2780
2.45k
          t[i].r.y + xinfo[i].crop_height > dstHeight)
2781
2.45k
        THROW("The cropping region exceeds the destination image dimensions");
2782
2.45k
      dstWidth = xinfo[i].crop_width;  dstHeight = xinfo[i].crop_height;
2783
2.45k
    }
2784
9.87k
    if (this->noRealloc) {
2785
7.42k
      int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2786
2787
7.42k
      if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2788
4.97k
          t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2789
4.90k
        if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2790
4.84k
        else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2791
4.79k
        else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2792
4.78k
        else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2793
4.90k
      }
2794
7.42k
      if (dstSubsamp == TJSAMP_UNKNOWN)
2795
6.47k
        THROW("Could not determine subsampling level of destination image");
2796
6.47k
      alloc = FALSE;
2797
6.47k
      dstSizes[i] = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
2798
6.47k
    }
2799
8.92k
    if (!(t[i].options & TJXOPT_NOOUTPUT))
2800
8.92k
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2801
8.92k
    jpeg_copy_critical_parameters(dinfo, cinfo);
2802
8.92k
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
2803
8.92k
    if (this->optimize || t[i].options & TJXOPT_OPTIMIZE)
2804
1.80k
      cinfo->optimize_coding = TRUE;
2805
8.92k
#ifdef C_PROGRESSIVE_SUPPORTED
2806
8.92k
    if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE)
2807
4.18k
      jpeg_simple_progression(cinfo);
2808
8.92k
#endif
2809
8.92k
    if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) {
2810
1.92k
      cinfo->arith_code = TRUE;
2811
1.92k
      cinfo->optimize_coding = FALSE;
2812
1.92k
    }
2813
8.92k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
2814
7.91k
      jpeg_write_coefficients(cinfo, dstcoefs);
2815
7.91k
      jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
2816
4.13k
                                          JCOPYOPT_NONE : JCOPYOPT_ALL);
2817
7.91k
    } else
2818
1.00k
      jinit_c_master_control(cinfo, TRUE);
2819
8.92k
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
2820
8.92k
    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
8.92k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2850
8.92k
  }
2851
2852
6.45k
  jpeg_finish_decompress(dinfo);
2853
2854
15.4k
bailout:
2855
15.4k
  if (cinfo->global_state > CSTATE_START) {
2856
1.45k
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
2857
1.45k
    jpeg_abort_compress(cinfo);
2858
1.45k
  }
2859
15.4k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2860
15.4k
  free(xinfo);
2861
15.4k
  if (this->jerr.warning) retval = -1;
2862
15.4k
  return retval;
2863
6.45k
}
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
}