Coverage Report

Created: 2025-10-13 06:06

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.88M
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
55
213k
#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
313k
{
88
313k
  (*cinfo->err->format_message) (cinfo, errStr);
89
313k
}
90
91
static void my_emit_message(j_common_ptr cinfo, int msg_level)
92
632M
{
93
632M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
94
95
632M
  myerr->emit_message(cinfo, msg_level);
96
632M
  if (msg_level < 0) {
97
423M
    myerr->warning = TRUE;
98
423M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
99
423M
  }
100
632M
}
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
351M
{
154
351M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
155
351M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
156
157
351M
  if (dinfo->is_decompressor) {
158
351M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
159
160
351M
    if (scan_no > myprog->this->scanLimit) {
161
76
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
162
76
               "Progressive JPEG image has more than %d scans",
163
76
               myprog->this->scanLimit);
164
76
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
165
76
               "Progressive JPEG image has more than %d scans",
166
76
               myprog->this->scanLimit);
167
76
      myprog->this->isInstanceError = TRUE;
168
76
      myerr->warning = FALSE;
169
76
      longjmp(myerr->setjmp_buffer, 1);
170
76
    }
171
351M
  }
172
351M
}
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
318k
#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.8k
  tjinstance *this = (tjinstance *)handle; \
278
82.8k
  j_compress_ptr cinfo = NULL; \
279
82.8k
  \
280
82.8k
  if (!this) { \
281
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
282
0
    return -1; \
283
0
  } \
284
82.8k
  cinfo = &this->cinfo; \
285
82.8k
  this->jerr.warning = FALSE; \
286
82.8k
  this->isInstanceError = FALSE;
287
288
#define GET_DINSTANCE(handle) \
289
74.1k
  tjinstance *this = (tjinstance *)handle; \
290
74.1k
  j_decompress_ptr dinfo = NULL; \
291
74.1k
  \
292
74.1k
  if (!this) { \
293
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
294
0
    return -1; \
295
0
  } \
296
74.1k
  dinfo = &this->dinfo; \
297
74.1k
  this->jerr.warning = FALSE; \
298
74.1k
  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
181k
{
331
181k
  int subsamp = this->subsamp;
332
333
181k
  this->cinfo.in_color_space = pf2cs[pixelFormat];
334
181k
  this->cinfo.input_components = tjPixelSize[pixelFormat];
335
181k
  jpeg_set_defaults(&this->cinfo);
336
337
181k
  this->cinfo.restart_interval = this->restartIntervalBlocks;
338
181k
  this->cinfo.restart_in_rows = this->restartIntervalRows;
339
181k
  this->cinfo.X_density = (UINT16)this->xDensity;
340
181k
  this->cinfo.Y_density = (UINT16)this->yDensity;
341
181k
  this->cinfo.density_unit = (UINT8)this->densityUnits;
342
181k
  this->cinfo.mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
343
344
181k
  if (this->lossless) {
345
37.5k
#ifdef C_LOSSLESS_SUPPORTED
346
37.5k
    jpeg_enable_lossless(&this->cinfo, this->losslessPSV, this->losslessPt);
347
37.5k
#endif
348
37.5k
    if (pixelFormat == TJPF_GRAY)
349
4.63k
      subsamp = TJSAMP_GRAY;
350
32.9k
    else if (subsamp != TJSAMP_GRAY)
351
32.9k
      subsamp = TJSAMP_444;
352
37.5k
    return;
353
37.5k
  }
354
355
144k
  jpeg_set_quality(&this->cinfo, this->quality, TRUE);
356
144k
  this->cinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
357
358
144k
  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
144k
  default:
370
144k
    if (subsamp == TJSAMP_GRAY)
371
41.7k
      jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);
372
102k
    else if (pixelFormat == TJPF_CMYK)
373
11.5k
      jpeg_set_colorspace(&this->cinfo, JCS_YCCK);
374
90.7k
    else
375
90.7k
      jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);
376
144k
  }
377
378
144k
  if (this->cinfo.data_precision == 8)
379
105k
    this->cinfo.optimize_coding = this->optimize;
380
144k
#ifdef C_PROGRESSIVE_SUPPORTED
381
144k
  if (this->progressive) jpeg_simple_progression(&this->cinfo);
382
144k
#endif
383
144k
  this->cinfo.arith_code = this->arithmetic;
384
385
144k
  this->cinfo.comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
386
144k
  this->cinfo.comp_info[1].h_samp_factor = 1;
387
144k
  this->cinfo.comp_info[2].h_samp_factor = 1;
388
144k
  if (this->cinfo.num_components > 3)
389
11.5k
    this->cinfo.comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
390
144k
  this->cinfo.comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
391
144k
  this->cinfo.comp_info[1].v_samp_factor = 1;
392
144k
  this->cinfo.comp_info[2].v_samp_factor = 1;
393
144k
  if (this->cinfo.num_components > 3)
394
11.5k
    this->cinfo.comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
395
144k
}
396
397
398
static int getSubsamp(j_decompress_ptr dinfo)
399
142k
{
400
142k
  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
142k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
407
75.3k
    return TJSAMP_GRAY;
408
409
354k
  for (i = 0; i < TJ_NUMSAMP; i++) {
410
325k
    if (i == TJSAMP_GRAY) continue;
411
412
289k
    if (dinfo->num_components == 3 ||
413
30.3k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
414
29.1k
          dinfo->jpeg_color_space == JCS_CMYK) &&
415
282k
         dinfo->num_components == 4)) {
416
282k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
417
121k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
418
57.9k
        int match = 0;
419
420
178k
        for (k = 1; k < dinfo->num_components; k++) {
421
120k
          int href = 1, vref = 1;
422
423
120k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
424
119k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
425
4.48k
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
426
4.48k
          }
427
120k
          if (dinfo->comp_info[k].h_samp_factor == href &&
428
97.7k
              dinfo->comp_info[k].v_samp_factor == vref)
429
84.2k
            match++;
430
120k
        }
431
57.9k
        if (match == dinfo->num_components - 1) {
432
35.1k
          retval = i;  break;
433
35.1k
        }
434
57.9k
      }
435
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
436
         in non-standard ways. */
437
247k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
438
142k
          dinfo->comp_info[0].v_samp_factor == 2 &&
439
76.8k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
440
35.1k
        int match = 0;
441
442
105k
        for (k = 1; k < dinfo->num_components; k++) {
443
70.8k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
444
445
70.8k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
446
70.4k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
447
572
            href = vref = 2;
448
572
          }
449
70.8k
          if (dinfo->comp_info[k].h_samp_factor == href &&
450
57.8k
              dinfo->comp_info[k].v_samp_factor == vref)
451
9.44k
            match++;
452
70.8k
        }
453
35.1k
        if (match == dinfo->num_components - 1) {
454
3.55k
          retval = i;  break;
455
3.55k
        }
456
35.1k
      }
457
      /* Handle 4:4:4 images whose sampling factors are specified in
458
         non-standard ways. */
