Coverage Report

Created: 2025-11-09 06:52

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