459
244k
      if (dinfo->comp_info[0].h_samp_factor *
460
244k
          dinfo->comp_info[0].v_samp_factor <=
461
244k
          D_MAX_BLOCKS_IN_MCU / 3 && i == TJSAMP_444) {
462
21.0k
        int match = 0;
463
62.8k
        for (k = 1; k < dinfo->num_components; k++) {
464
43.8k
          if (dinfo->comp_info[k].h_samp_factor ==
465
43.8k
              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.48k
            match++;
469
43.8k
          if (match == dinfo->num_components - 1) {
470
1.98k
            retval = i;  break;
471
1.98k
          }
472
43.8k
        }
473
21.0k
      }
474
244k
    }
475
289k
  }
476
67.4k
  return retval;
477
142k
}
478
479
480
static void setDecompParameters(tjinstance *this)
481
96.3k
{
482
96.3k
  this->subsamp = getSubsamp(&this->dinfo);
483
96.3k
  this->jpegWidth = this->dinfo.image_width;
484
96.3k
  this->jpegHeight = this->dinfo.image_height;
485
96.3k
  this->precision = this->dinfo.data_precision;
486
96.3k
  switch (this->dinfo.jpeg_color_space) {
487
45.1k
  case JCS_GRAYSCALE:  this->colorspace = TJCS_GRAY;  break;
488
20.3k
  case JCS_RGB:        this->colorspace = TJCS_RGB;  break;
489
29.2k
  case JCS_YCbCr:      this->colorspace = TJCS_YCbCr;  break;
490
1.13k
  case JCS_CMYK:       this->colorspace = TJCS_CMYK;  break;
491
131
  case JCS_YCCK:       this->colorspace = TJCS_YCCK;  break;
492
320
  default:             this->colorspace = -1;  break;
493
96.3k
  }
494
96.3k
  this->progressive = this->dinfo.progressive_mode;
495
96.3k
  this->arithmetic = this->dinfo.arith_code;
496
96.3k
  this->lossless = this->dinfo.master->lossless;
497
96.3k
  this->losslessPSV = this->dinfo.Ss;
498
96.3k
  this->losslessPt = this->dinfo.Al;
499
96.3k
  this->xDensity = this->dinfo.X_density;
500
96.3k
  this->yDensity = this->dinfo.Y_density;
501
96.3k
  this->densityUnits = this->dinfo.density_unit;
502
96.3k
}
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
419k
{
540
419k
  static const char FUNCTION_NAME[] = "tj3Init";
541
419k
  tjinstance *this = NULL;
542
419k
  tjhandle retval = NULL;
543
544
419k
  if (initType < 0 || initType >= TJ_NUMINIT)
545
419k
    THROWG("Invalid argument", NULL);
546
547
419k
  if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL)
548
419k
    THROWG("Memory allocation failure", NULL);
549
419k
  memset(this, 0, sizeof(tjinstance));
550
419k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
551
552
419k
  this->quality = -1;
553
419k
  this->subsamp = TJSAMP_UNKNOWN;
554
419k
  this->jpegWidth = -1;
555
419k
  this->jpegHeight = -1;
556
419k
  this->precision = 8;
557
419k
  this->colorspace = -1;
558
419k
  this->losslessPSV = 1;
559
419k
  this->xDensity = 1;
560
419k
  this->yDensity = 1;
561
419k
  this->scalingFactor = TJUNSCALED;
562
563
419k
  switch (initType) {
564
365k
  case TJINIT_COMPRESS:  return _tjInitCompress(this);
565
37.6k
  case TJINIT_DECOMPRESS:  return _tjInitDecompress(this);
566
15.7k
  case TJINIT_TRANSFORM:
567
15.7k
    retval = _tjInitCompress(this);
568
15.7k
    if (!retval) return NULL;
569
15.7k
    retval = _tjInitDecompress(this);
570
15.7k
    return retval;
571
419k
  }
572
573
0
bailout:
574
0
  return retval;
575
419k
}
576
577
578
/* TurboJPEG 3+ */
579
DLLEXPORT void tj3Destroy(tjhandle handle)
580
419k
{
581
419k
  tjinstance *this = (tjinstance *)handle;
582
419k
  j_compress_ptr cinfo = NULL;
583
419k
  j_decompress_ptr dinfo = NULL;
584
585
419k
  if (!this) return;
586
587
419k
  cinfo = &this->cinfo;  dinfo = &this->dinfo;
588
419k
  this->jerr.warning = FALSE;
589
419k
  this->isInstanceError = FALSE;
590
591
419k
  if (setjmp(this->jerr.setjmp_buffer)) return;
592
419k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
593
419k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
594
419k
  free(this);
595
419k
}
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
326k
#define SET_PARAM(field, minValue, maxValue) { \
656
326k
  if (value < minValue || (maxValue > 0 && value > maxValue)) \
657
326k
    THROW("Parameter value out of range"); \
658
326k
  this->field = value; \
659
326k
}
660
661
530k
#define SET_BOOL_PARAM(field) { \
662
530k
  if (value < 0 || value > 1) \
663
530k
    THROW("Parameter value out of range"); \
664
530k
  this->field = (boolean)value; \
665
530k
}
666
667
/* TurboJPEG 3+ */
668
DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
669
857k
{
670
857k
  static const char FUNCTION_NAME[] = "tj3Set";
671
857k
  int retval = 0;
672
673
857k
  GET_TJINSTANCE(handle, -1);
674
675
857k
  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
114k
  case TJPARAM_NOREALLOC:
683
114k
    if (!(this->init & COMPRESS))
684
114k
      THROW("TJPARAM_NOREALLOC is not applicable to decompression instances.");
685
114k
    SET_BOOL_PARAM(noRealloc);
686
114k
    break;
687
37.6k
  case TJPARAM_QUALITY:
688
37.6k
    if (!(this->init & COMPRESS))
689
37.6k
      THROW("TJPARAM_QUALITY is not applicable to decompression instances.");
690
37.6k
    SET_PARAM(quality, 1, 100);
691
37.6k
    break;
692
37.6k
  case TJPARAM_SUBSAMP:
693
37.6k
    SET_PARAM(subsamp, 0, TJ_NUMSAMP - 1);
694
37.6k
    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.5k
  case TJPARAM_FASTUPSAMPLE:
716
11.5k
    if (!(this->init & DECOMPRESS))
717
11.5k
      THROW("TJPARAM_FASTUPSAMPLE is not applicable to compression instances.");
718
11.5k
    SET_BOOL_PARAM(fastUpsample);
719
11.5k
    break;
720
77.3k
  case TJPARAM_FASTDCT:
721
77.3k
    SET_BOOL_PARAM(fastDCT);
722
77.3k
    break;
723
52.5k
  case TJPARAM_OPTIMIZE:
724
52.5k
    if (!(this->init & COMPRESS))
725
52.5k
      THROW("TJPARAM_OPTIMIZE is not applicable to decompression instances.");
726
52.5k
    SET_BOOL_PARAM(optimize);
727
52.5k
    break;
728
72.3k
  case TJPARAM_PROGRESSIVE:
729
72.3k
    if (!(this->init & COMPRESS))
730
72.3k
      THROW("TJPARAM_PROGRESSIVE is read-only in decompression instances.");
731
72.3k
    SET_BOOL_PARAM(progressive);
732
72.3k
    break;
733
13.4k
  case TJPARAM_SCANLIMIT:
734
13.4k
    if (!(this->init & DECOMPRESS))
735
13.4k
      THROW("TJPARAM_SCANLIMIT is not applicable to compression instances.");
736
13.4k
    SET_PARAM(scanLimit, 0, -1);
737
13.4k
    break;
738
72.3k
  case TJPARAM_ARITHMETIC:
739
72.3k
    if (!(this->init & COMPRESS))
740
72.3k
      THROW("TJPARAM_ARITHMETIC is read-only in decompression instances.");
741
72.3k
    SET_BOOL_PARAM(arithmetic);
742
72.3k
    break;
743
12.6k
  case TJPARAM_LOSSLESS:
744
12.6k
    if (!(this->init & COMPRESS))
745
12.6k
      THROW("TJPARAM_LOSSLESS is read-only in decompression instances.");
746
12.6k
    SET_BOOL_PARAM(lossless);
747
12.6k
    break;
748
12.6k
  case TJPARAM_LOSSLESSPSV:
749
12.6k
    if (!(this->init & COMPRESS))
750
12.6k
      THROW("TJPARAM_LOSSLESSPSV is read-only in decompression instances.");
751
12.6k
    SET_PARAM(losslessPSV, 1, 7);
752
12.6k
    break;
753
12.6k
  case TJPARAM_LOSSLESSPT:
754
12.6k
    if (!(this->init & COMPRESS))
755
12.6k
      THROW("TJPARAM_LOSSLESSPT is read-only in decompression instances.");
756
12.6k
    SET_PARAM(losslessPt, 0, 15);
757
12.6k
    break;
758
20.8k
  case TJPARAM_RESTARTBLOCKS:
759
20.8k
    if (!(this->init & COMPRESS))
760
20.8k
      THROW("TJPARAM_RESTARTBLOCKS is not applicable to decompression instances.");
761
20.8k
    SET_PARAM(restartIntervalBlocks, 0, 65535);
762
20.8k
    if (value != 0) this->restartIntervalRows = 0;
763
20.8k
    break;
764
85.4k
  case TJPARAM_RESTARTROWS:
765
85.4k
    if (!(this->init & COMPRESS))
766
85.4k
      THROW("TJPARAM_RESTARTROWS is not applicable to decompression instances.");
767
85.4k
    SET_PARAM(restartIntervalRows, 0, 65535);
768
85.4k
    if (value != 0) this->restartIntervalBlocks = 0;
769
85.4k
    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
106k
  case TJPARAM_MAXPIXELS:
789
106k
    SET_PARAM(maxPixels, 0, -1);
790
106k
    break;
791
0
  default:
792
0
    THROW("Invalid parameter");
793
857k
  }
794
795
857k
bailout:
796
857k
  return retval;
797
857k
}
798
799
800
/* TurboJPEG 3+ */
801
DLLEXPORT int tj3Get(tjhandle handle, int param)
802
104k
{
803
104k
  tjinstance *this = (tjinstance *)handle;
804
104k
  if (!this) return -1;
805
806
104k
  switch (param) {
807
0
  case TJPARAM_STOPONWARNING:
808
0
    return this->jerr.stopOnWarning;
809
0
  case TJPARAM_BOTTOMUP:
810
0
    return this->bottomUp;
811
39.4k
  case TJPARAM_NOREALLOC:
812
39.4k
    return this->noRealloc;
813
0
  case TJPARAM_QUALITY:
814
0
    return this->quality;
815
10.8k
  case TJPARAM_SUBSAMP:
816
10.8k
    return this->subsamp;
817
17.3k
  case TJPARAM_JPEGWIDTH:
818
17.3k
    return this->jpegWidth;
819
17.3k
  case TJPARAM_JPEGHEIGHT:
820
17.3k
    return this->jpegHeight;
821
6.47k
  case TJPARAM_PRECISION:
822
6.47k
    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.7k
  case TJPARAM_LOSSLESS:
838
12.7k
    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
104k
  }
858
859
0
  return -1;
860
104k
}
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
221k
{
871
221k
  return MALLOC(bytes);
872
221k
}
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
196k
{
884
196k
  free(buf);
885
196k
}
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
246k
{
897
246k
  static const char FUNCTION_NAME[] = "tj3JPEGBufSize";
898
246k
  unsigned long long retval = 0;
899
246k
  int mcuw, mcuh, chromasf;
900
901
246k
  if (width < 1 || height < 1 || jpegSubsamp < TJSAMP_UNKNOWN ||
902
246k
      jpegSubsamp >= TJ_NUMSAMP)
903
246k
    THROWG("Invalid argument", 0);
904
905
246k
  if (jpegSubsamp == TJSAMP_UNKNOWN)
906
13.0k
    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
246k
  mcuw = tjMCUWidth[jpegSubsamp];
912
246k
  mcuh = tjMCUHeight[jpegSubsamp];
913
246k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
914
246k
  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
246k
bailout:
921
246k
  return (size_t)retval;
922
246k
}
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.7k
{
965
47.7k
  static const char FUNCTION_NAME[] = "tj3YUVBufSize";
966
47.7k
  unsigned long long retval = 0;
967
47.7k
  int nc, i;
968
969
47.7k
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
970
47.6k
    THROWG("Invalid argument", 0);
971
972
47.6k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
973
155k
  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.7k
bailout:
987
47.7k
  return (size_t)retval;
988
47.6k
}
989
990
/* TurboJPEG 1.4+ */
991
DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
992
                                      int subsamp)
993
0
{
994
0
  size_t retval = tj3YUVBufSize(width, align, height, subsamp);
995
0
  return (retval == 0) ? (unsigned long)-1 : (unsigned long)retval;
996
0
}
997
998
/* TurboJPEG 1.2+ */
999
DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
1000
0
{
1001
0
  return tjBufSizeYUV2(width, 4, height, subsamp);
1002
0
}
1003
1004
/* TurboJPEG 1.1+ */
1005
DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
1006
0
{
1007
0
  return tjBufSizeYUV(width, height, subsamp);
1008
0
}
1009
1010
1011
/* TurboJPEG 3+ */
1012
DLLEXPORT size_t tj3YUVPlaneSize(int componentID, int width, int stride,
1013
                                 int height, int subsamp)
1014
0
{
1015
0
  static const char FUNCTION_NAME[] = "tj3YUVPlaneSize";
1016
0
  unsigned long long retval = 0;
1017
0
  int pw, ph;
1018
1019
0
  if (width < 1 || height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1020
0
    THROWG("Invalid argument", 0);
1021
1022
0
  pw = tj3YUVPlaneWidth(componentID, width, subsamp);
1023
0
  ph = tj3YUVPlaneHeight(componentID, height, subsamp);
1024
0
  if (pw == 0 || ph == 0) return 0;
1025
1026
0
  if (stride == 0) stride = pw;
1027
0
  else stride = abs(stride);
1028
1029
0
  retval = (unsigned long long)stride * (ph - 1) + pw;
1030
#if ULLONG_MAX > ULONG_MAX
1031
  if (retval > (unsigned long long)((unsigned long)-1))
1032
    THROWG("Image is too large", 0);
1033
#endif
1034
1035
0
bailout:
1036
0
  return (size_t)retval;
1037
0
}
1038
1039
/* TurboJPEG 1.4+ */
1040
DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
1041
                                       int height, int subsamp)
1042
0
{
1043
0
  size_t retval = tj3YUVPlaneSize(componentID, width, stride, height, subsamp);
1044
0
  return (retval == 0) ? -1 : (unsigned long)retval;
1045
0
}
1046
1047
1048
/* TurboJPEG 3+ */
1049
DLLEXPORT int tj3YUVPlaneWidth(int componentID, int width, int subsamp)
1050
275k
{
1051
275k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneWidth";
1052
275k
  unsigned long long pw, retval = 0;
1053
275k
  int nc;
1054
1055
275k
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1056
275k
    THROWG("Invalid argument", 0);
1057
275k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1058
275k
  if (componentID < 0 || componentID >= nc)
1059
275k
    THROWG("Invalid argument", 0);
1060
1061
275k
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
1062
275k
  if (componentID == 0)
1063
145k
    retval = pw;
1064
129k
  else
1065
129k
    retval = pw * 8 / tjMCUWidth[subsamp];
1066
1067
275k
  if (retval > (unsigned long long)INT_MAX)
1068
275k
    THROWG("Width is too large", 0);
1069
1070
275k
bailout:
1071
275k
  return (int)retval;
1072
275k
}
1073
1074
/* TurboJPEG 1.4+ */
1075
DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
1076
22.1k
{
1077
22.1k
  int retval = tj3YUVPlaneWidth(componentID, width, subsamp);
1078
22.1k
  return (retval == 0) ? -1 : retval;
1079
22.1k
}
1080
1081
1082
/* TurboJPEG 3+ */
1083
DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp)
1084
275k
{
1085
275k
  static const char FUNCTION_NAME[] = "tj3YUVPlaneHeight";
1086
275k
  unsigned long long ph, retval = 0;
1087
275k
  int nc;
1088
1089
275k
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1090
275k
    THROWG("Invalid argument", 0);
1091
275k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
1092
275k
  if (componentID < 0 || componentID >= nc)
1093
275k
    THROWG("Invalid argument", 0);
1094
1095
275k
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
1096
275k
  if (componentID == 0)
1097
145k
    retval = ph;
1098
129k
  else
1099
129k
    retval = ph * 8 / tjMCUHeight[subsamp];
1100
1101
275k
  if (retval > (unsigned long long)INT_MAX)
1102
275k
    THROWG("Height is too large", 0);
1103
1104
275k
bailout:
1105
275k
  return (int)retval;
1106
275k
}
1107
1108
/* TurboJPEG 1.4+ */
1109
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
1110
22.1k
{
1111
22.1k
  int retval = tj3YUVPlaneHeight(componentID, height, subsamp);
1112
22.1k
  return (retval == 0) ? -1 : retval;
1113
22.1k
}
1114
1115
1116
/******************************** Compressor *********************************/
1117
1118
static tjhandle _tjInitCompress(tjinstance *this)
1119
381k
{
1120
381k
  static unsigned char buffer[1];
1121
381k
  unsigned char *buf = buffer;
1122
381k
  size_t size = 1;
1123
1124
  /* This is also straight out of example.c */
1125
381k
  this->cinfo.err = jpeg_std_error(&this->jerr.pub);
1126
381k
  this->jerr.pub.error_exit = my_error_exit;
1127
381k
  this->jerr.pub.output_message = my_output_message;
1128
381k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1129
381k
  this->jerr.pub.emit_message = my_emit_message;
1130
381k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1131
381k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1132
381k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1133
1134
381k
  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
381k
  jpeg_create_compress(&this->cinfo);
1141
  /* Make an initial call so it will create the destination manager */
1142
381k
  jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
1143
1144
381k
  this->init |= COMPRESS;
1145
381k
  return (tjhandle)this;
1146
381k
}
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.5k
#define BITS_IN_JSAMPLE  8
1157
#include "turbojpeg-mp.c"
1158
#undef BITS_IN_JSAMPLE
1159
43.6k
#define BITS_IN_JSAMPLE  12
1160
#include "turbojpeg-mp.c"
1161
#undef BITS_IN_JSAMPLE
1162
13.2k
#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.40M
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1318
1319
9.40M
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1320
9.40M
      if (usetmpbuf) {
1321
9.40M
        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.40M
        yuvptr[i] = tmpbuf[i];
1333
9.40M
      } else
1334
366
        yuvptr[i] = &inbuf[i][crow[i]];
1335
9.40M
    }
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.4k
{
1393
32.4k
  static const char FUNCTION_NAME[] = "tj3CompressFromYUV8";
1394
32.4k
  const unsigned char *srcPlanes[3];
1395
32.4k
  int pw0, ph0, strides[3], retval = -1;
1396
1397
32.4k
  GET_TJINSTANCE(handle, -1);
1398
1399
32.4k
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1400
32.4k
      height <= 0)
1401
32.4k
    THROW("Invalid argument");
1402
1403
32.4k
  if (this->subsamp == TJSAMP_UNKNOWN)
1404
32.4k
    THROW("TJPARAM_SUBSAMP must be specified");
1405
1406
32.4k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1407
32.4k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1408
32.4k
  srcPlanes[0] = srcBuf;
1409
32.4k
  strides[0] = PAD(pw0, align);
1410
32.4k
  if (this->subsamp == TJSAMP_GRAY) {
1411
10.2k
    strides[1] = strides[2] = 0;
1412
10.2k
    srcPlanes[1] = srcPlanes[2] = NULL;
1413
22.1k
  } else {
1414
22.1k
    int pw1 = tjPlaneWidth(1, width, this->subsamp);
1415
22.1k
    int ph1 = tjPlaneHeight(1, height, this->subsamp);
1416
1417
22.1k
    strides[1] = strides[2] = PAD(pw1, align);
1418
22.1k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
1419
22.1k
        (unsigned long long)INT_MAX ||
1420
22.1k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
1421
22.1k
        (unsigned long long)INT_MAX)
1422
22.1k
      THROW("Image or row alignment is too large");
1423
22.1k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1424
22.1k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1425
22.1k
  }
1426
1427
32.4k
  return tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
1428
32.4k
                                   jpegBuf, jpegSize);
1429
1430
0
bailout:
1431
0
  return retval;
1432
32.4k
}
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.5k
{
1470
32.5k
  static const char FUNCTION_NAME[] = "tj3EncodeYUVPlanes8";
1471
32.5k
  JSAMPROW *row_pointer = NULL;
1472
32.5k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
1473
32.5k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
1474
32.5k
  JSAMPROW *outbuf[MAX_COMPONENTS];
1475
32.5k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1476
32.5k
  JSAMPLE *ptr;
1477
32.5k
  jpeg_component_info *compptr;
1478
1479
32.5k
  GET_CINSTANCE(handle)
1480
1481
358k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1482
325k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
1483
325k
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
1484
325k
  }
1485
1486
32.5k
  if ((this->init & COMPRESS) == 0)
1487
32.5k
    THROW("Instance has not been initialized for compression");
1488
1489
32.5k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1490
32.5k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
1491
32.5k
      !dstPlanes[0])
1492
32.5k
    THROW("Invalid argument");
1493
32.5k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1494
32.5k
    THROW("Invalid argument");
1495
1496
32.5k
  if (this->subsamp == TJSAMP_UNKNOWN)
1497
32.5k
    THROW("TJPARAM_SUBSAMP must be specified");
1498
32.5k
  if (pixelFormat == TJPF_CMYK)
1499
32.5k
    THROW("Cannot generate YUV images from packed-pixel CMYK images");
1500
1501
32.5k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1502
1503
32.5k
  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.4k
  cinfo->image_width = width;
1509
32.4k
  cinfo->image_height = height;
1510
32.4k
  cinfo->data_precision = 8;
1511
1512
32.4k
  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.4k
  if (cinfo->global_state != CSTATE_START)
1519
32.4k
    THROW("libjpeg API is in the wrong state");
1520
32.4k
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
1521
32.4k
  jinit_c_master_control(cinfo, FALSE);
1522
32.4k
  jinit_color_converter(cinfo);
1523
32.4k
  jinit_downsampler(cinfo);
1524
32.4k
  (*cinfo->cconvert->start_pass) (cinfo);
1525
1526
32.4k
  pw0 = PAD(width, cinfo->max_h_samp_factor);
1527
32.4k
  ph0 = PAD(height, cinfo->max_v_samp_factor);
1528
1529
32.4k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1530
32.4k
    THROW("Memory allocation failure");
1531
103M
  for (i = 0; i < height; i++) {
1532
103M
    if (this->bottomUp)
1533
17.4M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
1534
85.7M
    else
1535
85.7M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
1536
103M
  }
1537
32.4k
  if (height < ph0)
1538
6.17k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1539
1540
109k
  for (i = 0; i < cinfo->num_components; i++) {
1541
76.7k
    compptr = &cinfo->comp_info[i];
1542
76.7k
    _tmpbuf[i] = (JSAMPLE *)MALLOC(
1543
76.7k
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1544
76.7k
          compptr->h_samp_factor, 32) *
1545
76.7k
      cinfo->max_v_samp_factor + 32);
1546
76.7k
    if (!_tmpbuf[i])
1547
76.7k
      THROW("Memory allocation failure");
1548
76.7k
    tmpbuf[i] =
1549
76.7k
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
1550
76.7k
    if (!tmpbuf[i])
1551
76.7k
      THROW("Memory allocation failure");
1552
170k
    for (row = 0; row < cinfo->max_v_samp_factor; row++) {
1553
93.3k
      unsigned char *_tmpbuf_aligned =
1554
93.3k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
1555
1556
93.3k
      tmpbuf[i][row] = &_tmpbuf_aligned[
1557
93.3k
        PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
1558
93.3k
            compptr->h_samp_factor, 32) * row];
1559
93.3k
    }
1560
76.7k
    _tmpbuf2[i] =
1561
76.7k
      (JSAMPLE *)MALLOC(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1562
76.7k
                        compptr->v_samp_factor + 32);
1563
76.7k
    if (!_tmpbuf2[i])
1564
76.7k
      THROW("Memory allocation failure");
1565
76.7k
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1566
76.7k
    if (!tmpbuf2[i])
1567
76.7k
      THROW("Memory allocation failure");
1568
158k
    for (row = 0; row < compptr->v_samp_factor; row++) {
1569
82.2k
      unsigned char *_tmpbuf2_aligned =
1570
82.2k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
1571
1572
82.2k
      tmpbuf2[i][row] =
1573
82.2k
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1574
82.2k
    }
1575
76.7k
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
1576
76.7k
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1577
76.7k
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1578
76.7k
    if (!outbuf[i])
1579
76.7k
      THROW("Memory allocation failure");
1580
76.7k
    ptr = dstPlanes[i];
1581
225M
    for (row = 0; row < ph[i]; row++) {
1582
225M
      outbuf[i][row] = ptr;
1583
225M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1584
225M
    }
1585
76.7k
  }
1586
1587
32.4k
  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
94.5M
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
1593
94.5M
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
1594
94.5M
                                       cinfo->max_v_samp_factor);
1595
94.5M
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
1596
311M
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
1597
216M
         i++, compptr++)
1598
216M
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
1599
216M
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
1600
216M
        compptr->v_samp_factor, pw[i]);
1601
94.5M
  }
1602
32.4k
  cinfo->next_scanline += height;
1603
32.4k
  jpeg_abort_compress(cinfo);
1604
1605
32.5k
bailout:
1606
32.5k
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1607
32.5k
  free(row_pointer);
1608
358k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1609
325k
    free(tmpbuf[i]);
1610
325k
    free(_tmpbuf[i]);
1611
325k
    free(tmpbuf2[i]);
1612
325k
    free(_tmpbuf2[i]);
1613
325k
    free(outbuf[i]);
1614
325k
  }
1615
32.5k
  if (this->jerr.warning) retval = -1;
1616
32.5k
  return retval;
1617
32.4k
}
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.5k
{
1649
32.5k
  static const char FUNCTION_NAME[] = "tj3EncodeYUV8";
1650
32.5k
  unsigned char *dstPlanes[3];
1651
32.5k
  int pw0, ph0, strides[3], retval = -1;
1652
1653
32.5k
  GET_TJINSTANCE(handle, -1);
1654
1655
32.5k
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
1656
32.5k
      !IS_POW2(align))
1657
32.5k
    THROW("Invalid argument");
1658
1659
32.5k
  if (this->subsamp == TJSAMP_UNKNOWN)
1660
32.5k
    THROW("TJPARAM_SUBSAMP must be specified");
1661
1662
32.5k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
1663
32.5k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
1664
32.5k
  dstPlanes[0] = dstBuf;
1665
32.5k
  strides[0] = PAD(pw0, align);
1666
32.5k
  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.5k
  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
1684
32.5k
                             dstPlanes, strides);
1685
1686
0
bailout:
1687
0
  return retval;
1688
32.5k
}
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
53.3k
{
1738
53.3k
  static unsigned char buffer[1];
1739
1740
  /* This is also straight out of example.c */
1741
53.3k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1742
53.3k
  this->jerr.pub.error_exit = my_error_exit;
1743
53.3k
  this->jerr.pub.output_message = my_output_message;
1744
53.3k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1745
53.3k
  this->jerr.pub.emit_message = my_emit_message;
1746
53.3k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1747
53.3k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1748
53.3k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1749
1750
53.3k
  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
53.3k
  jpeg_create_decompress(&this->dinfo);
1757
  /* Make an initial call so it will create the source manager */
1758
53.3k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1759
1760
53.3k
  this->init |= DECOMPRESS;
1761
53.3k
  return (tjhandle)this;
1762
53.3k
}
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.3k
{
1776
17.3k
  static const char FUNCTION_NAME[] = "tj3DecompressHeader";
1777
17.3k
  int retval = 0;
1778
1779
17.3k
  GET_DINSTANCE(handle);
1780
17.3k
  if ((this->init & DECOMPRESS) == 0)
1781
17.3k
    THROW("Instance has not been initialized for decompression");
1782
1783
17.3k
  if (jpegBuf == NULL || jpegSize <= 0)
1784
17.3k
    THROW("Invalid argument");
1785
1786
17.3k
  if (setjmp(this->jerr.setjmp_buffer)) {
1787
    /* If we get here, the JPEG code has signaled an error. */
1788
1.84k
    return -1;
1789
1.84k
  }
1790
1791
15.4k
  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.4k
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1798
1.73k
    return 0;
1799
1800
13.7k
  setDecompParameters(this);
1801
1802
13.7k
  jpeg_abort_decompress(dinfo);
1803
1804
13.7k
  if (this->colorspace < 0)
1805
13.6k
    THROW("Could not determine colorspace of JPEG image");
1806
13.6k
  if (this->jpegWidth < 1 || this->jpegHeight < 1)
1807
13.6k
    THROW("Invalid data returned in header");
1808
1809
13.7k
bailout:
1810
13.7k
  if (this->jerr.warning) retval = -1;
1811
13.7k
  return retval;
1812
13.6k
}
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.6k
{
1892
30.6k
  static const char FUNCTION_NAME[] = "tj3SetScalingFactor";
1893
30.6k
  int i, retval = 0;
1894
1895
30.6k
  GET_TJINSTANCE(handle, -1);
1896
30.6k
  if ((this->init & DECOMPRESS) == 0)
1897
30.6k
    THROW("Instance has not been initialized for decompression");
1898
1899
287k
  for (i = 0; i < NUMSF; i++) {
1900
287k
    if (scalingFactor.num == sf[i].num && scalingFactor.denom == sf[i].denom)
1901
30.6k
      break;
1902
287k
  }
1903
30.6k
  if (i >= NUMSF)
1904
30.6k
    THROW("Unsupported scaling factor");
1905
1906
30.6k
  this->scalingFactor = scalingFactor;
1907
1908
30.6k
bailout:
1909
30.6k
  return retval;
1910
30.6k
}
1911
1912
1913
/* TurboJPEG 3+ */
1914
DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion)
1915
6.23k
{
1916
6.23k
  static const char FUNCTION_NAME[] = "tj3SetCroppingRegion";
1917
6.23k
  int retval = 0, scaledWidth, scaledHeight;
1918
1919
6.23k
  GET_TJINSTANCE(handle, -1);
1920
6.23k
  if ((this->init & DECOMPRESS) == 0)
1921
6.23k
    THROW("Instance has not been initialized for decompression");
1922
1923
6.23k
  if (croppingRegion.x == 0 && croppingRegion.y == 0 &&
1924
6.10k
      croppingRegion.w == 0 && croppingRegion.h == 0) {
1925
6.10k
    this->croppingRegion = croppingRegion;
1926
6.10k
    return 0;
1927
6.10k
  }
1928
1929
128
  if (croppingRegion.x < 0 || croppingRegion.y < 0 || croppingRegion.w < 0 ||
1930
128
      croppingRegion.h < 0)
1931
128
    THROW("Invalid cropping region");
1932
128
  if (this->jpegWidth < 0 || this->jpegHeight < 0)
1933
128
    THROW("JPEG header has not yet been read");
1934
128
  if (this->precision == 16 || this->lossless)
1935
128
    THROW("Cannot partially decompress lossless JPEG images");
1936
128
  if (this->subsamp == TJSAMP_UNKNOWN)
1937
98
    THROW("Could not determine subsampling level of JPEG image");
1938
1939
98
  scaledWidth = TJSCALED(this->jpegWidth, this->scalingFactor);
1940
98
  scaledHeight = TJSCALED(this->jpegHeight, this->scalingFactor);
1941
1942
98
  if (croppingRegion.x %
1943
98
      TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor) != 0)
1944
0
    THROWI("The left boundary of the cropping region (%d) is not\n"
1945
98
           "divisible by the scaled iMCU width (%d)",
1946
98
           croppingRegion.x,
1947
98
           TJSCALED(tjMCUWidth[this->subsamp], this->scalingFactor));
1948
98
  if (croppingRegion.w == 0)
1949
0
    croppingRegion.w = scaledWidth - croppingRegion.x;
1950
98
  if (croppingRegion.h == 0)
1951
0
    croppingRegion.h = scaledHeight - croppingRegion.y;
1952
98
  if (croppingRegion.w <= 0 || croppingRegion.h <= 0 ||
1953
98
      croppingRegion.x + croppingRegion.w > scaledWidth ||
1954
98
      croppingRegion.y + croppingRegion.h > scaledHeight)
1955
98
    THROW("The cropping region exceeds the scaled image dimensions");
1956
1957
98
  this->croppingRegion = croppingRegion;
1958
1959
128
bailout:
1960
128
  return retval;
1961
98
}
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
15.0k
{
2036
15.0k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUVPlanes8";
2037
15.0k
  int i, row, retval = 0;
2038
15.0k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
2039
15.0k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
2040
15.0k
  JSAMPLE *_tmpbuf = NULL, *ptr;
2041
15.0k
  JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
2042
15.0k
  int dctsize;
2043
15.0k
  struct my_progress_mgr progress;
2044
2045
15.0k
  GET_DINSTANCE(handle);
2046
2047
165k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2048
150k
    tmpbuf[i] = NULL;  outbuf[i] = NULL;
2049
150k
  }
2050
2051
15.0k
  if ((this->init & DECOMPRESS) == 0)
2052
15.0k
    THROW("Instance has not been initialized for decompression");
2053
2054
15.0k
  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0])
2055
15.0k
    THROW("Invalid argument");
2056
2057
15.0k
  if (this->scanLimit) {
2058
15.0k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
2059
15.0k
    progress.pub.progress_monitor = my_progress_monitor;
2060
15.0k
    progress.this = this;
2061
15.0k
    dinfo->progress = &progress.pub;
2062
15.0k
  } else
2063
0
    dinfo->progress = NULL;
2064
2065
15.0k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2066
2067
15.0k
  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
15.0k
  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
15.0k
  setDecompParameters(this);
2077
15.0k
  if (this->maxPixels &&
2078
0
      (unsigned long long)this->jpegWidth * this->jpegHeight >
2079
0
      (unsigned long long)this->maxPixels)
2080
15.0k
    THROW("Image is too large");
2081
15.0k
  if (this->subsamp == TJSAMP_UNKNOWN)
2082
15.0k
    THROW("Could not determine subsampling level of JPEG image");
2083
2084
15.0k
  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
2085
15.0k
    THROW("Invalid argument");
2086
2087
15.0k
  if (dinfo->num_components > 3)
2088
15.0k
    THROW("JPEG image must have 3 or fewer components");
2089
2090
15.0k
  dinfo->scale_num = this->scalingFactor.num;
2091
15.0k
  dinfo->scale_denom = this->scalingFactor.denom;
2092
15.0k
  jpeg_calc_output_dimensions(dinfo);
2093
2094
15.0k
  dctsize = DCTSIZE * this->scalingFactor.num / this->scalingFactor.denom;
2095
2096
45.6k
  for (i = 0; i < dinfo->num_components; i++) {
2097
30.6k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
2098
30.6k
    int ih;
2099
2100
30.6k
    iw[i] = compptr->width_in_blocks * dctsize;
2101
30.6k
    ih = compptr->height_in_blocks * dctsize;
2102
30.6k
    pw[i] = tj3YUVPlaneWidth(i, dinfo->output_width, this->subsamp);
2103
30.6k
    ph[i] = tj3YUVPlaneHeight(i, dinfo->output_height, this->subsamp);
2104
30.6k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
2105
30.6k
    th[i] = compptr->v_samp_factor * dctsize;
2106
30.6k
    tmpbufsize += iw[i] * th[i];
2107
30.6k
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
2108
30.6k
      THROW("Memory allocation failure");
2109
30.6k
    ptr = dstPlanes[i];
2110
189M
    for (row = 0; row < ph[i]; row++) {
2111
189M
      outbuf[i][row] = ptr;
2112
189M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2113
189M
    }
2114
30.6k
  }
2115
15.0k
  if (usetmpbuf) {
2116
13.3k
    if ((_tmpbuf = (JSAMPLE *)MALLOC(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
2117
13.3k
      THROW("Memory allocation failure");
2118
13.3k
    ptr = _tmpbuf;
2119
41.0k
    for (i = 0; i < dinfo->num_components; i++) {
2120
27.6k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
2121
27.6k
        THROW("Memory allocation failure");
2122
351k
      for (row = 0; row < th[i]; row++) {
2123
324k
        tmpbuf[i][row] = ptr;
2124
324k
        ptr += iw[i];
2125
324k
      }
2126
27.6k
    }
2127
13.3k
  }
2128
2129
15.0k
  if (setjmp(this->jerr.setjmp_buffer)) {
2130
    /* If we get here, the JPEG code has signaled an error. */
2131
7.52k
    retval = -1;  goto bailout;
2132
7.52k
  }
2133
2134
7.50k
  dinfo->do_fancy_upsampling = !this->fastUpsample;
2135
18.4E
  dinfo->dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
2136
7.50k
  dinfo->raw_data_out = TRUE;
2137
2138
7.50k
  dinfo->mem->max_memory_to_use = (long)this->maxMemory * 1048576L;
2139
2140
7.50k
  jpeg_start_decompress(dinfo);
2141
3.30M
  for (row = 0; row < (int)dinfo->output_height;
2142
3.30M
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
2143
3.30M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
2144
3.30M
    int crow[MAX_COMPONENTS];
2145
2146
9.33M
    for (i = 0; i < dinfo->num_components; i++) {
2147
6.03M
      jpeg_component_info *compptr = &dinfo->comp_info[i];
2148
2149
6.03M
      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.03M
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
2167
6.03M
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
2168
594k
      else yuvptr[i] = &outbuf[i][crow[i]];
2169
6.03M
    }
2170
3.30M
    jpeg_read_raw_data(dinfo, yuvptr,
2171
3.30M
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
2172
3.30M
    if (usetmpbuf) {
2173
2.97M
      int j;
2174
2175
8.39M
      for (i = 0; i < dinfo->num_components; i++) {
2176
61.6M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
2177
56.1M
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
2178
56.1M
        }
2179
5.42M
      }
2180
2.97M
    }
2181
3.30M
  }
2182
7.50k
  jpeg_finish_decompress(dinfo);
2183
2184
15.0k
bailout:
2185
15.0k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2186
165k
  for (i = 0; i < MAX_COMPONENTS; i++) {
2187
150k
    free(tmpbuf[i]);
2188
150k
    free(outbuf[i]);
2189
150k
  }
2190
15.0k
  free(_tmpbuf);
2191
15.0k
  if (this->jerr.warning) retval = -1;
2192
15.0k
  return retval;
2193
7.50k
}
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
15.1k
{
2251
15.1k
  static const char FUNCTION_NAME[] = "tj3DecompressToYUV8";
2252
15.1k
  unsigned char *dstPlanes[3];
2253
15.1k
  int pw0, ph0, strides[3], retval = -1;
2254
15.1k
  int width, height;
2255
2256
15.1k
  GET_DINSTANCE(handle);
2257
2258
15.1k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || align < 1 ||
2259
15.1k
      !IS_POW2(align))
2260
15.1k
    THROW("Invalid argument");
2261
2262
15.1k
  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
15.1k
  if (dinfo->global_state <= DSTATE_INHEADER) {
2268
15.1k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2269
15.1k
    jpeg_read_header(dinfo, TRUE);
2270
15.1k
  }
2271
15.1k
  setDecompParameters(this);
2272
15.1k
  if (this->subsamp == TJSAMP_UNKNOWN)
2273
15.0k
    THROW("Could not determine subsampling level of JPEG image");
2274
2275
15.0k
  width = TJSCALED(dinfo->image_width, this->scalingFactor);
2276
15.0k
  height = TJSCALED(dinfo->image_height, this->scalingFactor);
2277
2278
15.0k
  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
2279
15.0k
  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
2280
15.0k
  dstPlanes[0] = dstBuf;
2281
15.0k
  strides[0] = PAD(pw0, align);
2282
15.0k
  if (this->subsamp == TJSAMP_GRAY) {
2283
7.21k
    strides[1] = strides[2] = 0;
2284
7.21k
    dstPlanes[1] = dstPlanes[2] = NULL;
2285
7.83k
  } else {
2286
7.83k
    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
2287
7.83k
    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
2288
2289
7.83k
    strides[1] = strides[2] = PAD(pw1, align);
2290
7.83k
    if ((unsigned long long)strides[0] * (unsigned long long)ph0 >
2291
7.83k
        (unsigned long long)INT_MAX ||
2292
7.83k
        (unsigned long long)strides[1] * (unsigned long long)ph1 >
2293
7.83k
        (unsigned long long)INT_MAX)
2294
7.83k
      THROW("Image or row alignment is too large");
2295
7.83k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
2296
7.83k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
2297
7.83k
  }
2298
2299
15.0k
  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
2300
15.0k
                                   strides);
2301
2302
143
bailout:
2303
143
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2304
143
  if (this->jerr.warning) retval = -1;
2305
143
  return retval;
2306
15.0k
}
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.97k
  for (i = 0; i < this->dinfo.num_components; i++) {
2385
6.05k
    jpeg_component_info *compptr = &this->dinfo.comp_info[i];
2386
2387
6.05k
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[this->subsamp] / 8 : 1;
2388
6.05k
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[this->subsamp] / 8 : 1;
2389
6.05k
    compptr->component_index = i;
2390
6.05k
    compptr->component_id = i + 1;
2391
6.05k
    compptr->quant_tbl_no = compptr->dc_tbl_no =
2392
6.05k
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
2393
6.05k
    this->dinfo.cur_comp_info[i] = compptr;
2394
6.05k
  }
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
980
      this->dinfo.quant_tbl_ptrs[i] =
2399
980
        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.1k
  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.4M
  for (i = 0; i < height; i++) {
2488
14.4M
    if (this->bottomUp)
2489
5.27M
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
2490
9.19M
    else
2491
9.19M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
2492
14.4M
  }
2493
2.91k
  if (height < ph0)
2494
1.06k
    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.22k
      unsigned char *_tmpbuf_aligned =
2508
7.22k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
2509
2510
7.22k
      tmpbuf[i][row] =
2511
7.22k
        &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
2512
7.22k
    }
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.2M
    for (row = 0; row < ph[i]; row++) {
2520
24.2M
      inbuf[i][row] = ptr;
2521
24.2M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
2522
24.2M
    }
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.6M
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
2531
12.6M
    JDIMENSION inrow = 0, outrow = 0;
2532
2533
35.1M
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
2534
22.4M
         i++, compptr++)
2535
22.4M
      jcopy_sample_rows(inbuf[i],
2536
22.4M
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
2537
22.4M
        compptr->v_samp_factor, pw[i]);
2538
12.6M
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
2539
12.6M
                                 dinfo->max_v_samp_factor, &row_pointer[row],
2540
12.6M
                                 &outrow, dinfo->max_v_samp_factor);
2541
12.6M
  }
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.1k
  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.04k
    retval = -1;  goto bailout;
2700
8.04k
  }
2701
2702
7.43k
  if (dinfo->global_state <= DSTATE_INHEADER)
2703
15.4k
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2704
2705
22.9k
  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.87k
      if (t[i].r.x < 0 || t[i].r.y < 0 || t[i].r.w < 0 || t[i].r.h < 0)
2718
3.87k
        THROW("Invalid cropping region");
2719
3.87k
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
2720
3.87k
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
2721
3.87k
      if (t[i].r.w != 0) {
2722
3.87k
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
2723
3.87k
      } else
2724
0
        xinfo[i].crop_width = JCROP_UNSET;
2725
3.87k
      if (t[i].r.h != 0) {
2726
3.87k
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
2727
3.87k
      } else
2728
0
        xinfo[i].crop_height = JCROP_UNSET;
2729
3.87k
    }
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.43k
  if (dinfo->global_state <= DSTATE_INHEADER)
2735
15.4k
    jpeg_read_header(dinfo, TRUE);
2736
7.43k
  if (this->maxPixels &&
2737
0
      (unsigned long long)dinfo->image_width * dinfo->image_height >
2738
0
      (unsigned long long)this->maxPixels)
2739
7.43k
    THROW("Image is too large");
2740
7.43k
  srcSubsamp = getSubsamp(&this->dinfo);
2741
2742
22.9k
  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.87k
      int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2748
2749
3.87k
      if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2750
3.87k
          t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2751
3.87k
        if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2752
3.87k
        else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2753
3.87k
        else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2754
3.87k
        else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2755
3.87k
      }
2756
3.87k
      if (dstSubsamp == TJSAMP_UNKNOWN)
2757
3.87k
        THROW("Could not determine subsampling level of destination image");
2758
3.87k
      if ((t[i].r.x % tjMCUWidth[dstSubsamp]) != 0 ||
2759
3.87k
          (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.87k
               "and y must be a multiple of %d.", tjMCUWidth[dstSubsamp],
2762
3.87k
               tjMCUHeight[dstSubsamp]);
2763
3.87k
    }
2764
15.4k
  }
2765
2766
7.43k
  srccoefs = jpeg_read_coefficients(dinfo);
2767
2768
16.3k
  for (i = 0; i < n; i++) {
2769
9.89k
    JDIMENSION dstWidth = dinfo->image_width, dstHeight = dinfo->image_height;
2770
2771
9.89k
    if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2772
7.43k
        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.89k
    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.89k
    if (this->noRealloc) {
2785
7.43k
      int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
2786
2787
7.43k
      if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
2788
4.98k
          t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
2789
4.90k
        if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
2790
4.85k
        else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
2791
4.80k
        else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
2792
4.79k
        else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
2793
4.90k
      }
2794
7.43k
      if (dstSubsamp == TJSAMP_UNKNOWN)
2795
6.48k
        THROW("Could not determine subsampling level of destination image");
2796
6.48k
      alloc = FALSE;
2797
6.48k
      dstSizes[i] = tj3JPEGBufSize(dstWidth, dstHeight, dstSubsamp);
2798
6.48k
    }
2799
8.93k
    if (!(t[i].options & TJXOPT_NOOUTPUT))
2800
8.93k
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2801
8.93k
    jpeg_copy_critical_parameters(dinfo, cinfo);
2802
8.93k
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
2803
8.93k
    if (this->optimize || t[i].options & TJXOPT_OPTIMIZE)
2804
1.81k
      cinfo->optimize_coding = TRUE;
2805
8.93k
#ifdef C_PROGRESSIVE_SUPPORTED
2806
8.93k
    if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE)
2807
4.18k
      jpeg_simple_progression(cinfo);
2808
8.93k
#endif
2809
8.93k
    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.93k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
2814
7.92k
      jpeg_write_coefficients(cinfo, dstcoefs);
2815
7.92k
      jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
2816
4.13k
                                          JCOPYOPT_NONE : JCOPYOPT_ALL);
2817
7.92k
    } else
2818
1.00k
      jinit_c_master_control(cinfo, TRUE);
2819
8.93k
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
2820
8.93k
    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.93k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2850
8.93k
  }
2851
2852
6.48k
  jpeg_finish_decompress(dinfo);
2853
2854
15.4k
bailout:
2855
15.4k
  if (cinfo->global_state > CSTATE_START) {
2856
1.44k
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
2857
1.44k
    jpeg_abort_compress(cinfo);
2858
1.44k
  }
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.48k
}
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
}