Coverage Report

Created: 2023-06-07 06:03

/src/libjpeg-turbo.2.1.x/turbojpeg.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C)2009-2023 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
#include <jinclude.h>
36
#define JPEG_INTERNALS
37
#include <jpeglib.h>
38
#include <jerror.h>
39
#include <setjmp.h>
40
#include <errno.h>
41
#include "./turbojpeg.h"
42
#include "./tjutil.h"
43
#include "transupp.h"
44
#include "./jpegcomp.h"
45
#include "./cdjpeg.h"
46
47
extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, unsigned long *,
48
                             boolean);
49
extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
50
                            unsigned long);
51
52
1.24M
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
53
159k
#define IS_POW2(x)  (((x) & (x - 1)) == 0)
54
55
56
/* Error handling (based on example in example.txt) */
57
58
static THREAD_LOCAL char errStr[JMSG_LENGTH_MAX] = "No error";
59
60
struct my_error_mgr {
61
  struct jpeg_error_mgr pub;
62
  jmp_buf setjmp_buffer;
63
  void (*emit_message) (j_common_ptr, int);
64
  boolean warning, stopOnWarning;
65
};
66
typedef struct my_error_mgr *my_error_ptr;
67
68
#define JMESSAGE(code, string)  string,
69
static const char *turbojpeg_message_table[] = {
70
#include "cderror.h"
71
  NULL
72
};
73
74
static void my_error_exit(j_common_ptr cinfo)
75
135k
{
76
135k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
77
78
135k
  (*cinfo->err->output_message) (cinfo);
79
135k
  longjmp(myerr->setjmp_buffer, 1);
80
135k
}
81
82
/* Based on output_message() in jerror.c */
83
84
static void my_output_message(j_common_ptr cinfo)
85
198k
{
86
198k
  (*cinfo->err->format_message) (cinfo, errStr);
87
198k
}
88
89
static void my_emit_message(j_common_ptr cinfo, int msg_level)
90
441M
{
91
441M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
92
93
441M
  myerr->emit_message(cinfo, msg_level);
94
441M
  if (msg_level < 0) {
95
266M
    myerr->warning = TRUE;
96
266M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
97
266M
  }
98
441M
}
99
100
101
/********************** Global structures, macros, etc. **********************/
102
103
enum { COMPRESS = 1, DECOMPRESS = 2 };
104
105
typedef struct _tjinstance {
106
  struct jpeg_compress_struct cinfo;
107
  struct jpeg_decompress_struct dinfo;
108
  struct my_error_mgr jerr;
109
  int init, headerRead;
110
  char errStr[JMSG_LENGTH_MAX];
111
  boolean isInstanceError;
112
} tjinstance;
113
114
struct my_progress_mgr {
115
  struct jpeg_progress_mgr pub;
116
  tjinstance *this;
117
};
118
typedef struct my_progress_mgr *my_progress_ptr;
119
120
static void my_progress_monitor(j_common_ptr dinfo)
121
178M
{
122
178M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
123
178M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
124
125
178M
  if (dinfo->is_decompressor) {
126
178M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
127
128
178M
    if (scan_no > 500) {
129
22
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
130
22
               "Progressive JPEG image has more than 500 scans");
131
22
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
132
22
               "Progressive JPEG image has more than 500 scans");
133
22
      myprog->this->isInstanceError = TRUE;
134
22
      myerr->warning = FALSE;
135
22
      longjmp(myerr->setjmp_buffer, 1);
136
22
    }
137
178M
  }
138
178M
}
139
140
static const int pixelsize[TJ_NUMSAMP] = { 3, 3, 3, 1, 3, 3 };
141
142
static const JXFORM_CODE xformtypes[TJ_NUMXOP] = {
143
  JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
144
  JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
145
};
146
147
253k
#define NUMSF  16
148
static const tjscalingfactor sf[NUMSF] = {
149
  { 2, 1 },
150
  { 15, 8 },
151
  { 7, 4 },
152
  { 13, 8 },
153
  { 3, 2 },
154
  { 11, 8 },
155
  { 5, 4 },
156
  { 9, 8 },
157
  { 1, 1 },
158
  { 7, 8 },
159
  { 3, 4 },
160
  { 5, 8 },
161
  { 1, 2 },
162
  { 3, 8 },
163
  { 1, 4 },
164
  { 1, 8 }
165
};
166
167
static J_COLOR_SPACE pf2cs[TJ_NUMPF] = {
168
  JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR,
169
  JCS_EXT_XRGB, JCS_GRAYSCALE, JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ABGR,
170
  JCS_EXT_ARGB, JCS_CMYK
171
};
172
173
static int cs2pf[JPEG_NUMCS] = {
174
  TJPF_UNKNOWN, TJPF_GRAY,
175
#if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
176
  TJPF_RGB,
177
#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 3
178
  TJPF_BGR,
179
#elif RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 4
180
  TJPF_RGBX,
181
#elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 4
182
  TJPF_BGRX,
183
#elif RGB_RED == 3 && RGB_GREEN == 2 && RGB_BLUE == 1 && RGB_PIXELSIZE == 4
184
  TJPF_XBGR,
185
#elif RGB_RED == 1 && RGB_GREEN == 2 && RGB_BLUE == 3 && RGB_PIXELSIZE == 4
186
  TJPF_XRGB,
187
#endif
188
  TJPF_UNKNOWN, TJPF_CMYK, TJPF_UNKNOWN, TJPF_RGB, TJPF_RGBX, TJPF_BGR,
189
  TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_RGBA, TJPF_BGRA, TJPF_ABGR, TJPF_ARGB,
190
  TJPF_UNKNOWN
191
};
192
193
18.4E
#define THROWG(m) { \
194
18.4E
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s", m); \
195
18.4E
  retval = -1;  goto bailout; \
196
18.4E
}
197
#ifdef _MSC_VER
198
#define THROW_UNIX(m) { \
199
  char strerrorBuf[80] = { 0 }; \
200
  strerror_s(strerrorBuf, 80, errno); \
201
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerrorBuf); \
202
  retval = -1;  goto bailout; \
203
}
204
#else
205
0
#define THROW_UNIX(m) { \
206
0
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \
207
0
  retval = -1;  goto bailout; \
208
0
}
209
#endif
210
1.86k
#define THROW(m) { \
211
1.86k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
212
1.86k
  this->isInstanceError = TRUE;  THROWG(m) \
213
1.86k
}
214
215
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
216
/* Private flag that triggers different TurboJPEG API behavior when fuzzing */
217
79.4k
#define TJFLAG_FUZZING  (1 << 30)
218
#endif
219
220
#define GET_INSTANCE(handle) \
221
139k
  tjinstance *this = (tjinstance *)handle; \
222
139k
  j_compress_ptr cinfo = NULL; \
223
139k
  j_decompress_ptr dinfo = NULL; \
224
139k
  \
225
139k
  if (!this) { \
226
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
227
0
    return -1; \
228
0
  } \
229
139k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
230
139k
  this->jerr.warning = FALSE; \
231
139k
  this->isInstanceError = FALSE;
232
233
#define GET_CINSTANCE(handle) \
234
55.9k
  tjinstance *this = (tjinstance *)handle; \
235
55.9k
  j_compress_ptr cinfo = NULL; \
236
55.9k
  \
237
55.9k
  if (!this) { \
238
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
239
0
    return -1; \
240
0
  } \
241
55.9k
  cinfo = &this->cinfo; \
242
55.9k
  this->jerr.warning = FALSE; \
243
55.9k
  this->isInstanceError = FALSE;
244
245
#define GET_DINSTANCE(handle) \
246
42.1k
  tjinstance *this = (tjinstance *)handle; \
247
42.1k
  j_decompress_ptr dinfo = NULL; \
248
42.1k
  \
249
42.1k
  if (!this) { \
250
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
251
0
    return -1; \
252
0
  } \
253
42.1k
  dinfo = &this->dinfo; \
254
42.1k
  this->jerr.warning = FALSE; \
255
42.1k
  this->isInstanceError = FALSE;
256
257
static int getPixelFormat(int pixelSize, int flags)
258
0
{
259
0
  if (pixelSize == 1) return TJPF_GRAY;
260
0
  if (pixelSize == 3) {
261
0
    if (flags & TJ_BGR) return TJPF_BGR;
262
0
    else return TJPF_RGB;
263
0
  }
264
0
  if (pixelSize == 4) {
265
0
    if (flags & TJ_ALPHAFIRST) {
266
0
      if (flags & TJ_BGR) return TJPF_XBGR;
267
0
      else return TJPF_XRGB;
268
0
    } else {
269
0
      if (flags & TJ_BGR) return TJPF_BGRX;
270
0
      else return TJPF_RGBX;
271
0
    }
272
0
  }
273
0
  return -1;
274
0
}
275
276
static void setCompDefaults(struct jpeg_compress_struct *cinfo,
277
                            int pixelFormat, int subsamp, int jpegQual,
278
                            int flags)
279
27.3k
{
280
27.3k
#ifndef NO_GETENV
281
27.3k
  char env[7] = { 0 };
282
27.3k
#endif
283
284
27.3k
  cinfo->in_color_space = pf2cs[pixelFormat];
285
27.3k
  cinfo->input_components = tjPixelSize[pixelFormat];
286
27.3k
  jpeg_set_defaults(cinfo);
287
288
27.3k
#ifndef NO_GETENV
289
27.3k
  if (!GETENV_S(env, 7, "TJ_OPTIMIZE") && !strcmp(env, "1"))
290
0
    cinfo->optimize_coding = TRUE;
291
27.3k
  if (!GETENV_S(env, 7, "TJ_ARITHMETIC") && !strcmp(env, "1"))
292
7.08k
    cinfo->arith_code = TRUE;
293
27.3k
  if (!GETENV_S(env, 7, "TJ_RESTART") && strlen(env) > 0) {
294
20.7k
    int temp = -1;
295
20.7k
    char tempc = 0;
296
297
#ifdef _MSC_VER
298
    if (sscanf_s(env, "%d%c", &temp, &tempc, 1) >= 1 && temp >= 0 &&
299
        temp <= 65535) {
300
#else
301
20.7k
    if (sscanf(env, "%d%c", &temp, &tempc) >= 1 && temp >= 0 &&
302
20.7k
        temp <= 65535) {
303
20.7k
#endif
304
20.7k
      if (toupper(tempc) == 'B') {
305
0
        cinfo->restart_interval = temp;
306
0
        cinfo->restart_in_rows = 0;
307
0
      } else
308
20.7k
        cinfo->restart_in_rows = temp;
309
20.7k
    }
310
20.7k
  }
311
27.3k
#endif
312
313
27.3k
  if (jpegQual >= 0) {
314
16.9k
    jpeg_set_quality(cinfo, jpegQual, TRUE);
315
16.9k
    if (jpegQual >= 96 || flags & TJFLAG_ACCURATEDCT)
316
2.74k
      cinfo->dct_method = JDCT_ISLOW;
317
14.2k
    else
318
14.2k
      cinfo->dct_method = JDCT_FASTEST;
319
16.9k
  }
320
27.3k
  if (subsamp == TJSAMP_GRAY)
321
8.35k
    jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
322
19.0k
  else if (pixelFormat == TJPF_CMYK)
323
962
    jpeg_set_colorspace(cinfo, JCS_YCCK);
324
18.0k
  else
325
18.0k
    jpeg_set_colorspace(cinfo, JCS_YCbCr);
326
327
27.3k
#ifdef C_PROGRESSIVE_SUPPORTED
328
27.3k
  if (flags & TJFLAG_PROGRESSIVE)
329
8.05k
    jpeg_simple_progression(cinfo);
330
19.3k
#ifndef NO_GETENV
331
19.3k
  else if (!GETENV_S(env, 7, "TJ_PROGRESSIVE") && !strcmp(env, "1"))
332
0
    jpeg_simple_progression(cinfo);
333
27.3k
#endif
334
27.3k
#endif
335
336
27.3k
  cinfo->comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
337
27.3k
  cinfo->comp_info[1].h_samp_factor = 1;
338
27.3k
  cinfo->comp_info[2].h_samp_factor = 1;
339
27.3k
  if (cinfo->num_components > 3)
340
962
    cinfo->comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
341
27.3k
  cinfo->comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
342
27.3k
  cinfo->comp_info[1].v_samp_factor = 1;
343
27.3k
  cinfo->comp_info[2].v_samp_factor = 1;
344
27.3k
  if (cinfo->num_components > 3)
345
962
    cinfo->comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
346
27.3k
}
347
348
349
static int getSubsamp(j_decompress_ptr dinfo)
350
53.7k
{
351
53.7k
  int retval = -1, i, k;
352
353
  /* The sampling factors actually have no meaning with grayscale JPEG files,
354
     and in fact it's possible to generate grayscale JPEGs with sampling
355
     factors > 1 (even though those sampling factors are ignored by the
356
     decompressor.)  Thus, we need to treat grayscale as a special case. */
357
53.7k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
358
29.3k
    return TJSAMP_GRAY;
359
360
88.5k
  for (i = 0; i < TJ_NUMSAMP; i++) {
361
85.0k
    if (dinfo->num_components == pixelsize[i] ||
362
85.0k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
363
9.40k
          dinfo->jpeg_color_space == JCS_CMYK) &&
364
78.7k
         pixelsize[i] == 3 && dinfo->num_components == 4)) {
365
78.7k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
366
78.7k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
367
23.4k
        int match = 0;
368
369
71.2k
        for (k = 1; k < dinfo->num_components; k++) {
370
47.8k
          int href = 1, vref = 1;
371
372
47.8k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
373
47.8k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
374
951
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
375
951
          }
376
47.8k
          if (dinfo->comp_info[k].h_samp_factor == href &&
377
47.8k
              dinfo->comp_info[k].v_samp_factor == vref)
378
42.5k
            match++;
379
47.8k
        }
380
23.4k
        if (match == dinfo->num_components - 1) {
381
19.9k
          retval = i;  break;
382
19.9k
        }
383
23.4k
      }
384
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
385
         in non-standard ways. */
386
58.7k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
387
58.7k
          dinfo->comp_info[0].v_samp_factor == 2 &&
388
58.7k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
389
16.9k
        int match = 0;
390
391
51.2k
        for (k = 1; k < dinfo->num_components; k++) {
392
34.3k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
393
394
34.3k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
395
34.3k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
396
566
            href = vref = 2;
397
566
          }
398
34.3k
          if (dinfo->comp_info[k].h_samp_factor == href &&
399
34.3k
              dinfo->comp_info[k].v_samp_factor == vref)
400
2.34k
            match++;
401
34.3k
        }
402
16.9k
        if (match == dinfo->num_components - 1) {
403
905
          retval = i;  break;
404
905
        }
405
16.9k
      }
406
      /* Handle 4:4:4 images whose sampling factors are specified in
407
         non-standard ways. */
408
57.8k
      if (dinfo->comp_info[0].h_samp_factor *
409
57.8k
          dinfo->comp_info[0].v_samp_factor <=
410
57.8k
          D_MAX_BLOCKS_IN_MCU / pixelsize[i] && i == TJSAMP_444) {
411
6.16k
        int match = 0;
412
18.8k
        for (k = 1; k < dinfo->num_components; k++) {
413
12.8k
          if (dinfo->comp_info[k].h_samp_factor ==
414
12.8k
              dinfo->comp_info[0].h_samp_factor &&
415
12.8k
              dinfo->comp_info[k].v_samp_factor ==
416
3.08k
              dinfo->comp_info[0].v_samp_factor)
417
976
            match++;
418
12.8k
          if (match == dinfo->num_components - 1) {
419
182
            retval = i;  break;
420
182
          }
421
12.8k
        }
422
6.16k
      }
423
57.8k
    }
424
85.0k
  }
425
24.4k
  return retval;
426
53.7k
}
427
428
429
/*************************** General API functions ***************************/
430
431
/* TurboJPEG 2.0+ */
432
DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
433
0
{
434
0
  tjinstance *this = (tjinstance *)handle;
435
436
0
  if (this && this->isInstanceError) {
437
0
    this->isInstanceError = FALSE;
438
0
    return this->errStr;
439
0
  } else
440
0
    return errStr;
441
0
}
442
443
444
/* TurboJPEG 1.0+ */
445
DLLEXPORT char *tjGetErrorStr(void)
446
0
{
447
0
  return errStr;
448
0
}
449
450
451
/* TurboJPEG 2.0+ */
452
DLLEXPORT int tjGetErrorCode(tjhandle handle)
453
0
{
454
0
  tjinstance *this = (tjinstance *)handle;
455
456
0
  if (this && this->jerr.warning) return TJERR_WARNING;
457
0
  else return TJERR_FATAL;
458
0
}
459
460
461
/* TurboJPEG 1.0+ */
462
DLLEXPORT int tjDestroy(tjhandle handle)
463
123k
{
464
123k
  GET_INSTANCE(handle);
465
466
123k
  if (setjmp(this->jerr.setjmp_buffer)) return -1;
467
123k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
468
123k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
469
123k
  free(this);
470
123k
  return 0;
471
123k
}
472
473
474
/* These are exposed mainly because Windows can't malloc() and free() across
475
   DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
476
   with turbojpeg.dll for compatibility reasons.  However, these functions
477
   can potentially be used for other purposes by different implementations. */
478
479
/* TurboJPEG 1.2+ */
480
DLLEXPORT void tjFree(unsigned char *buf)
481
47.2k
{
482
47.2k
  free(buf);
483
47.2k
}
484
485
486
/* TurboJPEG 1.2+ */
487
DLLEXPORT unsigned char *tjAlloc(int bytes)
488
0
{
489
0
  return (unsigned char *)malloc(bytes);
490
0
}
491
492
493
/******************************** Compressor *********************************/
494
495
static tjhandle _tjInitCompress(tjinstance *this)
496
243k
{
497
243k
  static unsigned char buffer[1];
498
243k
  unsigned char *buf = buffer;
499
243k
  unsigned long size = 1;
500
501
  /* This is also straight out of example.txt */
502
243k
  this->cinfo.err = jpeg_std_error(&this->jerr.pub);
503
243k
  this->jerr.pub.error_exit = my_error_exit;
504
243k
  this->jerr.pub.output_message = my_output_message;
505
243k
  this->jerr.emit_message = this->jerr.pub.emit_message;
506
243k
  this->jerr.pub.emit_message = my_emit_message;
507
243k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
508
243k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
509
243k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
510
511
243k
  if (setjmp(this->jerr.setjmp_buffer)) {
512
    /* If we get here, the JPEG code has signaled an error. */
513
0
    free(this);
514
0
    return NULL;
515
0
  }
516
517
243k
  jpeg_create_compress(&this->cinfo);
518
  /* Make an initial call so it will create the destination manager */
519
243k
  jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
520
521
243k
  this->init |= COMPRESS;
522
243k
  return (tjhandle)this;
523
243k
}
524
525
/* TurboJPEG 1.0+ */
526
DLLEXPORT tjhandle tjInitCompress(void)
527
92.4k
{
528
92.4k
  tjinstance *this = NULL;
529
530
92.4k
  if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
531
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX,
532
0
             "tjInitCompress(): Memory allocation failure");
533
0
    return NULL;
534
0
  }
535
92.4k
  memset(this, 0, sizeof(tjinstance));
536
92.4k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
537
92.4k
  return _tjInitCompress(this);
538
92.4k
}
539
540
541
/* TurboJPEG 1.2+ */
542
DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
543
105k
{
544
105k
  unsigned long long retval = 0;
545
105k
  int mcuw, mcuh, chromasf;
546
547
105k
  if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP)
548
105k
    THROWG("tjBufSize(): Invalid argument");
549
550
  /* This allows for rare corner cases in which a JPEG image can actually be
551
     larger than the uncompressed input (we wouldn't mention it if it hadn't
552
     happened before.) */
553
105k
  mcuw = tjMCUWidth[jpegSubsamp];
554
105k
  mcuh = tjMCUHeight[jpegSubsamp];
555
105k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
556
105k
  retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
557
105k
  if (retval > (unsigned long long)((unsigned long)-1))
558
105k
    THROWG("tjBufSize(): Image is too large");
559
560
105k
bailout:
561
105k
  return (unsigned long)retval;
562
105k
}
563
564
/* TurboJPEG 1.0+ */
565
DLLEXPORT unsigned long TJBUFSIZE(int width, int height)
566
0
{
567
0
  unsigned long long retval = 0;
568
569
0
  if (width < 1 || height < 1)
570
0
    THROWG("TJBUFSIZE(): Invalid argument");
571
572
  /* This allows for rare corner cases in which a JPEG image can actually be
573
     larger than the uncompressed input (we wouldn't mention it if it hadn't
574
     happened before.) */
575
0
  retval = PAD(width, 16) * PAD(height, 16) * 6ULL + 2048ULL;
576
0
  if (retval > (unsigned long long)((unsigned long)-1))
577
0
    THROWG("TJBUFSIZE(): Image is too large");
578
579
0
bailout:
580
0
  return (unsigned long)retval;
581
0
}
582
583
584
/* TurboJPEG 1.4+ */
585
DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
586
                                      int subsamp)
587
28.4k
{
588
28.4k
  unsigned long long retval = 0;
589
28.4k
  int nc, i;
590
591
28.4k
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
592
28.4k
    THROWG("tjBufSizeYUV2(): Invalid argument");
593
594
28.4k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
595
92.3k
  for (i = 0; i < nc; i++) {
596
63.9k
    int pw = tjPlaneWidth(i, width, subsamp);
597
63.9k
    int stride = PAD(pw, align);
598
63.9k
    int ph = tjPlaneHeight(i, height, subsamp);
599
600
63.9k
    if (pw < 0 || ph < 0) return -1;
601
63.9k
    else retval += (unsigned long long)stride * ph;
602
63.9k
  }
603
28.4k
  if (retval > (unsigned long long)((unsigned long)-1))
604
28.4k
    THROWG("tjBufSizeYUV2(): Image is too large");
605
606
28.4k
bailout:
607
28.4k
  return (unsigned long)retval;
608
28.4k
}
609
610
/* TurboJPEG 1.2+ */
611
DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
612
0
{
613
0
  return tjBufSizeYUV2(width, 4, height, subsamp);
614
0
}
615
616
/* TurboJPEG 1.1+ */
617
DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
618
0
{
619
0
  return tjBufSizeYUV(width, height, subsamp);
620
0
}
621
622
623
/* TurboJPEG 1.4+ */
624
DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
625
162k
{
626
162k
  unsigned long long pw, retval = 0;
627
162k
  int nc;
628
629
162k
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
630
162k
    THROWG("tjPlaneWidth(): Invalid argument");
631
162k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
632
162k
  if (componentID < 0 || componentID >= nc)
633
162k
    THROWG("tjPlaneWidth(): Invalid argument");
634
635
162k
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
636
162k
  if (componentID == 0)
637
86.9k
    retval = pw;
638
75.0k
  else
639
75.0k
    retval = pw * 8 / tjMCUWidth[subsamp];
640
641
162k
  if (retval > (unsigned long long)INT_MAX)
642
162k
    THROWG("tjPlaneWidth(): Width is too large");
643
644
162k
bailout:
645
162k
  return (int)retval;
646
162k
}
647
648
649
/* TurboJPEG 1.4+ */
650
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
651
162k
{
652
162k
  unsigned long long ph, retval = 0;
653
162k
  int nc;
654
655
162k
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
656
162k
    THROWG("tjPlaneHeight(): Invalid argument");
657
162k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
658
162k
  if (componentID < 0 || componentID >= nc)
659
162k
    THROWG("tjPlaneHeight(): Invalid argument");
660
661
162k
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
662
162k
  if (componentID == 0)
663
86.9k
    retval = ph;
664
75.0k
  else
665
75.0k
    retval = ph * 8 / tjMCUHeight[subsamp];
666
667
162k
  if (retval > (unsigned long long)INT_MAX)
668
162k
    THROWG("tjPlaneHeight(): Height is too large");
669
670
162k
bailout:
671
162k
  return (int)retval;
672
162k
}
673
674
675
/* TurboJPEG 1.4+ */
676
DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
677
                                       int height, int subsamp)
678
0
{
679
0
  unsigned long long retval = 0;
680
0
  int pw, ph;
681
682
0
  if (width < 1 || height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
683
0
    THROWG("tjPlaneSizeYUV(): Invalid argument");
684
685
0
  pw = tjPlaneWidth(componentID, width, subsamp);
686
0
  ph = tjPlaneHeight(componentID, height, subsamp);
687
0
  if (pw < 0 || ph < 0) return -1;
688
689
0
  if (stride == 0) stride = pw;
690
0
  else stride = abs(stride);
691
692
0
  retval = (unsigned long long)stride * (ph - 1) + pw;
693
0
  if (retval > (unsigned long long)((unsigned long)-1))
694
0
    THROWG("tjPlaneSizeYUV(): Image is too large");
695
696
0
bailout:
697
0
  return (unsigned long)retval;
698
0
}
699
700
701
/* TurboJPEG 1.2+ */
702
DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
703
                          int width, int pitch, int height, int pixelFormat,
704
                          unsigned char **jpegBuf, unsigned long *jpegSize,
705
                          int jpegSubsamp, int jpegQual, int flags)
706
13.6k
{
707
13.6k
  int i, retval = 0;
708
13.6k
  boolean alloc = TRUE;
709
13.6k
  JSAMPROW *row_pointer = NULL;
710
711
13.6k
  GET_CINSTANCE(handle)
712
13.6k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
713
13.6k
  if ((this->init & COMPRESS) == 0)
714
13.6k
    THROW("tjCompress2(): Instance has not been initialized for compression");
715
716
13.6k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
717
13.6k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
718
13.6k
      jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP ||
719
13.6k
      jpegQual < 0 || jpegQual > 100)
720
13.6k
    THROW("tjCompress2(): Invalid argument");
721
722
13.6k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
723
724
13.6k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * height)) == NULL)
725
13.6k
    THROW("tjCompress2(): Memory allocation failure");
726
727
13.6k
  if (setjmp(this->jerr.setjmp_buffer)) {
728
    /* If we get here, the JPEG code has signaled an error. */
729
63
    retval = -1;  goto bailout;
730
63
  }
731
732
13.5k
  cinfo->image_width = width;
733
13.5k
  cinfo->image_height = height;
734
735
13.5k
#ifndef NO_PUTENV
736
13.5k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
737
13.5k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
738
13.5k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
739
13.5k
#endif
740
741
13.5k
  if (flags & TJFLAG_NOREALLOC) {
742
11.6k
    alloc = FALSE;  *jpegSize = tjBufSize(width, height, jpegSubsamp);
743
11.6k
  }
744
13.5k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
745
13.5k
  setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags);
746
747
13.5k
  jpeg_start_compress(cinfo, TRUE);
748
45.9M
  for (i = 0; i < height; i++) {
749
45.9M
    if (flags & TJFLAG_BOTTOMUP)
750
6.68M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
751
39.2M
    else
752
39.2M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
753
45.9M
  }
754
27.1k
  while (cinfo->next_scanline < cinfo->image_height)
755
13.5k
    jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
756
13.5k
                         cinfo->image_height - cinfo->next_scanline);
757
13.5k
  jpeg_finish_compress(cinfo);
758
759
13.6k
bailout:
760
13.6k
  if (cinfo->global_state > CSTATE_START) {
761
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
762
0
    jpeg_abort_compress(cinfo);
763
0
  }
764
13.6k
  free(row_pointer);
765
13.6k
  if (this->jerr.warning) retval = -1;
766
13.6k
  this->jerr.stopOnWarning = FALSE;
767
13.6k
  return retval;
768
13.5k
}
769
770
/* TurboJPEG 1.0+ */
771
DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
772
                         int pitch, int height, int pixelSize,
773
                         unsigned char *jpegBuf, unsigned long *jpegSize,
774
                         int jpegSubsamp, int jpegQual, int flags)
775
0
{
776
0
  int retval = 0;
777
0
  unsigned long size;
778
779
0
  if (flags & TJ_YUV) {
780
0
    size = tjBufSizeYUV(width, height, jpegSubsamp);
781
0
    retval = tjEncodeYUV2(handle, srcBuf, width, pitch, height,
782
0
                          getPixelFormat(pixelSize, flags), jpegBuf,
783
0
                          jpegSubsamp, flags);
784
0
  } else {
785
0
    retval = tjCompress2(handle, srcBuf, width, pitch, height,
786
0
                         getPixelFormat(pixelSize, flags), &jpegBuf, &size,
787
0
                         jpegSubsamp, jpegQual, flags | TJFLAG_NOREALLOC);
788
0
  }
789
0
  *jpegSize = size;
790
0
  return retval;
791
0
}
792
793
794
/* TurboJPEG 1.4+ */
795
DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
796
                                int width, int pitch, int height,
797
                                int pixelFormat, unsigned char **dstPlanes,
798
                                int *strides, int subsamp, int flags)
799
21.1k
{
800
21.1k
  JSAMPROW *row_pointer = NULL;
801
21.1k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
802
21.1k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
803
21.1k
  JSAMPROW *outbuf[MAX_COMPONENTS];
804
21.1k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
805
21.1k
  JSAMPLE *ptr;
806
21.1k
  jpeg_component_info *compptr;
807
808
21.1k
  GET_CINSTANCE(handle);
809
21.1k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
810
811
233k
  for (i = 0; i < MAX_COMPONENTS; i++) {
812
211k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
813
211k
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
814
211k
  }
815
816
21.1k
  if ((this->init & COMPRESS) == 0)
817
21.1k
    THROW("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
818
819
21.1k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
820
21.1k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
821
21.1k
      !dstPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP)
822
21.1k
    THROW("tjEncodeYUVPlanes(): Invalid argument");
823
21.1k
  if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
824
21.1k
    THROW("tjEncodeYUVPlanes(): Invalid argument");
825
826
21.1k
  if (pixelFormat == TJPF_CMYK)
827
21.1k
    THROW("tjEncodeYUVPlanes(): Cannot generate YUV images from packed-pixel CMYK images");
828
829
21.1k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
830
831
21.1k
  if (setjmp(this->jerr.setjmp_buffer)) {
832
    /* If we get here, the JPEG code has signaled an error. */
833
57
    retval = -1;  goto bailout;
834
57
  }
835
836
21.1k
  cinfo->image_width = width;
837
21.1k
  cinfo->image_height = height;
838
839
21.1k
#ifndef NO_PUTENV
840
21.1k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
841
21.1k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
842
21.1k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
843
21.1k
#endif
844
845
21.1k
  setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags);
846
847
  /* Execute only the parts of jpeg_start_compress() that we need.  If we
848
     were to call the whole jpeg_start_compress() function, then it would try
849
     to write the file headers, which could overflow the output buffer if the
850
     YUV image were very small. */
851
21.1k
  if (cinfo->global_state != CSTATE_START)
852
21.1k
    THROW("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
853
21.1k
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
854
21.1k
  jinit_c_master_control(cinfo, FALSE);
855
21.1k
  jinit_color_converter(cinfo);
856
21.1k
  jinit_downsampler(cinfo);
857
21.1k
  (*cinfo->cconvert->start_pass) (cinfo);
858
859
21.1k
  pw0 = PAD(width, cinfo->max_h_samp_factor);
860
21.1k
  ph0 = PAD(height, cinfo->max_v_samp_factor);
861
862
21.1k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
863
21.1k
    THROW("tjEncodeYUVPlanes(): Memory allocation failure");
864
60.5M
  for (i = 0; i < height; i++) {
865
60.5M
    if (flags & TJFLAG_BOTTOMUP)
866
10.1M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
867
50.3M
    else
868
50.3M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
869
60.5M
  }
870
21.1k
  if (height < ph0)
871
3.90k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
872
873
71.0k
  for (i = 0; i < cinfo->num_components; i++) {
874
49.9k
    compptr = &cinfo->comp_info[i];
875
49.9k
    _tmpbuf[i] = (JSAMPLE *)malloc(
876
49.9k
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
877
49.9k
          compptr->h_samp_factor, 32) *
878
49.9k
      cinfo->max_v_samp_factor + 32);
879
49.9k
    if (!_tmpbuf[i])
880
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
881
49.9k
    tmpbuf[i] =
882
49.9k
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
883
49.9k
    if (!tmpbuf[i])
884
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
885
110k
    for (row = 0; row < cinfo->max_v_samp_factor; row++) {
886
60.7k
      unsigned char *_tmpbuf_aligned =
887
60.7k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
888
889
60.7k
      tmpbuf[i][row] = &_tmpbuf_aligned[
890
60.7k
        PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
891
60.7k
            compptr->h_samp_factor, 32) * row];
892
60.7k
    }
893
49.9k
    _tmpbuf2[i] =
894
49.9k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
895
49.9k
                        compptr->v_samp_factor + 32);
896
49.9k
    if (!_tmpbuf2[i])
897
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
898
49.9k
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
899
49.9k
    if (!tmpbuf2[i])
900
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
901
103k
    for (row = 0; row < compptr->v_samp_factor; row++) {
902
53.5k
      unsigned char *_tmpbuf2_aligned =
903
53.5k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
904
905
53.5k
      tmpbuf2[i][row] =
906
53.5k
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
907
53.5k
    }
908
49.9k
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
909
49.9k
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
910
49.9k
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
911
49.9k
    if (!outbuf[i])
912
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
913
49.9k
    ptr = dstPlanes[i];
914
131M
    for (row = 0; row < ph[i]; row++) {
915
131M
      outbuf[i][row] = ptr;
916
131M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
917
131M
    }
918
49.9k
  }
919
920
21.1k
  if (setjmp(this->jerr.setjmp_buffer)) {
921
    /* If we get here, the JPEG code has signaled an error. */
922
0
    retval = -1;  goto bailout;
923
0
  }
924
925
55.5M
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
926
55.4M
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
927
55.4M
                                       cinfo->max_v_samp_factor);
928
55.4M
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
929
182M
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
930
126M
         i++, compptr++)
931
126M
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
932
126M
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
933
126M
        compptr->v_samp_factor, pw[i]);
934
55.4M
  }
935
21.1k
  cinfo->next_scanline += height;
936
21.1k
  jpeg_abort_compress(cinfo);
937
938
21.1k
bailout:
939
21.1k
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
940
21.1k
  free(row_pointer);
941
233k
  for (i = 0; i < MAX_COMPONENTS; i++) {
942
211k
    free(tmpbuf[i]);
943
211k
    free(_tmpbuf[i]);
944
211k
    free(tmpbuf2[i]);
945
211k
    free(_tmpbuf2[i]);
946
211k
    free(outbuf[i]);
947
211k
  }
948
21.1k
  if (this->jerr.warning) retval = -1;
949
21.1k
  this->jerr.stopOnWarning = FALSE;
950
21.1k
  return retval;
951
21.1k
}
952
953
/* TurboJPEG 1.4+ */
954
DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
955
                           int width, int pitch, int height, int pixelFormat,
956
                           unsigned char *dstBuf, int align, int subsamp,
957
                           int flags)
958
21.1k
{
959
21.1k
  unsigned char *dstPlanes[3];
960
21.1k
  int pw0, ph0, strides[3], retval = -1;
961
21.1k
  tjinstance *this = (tjinstance *)handle;
962
963
21.1k
  if (!this) THROWG("tjEncodeYUV3(): Invalid handle");
964
21.1k
  this->isInstanceError = FALSE;
965
966
21.1k
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
967
21.1k
      !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
968
21.1k
    THROW("tjEncodeYUV3(): Invalid argument");
969
970
21.1k
  pw0 = tjPlaneWidth(0, width, subsamp);
971
21.1k
  ph0 = tjPlaneHeight(0, height, subsamp);
972
21.1k
  dstPlanes[0] = dstBuf;
973
21.1k
  strides[0] = PAD(pw0, align);
974
21.1k
  if (subsamp == TJSAMP_GRAY) {
975
6.75k
    strides[1] = strides[2] = 0;
976
6.75k
    dstPlanes[1] = dstPlanes[2] = NULL;
977
14.4k
  } else {
978
14.4k
    int pw1 = tjPlaneWidth(1, width, subsamp);
979
14.4k
    int ph1 = tjPlaneHeight(1, height, subsamp);
980
981
14.4k
    strides[1] = strides[2] = PAD(pw1, align);
982
14.4k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
983
14.4k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
984
14.4k
  }
985
986
21.1k
  return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
987
21.1k
                           dstPlanes, strides, subsamp, flags);
988
989
0
bailout:
990
0
  return retval;
991
21.1k
}
992
993
/* TurboJPEG 1.2+ */
994
DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
995
                           int pitch, int height, int pixelFormat,
996
                           unsigned char *dstBuf, int subsamp, int flags)
997
0
{
998
0
  return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
999
0
                      dstBuf, 4, subsamp, flags);
1000
0
}
1001
1002
/* TurboJPEG 1.1+ */
1003
DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
1004
                          int pitch, int height, int pixelSize,
1005
                          unsigned char *dstBuf, int subsamp, int flags)
1006
0
{
1007
0
  return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1008
0
                      getPixelFormat(pixelSize, flags), dstBuf, subsamp,
1009
0
                      flags);
1010
0
}
1011
1012
1013
/* TurboJPEG 1.4+ */
1014
DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
1015
                                      const unsigned char **srcPlanes,
1016
                                      int width, const int *strides,
1017
                                      int height, int subsamp,
1018
                                      unsigned char **jpegBuf,
1019
                                      unsigned long *jpegSize, int jpegQual,
1020
                                      int flags)
1021
21.1k
{
1022
21.1k
  int i, row, retval = 0;
1023
21.1k
  boolean alloc = TRUE;
1024
21.1k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1025
21.1k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1026
21.1k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1027
21.1k
  JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1028
1029
21.1k
  GET_CINSTANCE(handle)
1030
21.1k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1031
1032
232k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1033
211k
    tmpbuf[i] = NULL;  inbuf[i] = NULL;
1034
211k
  }
1035
1036
21.1k
  if ((this->init & COMPRESS) == 0)
1037
21.1k
    THROW("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
1038
1039
21.1k
  if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
1040
21.1k
      subsamp < 0 || subsamp >= TJ_NUMSAMP || jpegBuf == NULL ||
1041
21.1k
      jpegSize == NULL || jpegQual < 0 || jpegQual > 100)
1042
21.1k
    THROW("tjCompressFromYUVPlanes(): Invalid argument");
1043
21.1k
  if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1044
21.1k
    THROW("tjCompressFromYUVPlanes(): Invalid argument");
1045
1046
21.1k
  if (setjmp(this->jerr.setjmp_buffer)) {
1047
    /* If we get here, the JPEG code has signaled an error. */
1048
0
    retval = -1;  goto bailout;
1049
0
  }
1050
1051
21.1k
  cinfo->image_width = width;
1052
21.1k
  cinfo->image_height = height;
1053
1054
21.1k
#ifndef NO_PUTENV
1055
21.1k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1056
21.1k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1057
21.1k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1058
21.1k
#endif
1059
1060
21.1k
  if (flags & TJFLAG_NOREALLOC) {
1061
21.1k
    alloc = FALSE;  *jpegSize = tjBufSize(width, height, subsamp);
1062
21.1k
  }
1063
21.1k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1064
21.1k
  setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags);
1065
21.1k
  cinfo->raw_data_in = TRUE;
1066
1067
21.1k
  jpeg_start_compress(cinfo, TRUE);
1068
71.0k
  for (i = 0; i < cinfo->num_components; i++) {
1069
49.9k
    jpeg_component_info *compptr = &cinfo->comp_info[i];
1070
49.9k
    int ih;
1071
1072
49.9k
    iw[i] = compptr->width_in_blocks * DCTSIZE;
1073
49.9k
    ih = compptr->height_in_blocks * DCTSIZE;
1074
49.9k
    pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
1075
49.9k
            compptr->h_samp_factor / cinfo->max_h_samp_factor;
1076
49.9k
    ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
1077
49.9k
            compptr->v_samp_factor / cinfo->max_v_samp_factor;
1078
49.9k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1079
49.9k
    th[i] = compptr->v_samp_factor * DCTSIZE;
1080
49.9k
    tmpbufsize += iw[i] * th[i];
1081
49.9k
    if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1082
49.9k
      THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
1083
49.9k
    ptr = (JSAMPLE *)srcPlanes[i];
1084
131M
    for (row = 0; row < ph[i]; row++) {
1085
131M
      inbuf[i][row] = ptr;
1086
131M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1087
131M
    }
1088
49.9k
  }
1089
21.1k
  if (usetmpbuf) {
1090
21.0k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1091
21.0k
      THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
1092
21.0k
    ptr = _tmpbuf;
1093
70.8k
    for (i = 0; i < cinfo->num_components; i++) {
1094
49.7k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1095
49.7k
        THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
1096
476k
      for (row = 0; row < th[i]; row++) {
1097
426k
        tmpbuf[i][row] = ptr;
1098
426k
        ptr += iw[i];
1099
426k
      }
1100
49.7k
    }
1101
21.0k
  }
1102
1103
21.1k
  if (setjmp(this->jerr.setjmp_buffer)) {
1104
    /* If we get here, the JPEG code has signaled an error. */
1105
0
    retval = -1;  goto bailout;
1106
0
  }
1107
1108
6.96M
  for (row = 0; row < (int)cinfo->image_height;
1109
6.94M
       row += cinfo->max_v_samp_factor * DCTSIZE) {
1110
6.94M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1111
6.94M
    int crow[MAX_COMPONENTS];
1112
1113
22.8M
    for (i = 0; i < cinfo->num_components; i++) {
1114
15.8M
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1115
1116
15.8M
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1117
15.8M
      if (usetmpbuf) {
1118
15.8M
        int j, k;
1119
1120
147M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1121
131M
          memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1122
          /* Duplicate last sample in row to fill out MCU */
1123
995M
          for (k = pw[i]; k < iw[i]; k++)
1124
863M
            tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1125
131M
        }
1126
        /* Duplicate last row to fill out MCU */
1127
16.1M
        for (j = ph[i] - crow[i]; j < th[i]; j++)
1128
261k
          memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1129
15.8M
        yuvptr[i] = tmpbuf[i];
1130
15.8M
      } else
1131
704
        yuvptr[i] = &inbuf[i][crow[i]];
1132
15.8M
    }
1133
6.94M
    jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1134
6.94M
  }
1135
21.1k
  jpeg_finish_compress(cinfo);
1136
1137
21.1k
bailout:
1138
21.1k
  if (cinfo->global_state > CSTATE_START) {
1139
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
1140
0
    jpeg_abort_compress(cinfo);
1141
0
  }
1142
232k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1143
211k
    free(tmpbuf[i]);
1144
211k
    free(inbuf[i]);
1145
211k
  }
1146
21.1k
  free(_tmpbuf);
1147
21.1k
  if (this->jerr.warning) retval = -1;
1148
21.1k
  this->jerr.stopOnWarning = FALSE;
1149
21.1k
  return retval;
1150
21.1k
}
1151
1152
/* TurboJPEG 1.4+ */
1153
DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
1154
                                int width, int align, int height, int subsamp,
1155
                                unsigned char **jpegBuf,
1156
                                unsigned long *jpegSize, int jpegQual,
1157
                                int flags)
1158
21.1k
{
1159
21.1k
  const unsigned char *srcPlanes[3];
1160
21.1k
  int pw0, ph0, strides[3], retval = -1;
1161
21.1k
  tjinstance *this = (tjinstance *)handle;
1162
1163
21.1k
  if (!this) THROWG("tjCompressFromYUV(): Invalid handle");
1164
21.1k
  this->isInstanceError = FALSE;
1165
1166
21.1k
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1167
21.1k
      height <= 0 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1168
21.1k
    THROW("tjCompressFromYUV(): Invalid argument");
1169
1170
21.1k
  pw0 = tjPlaneWidth(0, width, subsamp);
1171
21.1k
  ph0 = tjPlaneHeight(0, height, subsamp);
1172
21.1k
  srcPlanes[0] = srcBuf;
1173
21.1k
  strides[0] = PAD(pw0, align);
1174
21.1k
  if (subsamp == TJSAMP_GRAY) {
1175
6.74k
    strides[1] = strides[2] = 0;
1176
6.74k
    srcPlanes[1] = srcPlanes[2] = NULL;
1177
14.3k
  } else {
1178
14.3k
    int pw1 = tjPlaneWidth(1, width, subsamp);
1179
14.3k
    int ph1 = tjPlaneHeight(1, height, subsamp);
1180
1181
14.3k
    strides[1] = strides[2] = PAD(pw1, align);
1182
14.3k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1183
14.3k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1184
14.3k
  }
1185
1186
21.1k
  return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1187
21.1k
                                 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1188
1189
0
bailout:
1190
0
  return retval;
1191
21.1k
}
1192
1193
1194
/******************************* Decompressor ********************************/
1195
1196
static tjhandle _tjInitDecompress(tjinstance *this)
1197
48.8k
{
1198
48.8k
  static unsigned char buffer[1];
1199
1200
  /* This is also straight out of example.txt */
1201
48.8k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1202
48.8k
  this->jerr.pub.error_exit = my_error_exit;
1203
48.8k
  this->jerr.pub.output_message = my_output_message;
1204
48.8k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1205
48.8k
  this->jerr.pub.emit_message = my_emit_message;
1206
48.8k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1207
48.8k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1208
48.8k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1209
1210
48.8k
  if (setjmp(this->jerr.setjmp_buffer)) {
1211
    /* If we get here, the JPEG code has signaled an error. */
1212
0
    free(this);
1213
0
    return NULL;
1214
0
  }
1215
1216
48.8k
  jpeg_create_decompress(&this->dinfo);
1217
  /* Make an initial call so it will create the source manager */
1218
48.8k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1219
1220
48.8k
  this->init |= DECOMPRESS;
1221
48.8k
  return (tjhandle)this;
1222
48.8k
}
1223
1224
/* TurboJPEG 1.0+ */
1225
DLLEXPORT tjhandle tjInitDecompress(void)
1226
20.0k
{
1227
20.0k
  tjinstance *this;
1228
1229
20.0k
  if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
1230
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX,
1231
0
             "tjInitDecompress(): Memory allocation failure");
1232
0
    return NULL;
1233
0
  }
1234
20.0k
  memset(this, 0, sizeof(tjinstance));
1235
20.0k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
1236
20.0k
  return _tjInitDecompress(this);
1237
20.0k
}
1238
1239
1240
/* TurboJPEG 1.4+ */
1241
DLLEXPORT int tjDecompressHeader3(tjhandle handle,
1242
                                  const unsigned char *jpegBuf,
1243
                                  unsigned long jpegSize, int *width,
1244
                                  int *height, int *jpegSubsamp,
1245
                                  int *jpegColorspace)
1246
15.5k
{
1247
15.5k
  int retval = 0;
1248
1249
15.5k
  GET_DINSTANCE(handle);
1250
15.5k
  if ((this->init & DECOMPRESS) == 0)
1251
15.5k
    THROW("tjDecompressHeader3(): Instance has not been initialized for decompression");
1252
1253
15.5k
  if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL ||
1254
15.5k
      jpegSubsamp == NULL || jpegColorspace == NULL)
1255
15.5k
    THROW("tjDecompressHeader3(): Invalid argument");
1256
1257
15.5k
  if (setjmp(this->jerr.setjmp_buffer)) {
1258
    /* If we get here, the JPEG code has signaled an error. */
1259
2.11k
    return -1;
1260
2.11k
  }
1261
1262
13.4k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1263
1264
  /* jpeg_read_header() calls jpeg_abort() and returns JPEG_HEADER_TABLES_ONLY
1265
     if the datastream is a tables-only datastream.  Since we aren't using a
1266
     suspending data source, the only other value it can return is
1267
     JPEG_HEADER_OK. */
1268
13.4k
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1269
1.96k
    return 0;
1270
1271
11.4k
  *width = dinfo->image_width;
1272
11.4k
  *height = dinfo->image_height;
1273
11.4k
  *jpegSubsamp = getSubsamp(dinfo);
1274
11.4k
  switch (dinfo->jpeg_color_space) {
1275
6.50k
  case JCS_GRAYSCALE:  *jpegColorspace = TJCS_GRAY;  break;
1276
123
  case JCS_RGB:        *jpegColorspace = TJCS_RGB;  break;
1277
4.56k
  case JCS_YCbCr:      *jpegColorspace = TJCS_YCbCr;  break;
1278
183
  case JCS_CMYK:       *jpegColorspace = TJCS_CMYK;  break;
1279
37
  case JCS_YCCK:       *jpegColorspace = TJCS_YCCK;  break;
1280
20
  default:             *jpegColorspace = -1;  break;
1281
11.4k
  }
1282
1283
11.4k
  jpeg_abort_decompress(dinfo);
1284
1285
11.4k
  if (*jpegSubsamp < 0)
1286
9.95k
    THROW("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1287
9.95k
  if (*jpegColorspace < 0)
1288
9.95k
    THROW("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1289
9.95k
  if (*width < 1 || *height < 1)
1290
9.95k
    THROW("tjDecompressHeader3(): Invalid data returned in header");
1291
1292
11.4k
bailout:
1293
11.4k
  if (this->jerr.warning) retval = -1;
1294
11.4k
  return retval;
1295
9.95k
}
1296
1297
/* TurboJPEG 1.1+ */
1298
DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
1299
                                  unsigned long jpegSize, int *width,
1300
                                  int *height, int *jpegSubsamp)
1301
0
{
1302
0
  int jpegColorspace;
1303
1304
0
  return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1305
0
                             jpegSubsamp, &jpegColorspace);
1306
0
}
1307
1308
/* TurboJPEG 1.0+ */
1309
DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
1310
                                 unsigned long jpegSize, int *width,
1311
                                 int *height)
1312
0
{
1313
0
  int jpegSubsamp;
1314
1315
0
  return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1316
0
                             &jpegSubsamp);
1317
0
}
1318
1319
1320
/* TurboJPEG 1.2+ */
1321
DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numScalingFactors)
1322
0
{
1323
0
  if (numScalingFactors == NULL) {
1324
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX,
1325
0
             "tjGetScalingFactors(): Invalid argument");
1326
0
    return NULL;
1327
0
  }
1328
1329
0
  *numScalingFactors = NUMSF;
1330
0
  return (tjscalingfactor *)sf;
1331
0
}
1332
1333
1334
/* TurboJPEG 1.2+ */
1335
DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
1336
                            unsigned long jpegSize, unsigned char *dstBuf,
1337
                            int width, int pitch, int height, int pixelFormat,
1338
                            int flags)
1339
10.4k
{
1340
10.4k
  JSAMPROW *row_pointer = NULL;
1341
10.4k
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
1342
10.4k
  struct my_progress_mgr progress;
1343
1344
10.4k
  GET_DINSTANCE(handle);
1345
10.4k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1346
10.4k
  if ((this->init & DECOMPRESS) == 0)
1347
10.4k
    THROW("tjDecompress2(): Instance has not been initialized for decompression");
1348
1349
10.4k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1350
10.4k
      pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1351
10.4k
    THROW("tjDecompress2(): Invalid argument");
1352
1353
10.4k
#ifndef NO_PUTENV
1354
10.4k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1355
10.4k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1356
10.4k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1357
10.4k
#endif
1358
1359
10.4k
  if (flags & TJFLAG_LIMITSCANS) {
1360
10.4k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
1361
10.4k
    progress.pub.progress_monitor = my_progress_monitor;
1362
10.4k
    progress.this = this;
1363
10.4k
    dinfo->progress = &progress.pub;
1364
10.4k
  } else
1365
0
    dinfo->progress = NULL;
1366
1367
10.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
1368
    /* If we get here, the JPEG code has signaled an error. */
1369
2.98k
    retval = -1;  goto bailout;
1370
2.98k
  }
1371
1372
7.44k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1373
7.44k
  jpeg_read_header(dinfo, TRUE);
1374
7.44k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
1375
7.65k
  if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1376
7.65k
  if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1377
1378
7.44k
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1379
7.44k
  if (width == 0) width = jpegwidth;
1380
7.44k
  if (height == 0) height = jpegheight;
1381
97.3k
  for (i = 0; i < NUMSF; i++) {
1382
97.3k
    scaledw = TJSCALED(jpegwidth, sf[i]);
1383
97.3k
    scaledh = TJSCALED(jpegheight, sf[i]);
1384
97.3k
    if (scaledw <= width && scaledh <= height)
1385
10.4k
      break;
1386
97.3k
  }
1387
7.44k
  if (i >= NUMSF)
1388
7.44k
    THROW("tjDecompress2(): Could not scale down to desired image dimensions");
1389
7.44k
  width = scaledw;  height = scaledh;
1390
7.44k
  dinfo->scale_num = sf[i].num;
1391
7.44k
  dinfo->scale_denom = sf[i].denom;
1392
1393
7.44k
  jpeg_start_decompress(dinfo);
1394
7.44k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1395
1396
7.44k
  if ((row_pointer =
1397
7.44k
       (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL)
1398
7.44k
    THROW("tjDecompress2(): Memory allocation failure");
1399
7.44k
  if (setjmp(this->jerr.setjmp_buffer)) {
1400
    /* If we get here, the JPEG code has signaled an error. */
1401
627
    retval = -1;  goto bailout;
1402
627
  }
1403
33.5M
  for (i = 0; i < (int)dinfo->output_height; i++) {
1404
33.5M
    if (flags & TJFLAG_BOTTOMUP)
1405
27.7M
      row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * (size_t)pitch];
1406
5.74M
    else
1407
5.74M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
1408
33.5M
  }
1409
18.4M
  while (dinfo->output_scanline < dinfo->output_height)
1410
18.4M
    jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1411
18.4M
                        dinfo->output_height - dinfo->output_scanline);
1412
6.81k
  jpeg_finish_decompress(dinfo);
1413
1414
10.4k
bailout:
1415
10.4k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1416
10.4k
  free(row_pointer);
1417
10.4k
  if (this->jerr.warning) retval = -1;
1418
10.4k
  this->jerr.stopOnWarning = FALSE;
1419
10.4k
  return retval;
1420
6.81k
}
1421
1422
/* TurboJPEG 1.0+ */
1423
DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1424
                           unsigned long jpegSize, unsigned char *dstBuf,
1425
                           int width, int pitch, int height, int pixelSize,
1426
                           int flags)
1427
0
{
1428
0
  if (flags & TJ_YUV)
1429
0
    return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1430
0
  else
1431
0
    return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1432
0
                         height, getPixelFormat(pixelSize, flags), flags);
1433
0
}
1434
1435
1436
static void setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1437
                              int pixelFormat, int subsamp, int flags)
1438
2.41k
{
1439
2.41k
  int i;
1440
1441
2.41k
  dinfo->scale_num = dinfo->scale_denom = 1;
1442
1443
2.41k
  if (subsamp == TJSAMP_GRAY) {
1444
1.09k
    dinfo->num_components = dinfo->comps_in_scan = 1;
1445
1.09k
    dinfo->jpeg_color_space = JCS_GRAYSCALE;
1446
1.32k
  } else {
1447
1.32k
    dinfo->num_components = dinfo->comps_in_scan = 3;
1448
1.32k
    dinfo->jpeg_color_space = JCS_YCbCr;
1449
1.32k
  }
1450
1451
2.41k
  dinfo->comp_info = (jpeg_component_info *)
1452
2.41k
    (*dinfo->mem->alloc_small) ((j_common_ptr)dinfo, JPOOL_IMAGE,
1453
2.41k
                                dinfo->num_components *
1454
2.41k
                                sizeof(jpeg_component_info));
1455
1456
7.47k
  for (i = 0; i < dinfo->num_components; i++) {
1457
5.06k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
1458
1459
5.06k
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[subsamp] / 8 : 1;
1460
5.06k
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[subsamp] / 8 : 1;
1461
5.06k
    compptr->component_index = i;
1462
5.06k
    compptr->component_id = i + 1;
1463
5.06k
    compptr->quant_tbl_no = compptr->dc_tbl_no =
1464
5.06k
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
1465
5.06k
    dinfo->cur_comp_info[i] = compptr;
1466
5.06k
  }
1467
2.41k
  dinfo->data_precision = 8;
1468
7.24k
  for (i = 0; i < 2; i++) {
1469
4.83k
    if (dinfo->quant_tbl_ptrs[i] == NULL)
1470
760
      dinfo->quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)dinfo);
1471
4.83k
  }
1472
2.41k
}
1473
1474
1475
static int my_read_markers(j_decompress_ptr dinfo)
1476
2.41k
{
1477
2.41k
  return JPEG_REACHED_SOS;
1478
2.41k
}
1479
1480
static void my_reset_marker_reader(j_decompress_ptr dinfo)
1481
2.41k
{
1482
2.41k
}
1483
1484
/* TurboJPEG 1.4+ */
1485
DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
1486
                                const unsigned char **srcPlanes,
1487
                                const int *strides, int subsamp,
1488
                                unsigned char *dstBuf, int width, int pitch,
1489
                                int height, int pixelFormat, int flags)
1490
1.66k
{
1491
1.66k
  JSAMPROW *row_pointer = NULL;
1492
1.66k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1493
1.66k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
1494
1.66k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1495
1.66k
  JSAMPLE *ptr;
1496
1.66k
  jpeg_component_info *compptr;
1497
1.66k
  int (*old_read_markers) (j_decompress_ptr);
1498
1.66k
  void (*old_reset_marker_reader) (j_decompress_ptr);
1499
1500
1.66k
  GET_DINSTANCE(handle);
1501
1.66k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1502
1503
18.2k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1504
16.6k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;  inbuf[i] = NULL;
1505
16.6k
  }
1506
1507
1.66k
  if ((this->init & DECOMPRESS) == 0)
1508
1.66k
    THROW("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
1509
1510
1.66k
  if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP ||
1511
1.66k
      dstBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1512
1.66k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1513
1.66k
    THROW("tjDecodeYUVPlanes(): Invalid argument");
1514
1.66k
  if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1515
1.66k
    THROW("tjDecodeYUVPlanes(): Invalid argument");
1516
1517
1.66k
  if (setjmp(this->jerr.setjmp_buffer)) {
1518
    /* If we get here, the JPEG code has signaled an error. */
1519
8
    retval = -1;  goto bailout;
1520
8
  }
1521
1522
1.65k
  if (pixelFormat == TJPF_CMYK)
1523
1.65k
    THROW("tjDecodeYUVPlanes(): Cannot decode YUV images into packed-pixel CMYK images.");
1524
1525
1.66k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1526
1.65k
  dinfo->image_width = width;
1527
1.65k
  dinfo->image_height = height;
1528
1529
1.65k
#ifndef NO_PUTENV
1530
1.65k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1531
1.65k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1532
1.65k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1533
1.65k
#endif
1534
1535
1.65k
  dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
1536
1.65k
  dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
1537
1.65k
  dinfo->Se = DCTSIZE2 - 1;
1538
1.65k
  setDecodeDefaults(dinfo, pixelFormat, subsamp, flags);
1539
1.65k
  old_read_markers = dinfo->marker->read_markers;
1540
1.65k
  dinfo->marker->read_markers = my_read_markers;
1541
1.65k
  old_reset_marker_reader = dinfo->marker->reset_marker_reader;
1542
1.65k
  dinfo->marker->reset_marker_reader = my_reset_marker_reader;
1543
1.65k
  jpeg_read_header(dinfo, TRUE);
1544
1.65k
  dinfo->marker->read_markers = old_read_markers;
1545
1.65k
  dinfo->marker->reset_marker_reader = old_reset_marker_reader;
1546
1547
1.65k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
1548
1.65k
  if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1549
1.65k
  dinfo->do_fancy_upsampling = FALSE;
1550
1.65k
  dinfo->Se = DCTSIZE2 - 1;
1551
1.65k
  jinit_master_decompress(dinfo);
1552
1.65k
  (*dinfo->upsample->start_pass) (dinfo);
1553
1554
1.65k
  pw0 = PAD(width, dinfo->max_h_samp_factor);
1555
1.65k
  ph0 = PAD(height, dinfo->max_v_samp_factor);
1556
1557
1.65k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1558
1559
1.65k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1560
1.65k
    THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1561
9.76M
  for (i = 0; i < height; i++) {
1562
9.75M
    if (flags & TJFLAG_BOTTOMUP)
1563
4.38M
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
1564
5.37M
    else
1565
5.37M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
1566
9.75M
  }
1567
1.65k
  if (height < ph0)
1568
606
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1569
1570
5.11k
  for (i = 0; i < dinfo->num_components; i++) {
1571
3.46k
    compptr = &dinfo->comp_info[i];
1572
3.46k
    _tmpbuf[i] =
1573
3.46k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1574
3.46k
                        compptr->v_samp_factor + 32);
1575
3.46k
    if (!_tmpbuf[i])
1576
3.46k
      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1577
3.46k
    tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1578
3.46k
    if (!tmpbuf[i])
1579
3.46k
      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1580
7.52k
    for (row = 0; row < compptr->v_samp_factor; row++) {
1581
4.05k
      unsigned char *_tmpbuf_aligned =
1582
4.05k
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
1583
1584
4.05k
      tmpbuf[i][row] =
1585
4.05k
        &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1586
4.05k
    }
1587
3.46k
    pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
1588
3.46k
    ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1589
3.46k
    inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1590
3.46k
    if (!inbuf[i])
1591
3.46k
      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1592
3.46k
    ptr = (JSAMPLE *)srcPlanes[i];
1593
17.0M
    for (row = 0; row < ph[i]; row++) {
1594
17.0M
      inbuf[i][row] = ptr;
1595
17.0M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1596
17.0M
    }
1597
3.46k
  }
1598
1599
1.65k
  if (setjmp(this->jerr.setjmp_buffer)) {
1600
    /* If we get here, the JPEG code has signaled an error. */
1601
0
    retval = -1;  goto bailout;
1602
0
  }
1603
1604
8.42M
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
1605
8.42M
    JDIMENSION inrow = 0, outrow = 0;
1606
1607
24.0M
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
1608
15.6M
         i++, compptr++)
1609
15.6M
      jcopy_sample_rows(inbuf[i],
1610
15.6M
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
1611
15.6M
        compptr->v_samp_factor, pw[i]);
1612
8.42M
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
1613
8.42M
                                 dinfo->max_v_samp_factor, &row_pointer[row],
1614
8.42M
                                 &outrow, dinfo->max_v_samp_factor);
1615
8.42M
  }
1616
1.65k
  jpeg_abort_decompress(dinfo);
1617
1618
1.66k
bailout:
1619
1.66k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1620
1.66k
  free(row_pointer);
1621
18.2k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1622
16.6k
    free(tmpbuf[i]);
1623
16.6k
    free(_tmpbuf[i]);
1624
16.6k
    free(inbuf[i]);
1625
16.6k
  }
1626
1.66k
  if (this->jerr.warning) retval = -1;
1627
1.66k
  this->jerr.stopOnWarning = FALSE;
1628
1.66k
  return retval;
1629
1.65k
}
1630
1631
/* TurboJPEG 1.4+ */
1632
DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
1633
                          int align, int subsamp, unsigned char *dstBuf,
1634
                          int width, int pitch, int height, int pixelFormat,
1635
                          int flags)
1636
1.66k
{
1637
1.66k
  const unsigned char *srcPlanes[3];
1638
1.66k
  int pw0, ph0, strides[3], retval = -1;
1639
1.66k
  tjinstance *this = (tjinstance *)handle;
1640
1641
1.66k
  if (!this) THROWG("tjDecodeYUV(): Invalid handle");
1642
1.66k
  this->isInstanceError = FALSE;
1643
1644
1.66k
  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || subsamp < 0 ||
1645
1.66k
      subsamp >= TJ_NUMSAMP || width <= 0 || height <= 0)
1646
1.66k
    THROW("tjDecodeYUV(): Invalid argument");
1647
1648
1.66k
  pw0 = tjPlaneWidth(0, width, subsamp);
1649
1.66k
  ph0 = tjPlaneHeight(0, height, subsamp);
1650
1.66k
  srcPlanes[0] = srcBuf;
1651
1.66k
  strides[0] = PAD(pw0, align);
1652
1.66k
  if (subsamp == TJSAMP_GRAY) {
1653
752
    strides[1] = strides[2] = 0;
1654
752
    srcPlanes[1] = srcPlanes[2] = NULL;
1655
910
  } else {
1656
910
    int pw1 = tjPlaneWidth(1, width, subsamp);
1657
910
    int ph1 = tjPlaneHeight(1, height, subsamp);
1658
1659
910
    strides[1] = strides[2] = PAD(pw1, align);
1660
910
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1661
910
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1662
910
  }
1663
1664
1.66k
  return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1665
1.66k
                           pitch, height, pixelFormat, flags);
1666
1667
0
bailout:
1668
0
  return retval;
1669
1.66k
}
1670
1671
/* TurboJPEG 1.4+ */
1672
DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
1673
                                      const unsigned char *jpegBuf,
1674
                                      unsigned long jpegSize,
1675
                                      unsigned char **dstPlanes, int width,
1676
                                      int *strides, int height, int flags)
1677
7.27k
{
1678
7.27k
  int i, sfi, row, retval = 0;
1679
7.27k
  int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
1680
7.27k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1681
7.27k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1682
7.27k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1683
7.27k
  JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1684
7.27k
  int dctsize;
1685
7.27k
  struct my_progress_mgr progress;
1686
1687
7.27k
  GET_DINSTANCE(handle);
1688
7.27k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1689
1690
79.9k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1691
72.7k
    tmpbuf[i] = NULL;  outbuf[i] = NULL;
1692
72.7k
  }
1693
1694
7.27k
  if ((this->init & DECOMPRESS) == 0)
1695
7.27k
    THROW("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
1696
1697
7.27k
  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0] ||
1698
7.27k
      width < 0 || height < 0)
1699
7.27k
    THROW("tjDecompressToYUVPlanes(): Invalid argument");
1700
1701
7.27k
#ifndef NO_PUTENV
1702
7.27k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1703
7.27k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1704
7.27k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1705
7.27k
#endif
1706
1707
7.27k
  if (flags & TJFLAG_LIMITSCANS) {
1708
7.27k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
1709
7.27k
    progress.pub.progress_monitor = my_progress_monitor;
1710
7.27k
    progress.this = this;
1711
7.27k
    dinfo->progress = &progress.pub;
1712
7.27k
  } else
1713
0
    dinfo->progress = NULL;
1714
1715
7.27k
  if (setjmp(this->jerr.setjmp_buffer)) {
1716
    /* If we get here, the JPEG code has signaled an error. */
1717
0
    retval = -1;  goto bailout;
1718
0
  }
1719
1720
7.27k
  if (!this->headerRead) {
1721
0
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1722
0
    jpeg_read_header(dinfo, TRUE);
1723
0
  }
1724
7.27k
  this->headerRead = 0;
1725
7.27k
  jpegSubsamp = getSubsamp(dinfo);
1726
7.27k
  if (jpegSubsamp < 0)
1727
7.27k
    THROW("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1728
1729
7.27k
  if (jpegSubsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1730
7.27k
    THROW("tjDecompressToYUVPlanes(): Invalid argument");
1731
1732
7.27k
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1733
7.27k
  if (width == 0) width = jpegwidth;
1734
7.27k
  if (height == 0) height = jpegheight;
1735
68.6k
  for (i = 0; i < NUMSF; i++) {
1736
68.6k
    scaledw = TJSCALED(jpegwidth, sf[i]);
1737
68.6k
    scaledh = TJSCALED(jpegheight, sf[i]);
1738
68.6k
    if (scaledw <= width && scaledh <= height)
1739
7.27k
      break;
1740
68.6k
  }
1741
7.27k
  if (i >= NUMSF)
1742
7.27k
    THROW("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
1743
7.27k
  if (dinfo->num_components > 3)
1744
7.26k
    THROW("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
1745
1746
7.26k
  width = scaledw;  height = scaledh;
1747
7.26k
  dinfo->scale_num = sf[i].num;
1748
7.26k
  dinfo->scale_denom = sf[i].denom;
1749
7.26k
  sfi = i;
1750
7.26k
  jpeg_calc_output_dimensions(dinfo);
1751
1752
7.26k
  dctsize = DCTSIZE * sf[sfi].num / sf[sfi].denom;
1753
1754
21.0k
  for (i = 0; i < dinfo->num_components; i++) {
1755
13.8k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
1756
13.8k
    int ih;
1757
1758
13.8k
    iw[i] = compptr->width_in_blocks * dctsize;
1759
13.8k
    ih = compptr->height_in_blocks * dctsize;
1760
13.8k
    pw[i] = tjPlaneWidth(i, dinfo->output_width, jpegSubsamp);
1761
13.8k
    ph[i] = tjPlaneHeight(i, dinfo->output_height, jpegSubsamp);
1762
13.8k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1763
13.8k
    th[i] = compptr->v_samp_factor * dctsize;
1764
13.8k
    tmpbufsize += iw[i] * th[i];
1765
13.8k
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1766
13.8k
      THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
1767
13.8k
    ptr = dstPlanes[i];
1768
88.9M
    for (row = 0; row < ph[i]; row++) {
1769
88.9M
      outbuf[i][row] = ptr;
1770
88.9M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1771
88.9M
    }
1772
13.8k
  }
1773
7.26k
  if (usetmpbuf) {
1774
6.41k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1775
6.41k
      THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
1776
6.41k
    ptr = _tmpbuf;
1777
18.4k
    for (i = 0; i < dinfo->num_components; i++) {
1778
12.0k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1779
12.0k
        THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
1780
155k
      for (row = 0; row < th[i]; row++) {
1781
143k
        tmpbuf[i][row] = ptr;
1782
143k
        ptr += iw[i];
1783
143k
      }
1784
12.0k
    }
1785
6.41k
  }
1786
1787
7.26k
  if (setjmp(this->jerr.setjmp_buffer)) {
1788
    /* If we get here, the JPEG code has signaled an error. */
1789
1.84k
    retval = -1;  goto bailout;
1790
1.84k
  }
1791
1792
6.16k
  if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1793
6.16k
  if (flags & TJFLAG_FASTDCT) dinfo->dct_method = JDCT_FASTEST;
1794
5.41k
  dinfo->raw_data_out = TRUE;
1795
1796
5.41k
  jpeg_start_decompress(dinfo);
1797
3.63M
  for (row = 0; row < (int)dinfo->output_height;
1798
3.63M
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
1799
3.63M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1800
3.63M
    int crow[MAX_COMPONENTS];
1801
1802
10.4M
    for (i = 0; i < dinfo->num_components; i++) {
1803
6.81M
      jpeg_component_info *compptr = &dinfo->comp_info[i];
1804
1805
6.81M
      if (jpegSubsamp == TJSAMP_420) {
1806
        /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1807
           to be clever and use the IDCT to perform upsampling on the U and V
1808
           planes.  For instance, if the output image is to be scaled by 1/2
1809
           relative to the JPEG image, then the scaling factor and upsampling
1810
           effectively cancel each other, so a normal 8x8 IDCT can be used.
1811
           However, this is not desirable when using the decompress-to-YUV
1812
           functionality in TurboJPEG, since we want to output the U and V
1813
           planes in their subsampled form.  Thus, we have to override some
1814
           internal libjpeg parameters to force it to use the "scaled" IDCT
1815
           functions on the U and V planes. */
1816
2.38M
        compptr->_DCT_scaled_size = dctsize;
1817
2.38M
        compptr->MCU_sample_width = tjMCUWidth[jpegSubsamp] *
1818
2.38M
          sf[sfi].num / sf[sfi].denom *
1819
2.38M
          compptr->v_samp_factor / dinfo->max_v_samp_factor;
1820
2.38M
        dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1821
2.38M
      }
1822
6.81M
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1823
6.81M
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
1824
289k
      else yuvptr[i] = &outbuf[i][crow[i]];
1825
6.81M
    }
1826
3.63M
    jpeg_read_raw_data(dinfo, yuvptr,
1827
3.63M
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
1828
3.63M
    if (usetmpbuf) {
1829
3.42M
      int j;
1830
1831
9.94M
      for (i = 0; i < dinfo->num_components; i++) {
1832
75.7M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1833
69.2M
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
1834
69.2M
        }
1835
6.52M
      }
1836
3.42M
    }
1837
3.63M
  }
1838
5.41k
  jpeg_finish_decompress(dinfo);
1839
1840
7.27k
bailout:
1841
7.27k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1842
79.9k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1843
72.7k
    free(tmpbuf[i]);
1844
72.7k
    free(outbuf[i]);
1845
72.7k
  }
1846
7.27k
  free(_tmpbuf);
1847
7.27k
  if (this->jerr.warning) retval = -1;
1848
7.27k
  this->jerr.stopOnWarning = FALSE;
1849
7.27k
  return retval;
1850
5.41k
}
1851
1852
/* TurboJPEG 1.4+ */
1853
DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
1854
                                 unsigned long jpegSize, unsigned char *dstBuf,
1855
                                 int width, int align, int height, int flags)
1856
7.27k
{
1857
7.27k
  unsigned char *dstPlanes[3];
1858
7.27k
  int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1;
1859
7.27k
  int i, jpegwidth, jpegheight, scaledw, scaledh;
1860
1861
7.27k
  GET_DINSTANCE(handle);
1862
7.27k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1863
1864
7.27k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1865
7.27k
      align < 1 || !IS_POW2(align) || height < 0)
1866
7.27k
    THROW("tjDecompressToYUV2(): Invalid argument");
1867
1868
7.27k
  if (setjmp(this->jerr.setjmp_buffer)) {
1869
    /* If we get here, the JPEG code has signaled an error. */
1870
0
    return -1;
1871
0
  }
1872
1873
7.27k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1874
7.27k
  jpeg_read_header(dinfo, TRUE);
1875
7.27k
  jpegSubsamp = getSubsamp(dinfo);
1876
7.27k
  if (jpegSubsamp < 0)
1877
7.27k
    THROW("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1878
1879
7.27k
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1880
7.27k
  if (width == 0) width = jpegwidth;
1881
7.27k
  if (height == 0) height = jpegheight;
1882
68.6k
  for (i = 0; i < NUMSF; i++) {
1883
68.6k
    scaledw = TJSCALED(jpegwidth, sf[i]);
1884
68.6k
    scaledh = TJSCALED(jpegheight, sf[i]);
1885
68.6k
    if (scaledw <= width && scaledh <= height)
1886
7.27k
      break;
1887
68.6k
  }
1888
7.27k
  if (i >= NUMSF)
1889
7.27k
    THROW("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1890
1891
7.27k
  width = scaledw;  height = scaledh;
1892
1893
7.27k
  pw0 = tjPlaneWidth(0, width, jpegSubsamp);
1894
7.27k
  ph0 = tjPlaneHeight(0, height, jpegSubsamp);
1895
7.27k
  dstPlanes[0] = dstBuf;
1896
7.27k
  strides[0] = PAD(pw0, align);
1897
7.27k
  if (jpegSubsamp == TJSAMP_GRAY) {
1898
3.97k
    strides[1] = strides[2] = 0;
1899
3.97k
    dstPlanes[1] = dstPlanes[2] = NULL;
1900
3.97k
  } else {
1901
3.29k
    int pw1 = tjPlaneWidth(1, width, jpegSubsamp);
1902
3.29k
    int ph1 = tjPlaneHeight(1, height, jpegSubsamp);
1903
1904
3.29k
    strides[1] = strides[2] = PAD(pw1, align);
1905
3.29k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1906
3.29k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1907
3.29k
  }
1908
1909
7.27k
  this->headerRead = 1;
1910
7.27k
  return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1911
7.27k
                                 strides, height, flags);
1912
1913
0
bailout:
1914
0
  this->jerr.stopOnWarning = FALSE;
1915
0
  return retval;
1916
7.27k
}
1917
1918
/* TurboJPEG 1.1+ */
1919
DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
1920
                                unsigned long jpegSize, unsigned char *dstBuf,
1921
                                int flags)
1922
0
{
1923
0
  return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1924
0
}
1925
1926
1927
/******************************** Transformer ********************************/
1928
1929
/* TurboJPEG 1.2+ */
1930
DLLEXPORT tjhandle tjInitTransform(void)
1931
10.8k
{
1932
10.8k
  tjinstance *this = NULL;
1933
10.8k
  tjhandle handle = NULL;
1934
1935
10.8k
  if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
1936
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX,
1937
0
             "tjInitTransform(): Memory allocation failure");
1938
0
    return NULL;
1939
0
  }
1940
10.8k
  memset(this, 0, sizeof(tjinstance));
1941
10.8k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
1942
10.8k
  handle = _tjInitCompress(this);
1943
10.8k
  if (!handle) return NULL;
1944
10.8k
  handle = _tjInitDecompress(this);
1945
10.8k
  return handle;
1946
10.8k
}
1947
1948
1949
/* TurboJPEG 1.2+ */
1950
DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
1951
                          unsigned long jpegSize, int n,
1952
                          unsigned char **dstBufs, unsigned long *dstSizes,
1953
                          tjtransform *t, int flags)
1954
16.4k
{
1955
16.4k
  jpeg_transform_info *xinfo = NULL;
1956
16.4k
  jvirt_barray_ptr *srccoefs, *dstcoefs;
1957
16.4k
  int retval = 0, i, jpegSubsamp, saveMarkers = 0;
1958
16.4k
  boolean alloc = TRUE;
1959
16.4k
  struct my_progress_mgr progress;
1960
1961
16.4k
  GET_INSTANCE(handle);
1962
16.4k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1963
16.4k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
1964
16.4k
    THROW("tjTransform(): Instance has not been initialized for transformation");
1965
1966
16.4k
  if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
1967
16.4k
      dstSizes == NULL || t == NULL || flags < 0)
1968
16.4k
    THROW("tjTransform(): Invalid argument");
1969
1970
16.4k
#ifndef NO_PUTENV
1971
16.4k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1972
16.4k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1973
16.4k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1974
16.4k
#endif
1975
1976
16.4k
  if (flags & TJFLAG_LIMITSCANS) {
1977
16.4k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
1978
16.4k
    progress.pub.progress_monitor = my_progress_monitor;
1979
16.4k
    progress.this = this;
1980
16.4k
    dinfo->progress = &progress.pub;
1981
16.4k
  } else
1982
0
    dinfo->progress = NULL;
1983
1984
16.4k
  if ((xinfo =
1985
16.4k
       (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
1986
16.4k
    THROW("tjTransform(): Memory allocation failure");
1987
16.4k
  memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
1988
1989
16.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
1990
    /* If we get here, the JPEG code has signaled an error. */
1991
11.8k
    retval = -1;  goto bailout;
1992
11.8k
  }
1993
1994
4.59k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1995
1996
37.5k
  for (i = 0; i < n; i++) {
1997
32.9k
    xinfo[i].transform = xformtypes[t[i].op];
1998
32.9k
    xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
1999
32.9k
    xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
2000
32.9k
    xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
2001
32.9k
    xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
2002
32.9k
    if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
2003
32.9k
    else xinfo[i].slow_hflip = 0;
2004
2005
32.9k
    if (xinfo[i].crop) {
2006
8.24k
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
2007
8.24k
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
2008
8.24k
      if (t[i].r.w != 0) {
2009
8.24k
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
2010
8.24k
      } else
2011
0
        xinfo[i].crop_width = JCROP_UNSET;
2012
8.24k
      if (t[i].r.h != 0) {
2013
8.24k
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
2014
8.24k
      } else
2015
0
        xinfo[i].crop_height = JCROP_UNSET;
2016
8.24k
    }
2017
32.9k
    if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
2018
32.9k
  }
2019
2020
18.4E
  jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
2021
4.59k
  jpeg_read_header(dinfo, TRUE);
2022
4.59k
  jpegSubsamp = getSubsamp(dinfo);
2023
4.59k
  if (jpegSubsamp < 0)
2024
4.22k
    THROW("tjTransform(): Could not determine subsampling type for JPEG image");
2025
2026
32.4k
  for (i = 0; i < n; i++) {
2027
28.2k
    if (!jtransform_request_workspace(dinfo, &xinfo[i]))
2028
28.2k
      THROW("tjTransform(): Transform is not perfect");
2029
2030
28.2k
    if (xinfo[i].crop) {
2031
4.01k
      if ((t[i].r.x % tjMCUWidth[jpegSubsamp]) != 0 ||
2032
4.01k
          (t[i].r.y % tjMCUHeight[jpegSubsamp]) != 0) {
2033
0
        SNPRINTF(this->errStr, JMSG_LENGTH_MAX,
2034
0
                 "To crop this JPEG image, x must be a multiple of %d\n"
2035
0
                 "and y must be a multiple of %d.\n",
2036
0
                 tjMCUWidth[jpegSubsamp], tjMCUHeight[jpegSubsamp]);
2037
0
        this->isInstanceError = TRUE;
2038
0
        retval = -1;  goto bailout;
2039
0
      }
2040
4.01k
    }
2041
28.2k
  }
2042
2043
4.22k
  srccoefs = jpeg_read_coefficients(dinfo);
2044
2045
14.5k
  for (i = 0; i < n; i++) {
2046
10.3k
    int w, h;
2047
2048
10.3k
    if (!xinfo[i].crop) {
2049
8.89k
      w = dinfo->image_width;  h = dinfo->image_height;
2050
8.89k
    } else {
2051
1.47k
      w = xinfo[i].crop_width;  h = xinfo[i].crop_height;
2052
1.47k
    }
2053
10.3k
    if (flags & TJFLAG_NOREALLOC) {
2054
5.23k
      alloc = FALSE;  dstSizes[i] = tjBufSize(w, h, jpegSubsamp);
2055
5.23k
    }
2056
10.3k
    if (!(t[i].options & TJXOPT_NOOUTPUT))
2057
10.3k
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2058
10.3k
    jpeg_copy_critical_parameters(dinfo, cinfo);
2059
10.3k
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
2060
10.3k
#ifdef C_PROGRESSIVE_SUPPORTED
2061
10.3k
    if (flags & TJFLAG_PROGRESSIVE || t[i].options & TJXOPT_PROGRESSIVE)
2062
5.46k
      jpeg_simple_progression(cinfo);
2063
10.3k
#endif
2064
10.3k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
2065
8.17k
      jpeg_write_coefficients(cinfo, dstcoefs);
2066
8.17k
      jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
2067
4.41k
                                          JCOPYOPT_NONE : JCOPYOPT_ALL);
2068
8.17k
    } else
2069
2.19k
      jinit_c_master_control(cinfo, TRUE);
2070
10.3k
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
2071
10.3k
    if (t[i].customFilter) {
2072
0
      int ci, y;
2073
0
      JDIMENSION by;
2074
2075
0
      for (ci = 0; ci < cinfo->num_components; ci++) {
2076
0
        jpeg_component_info *compptr = &cinfo->comp_info[ci];
2077
0
        tjregion arrayRegion = { 0, 0, 0, 0 };
2078
0
        tjregion planeRegion = { 0, 0, 0, 0 };
2079
2080
0
        arrayRegion.w = compptr->width_in_blocks * DCTSIZE;
2081
0
        arrayRegion.h = DCTSIZE;
2082
0
        planeRegion.w = compptr->width_in_blocks * DCTSIZE;
2083
0
        planeRegion.h = compptr->height_in_blocks * DCTSIZE;
2084
2085
0
        for (by = 0; by < compptr->height_in_blocks;
2086
0
             by += compptr->v_samp_factor) {
2087
0
          JBLOCKARRAY barray = (dinfo->mem->access_virt_barray)
2088
0
            ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2089
0
             TRUE);
2090
2091
0
          for (y = 0; y < compptr->v_samp_factor; y++) {
2092
0
            if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
2093
0
                                  i, &t[i]) == -1)
2094
0
              THROW("tjTransform(): Error in custom filter");
2095
0
            arrayRegion.y += DCTSIZE;
2096
0
          }
2097
0
        }
2098
0
      }
2099
0
    }
2100
10.3k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2101
10.3k
  }
2102
2103
4.22k
  jpeg_finish_decompress(dinfo);
2104
2105
16.4k
bailout:
2106
16.4k
  if (cinfo->global_state > CSTATE_START) {
2107
1.12k
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
2108
1.12k
    jpeg_abort_compress(cinfo);
2109
1.12k
  }
2110
16.4k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2111
16.4k
  free(xinfo);
2112
16.4k
  if (this->jerr.warning) retval = -1;
2113
16.4k
  this->jerr.stopOnWarning = FALSE;
2114
16.4k
  return retval;
2115
4.22k
}
2116
2117
2118
/*************************** Packed-Pixel Image I/O **************************/
2119
2120
/* TurboJPEG 2.0+ */
2121
DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
2122
                                     int align, int *height, int *pixelFormat,
2123
                                     int flags)
2124
80.0k
{
2125
80.0k
  int retval = 0, tempc;
2126
80.0k
  size_t pitch;
2127
80.0k
  tjhandle handle = NULL;
2128
80.0k
  tjinstance *this;
2129
80.0k
  j_compress_ptr cinfo = NULL;
2130
80.0k
  cjpeg_source_ptr src;
2131
80.0k
  unsigned char *dstBuf = NULL;
2132
80.0k
  FILE *file = NULL;
2133
80.0k
  boolean invert;
2134
2135
80.0k
  if (!filename || !width || align < 1 || !height || !pixelFormat ||
2136
80.0k
      *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF)
2137
80.0k
    THROWG("tjLoadImage(): Invalid argument");
2138
80.0k
  if ((align & (align - 1)) != 0)
2139
80.0k
    THROWG("tjLoadImage(): Alignment must be a power of 2");
2140
2141
80.0k
  if ((handle = tjInitCompress()) == NULL) return NULL;
2142
80.0k
  this = (tjinstance *)handle;
2143
80.0k
  cinfo = &this->cinfo;
2144
2145
#ifdef _MSC_VER
2146
  if (fopen_s(&file, filename, "rb") || file == NULL)
2147
#else
2148
80.0k
  if ((file = fopen(filename, "rb")) == NULL)
2149
0
#endif
2150
80.0k
    THROW_UNIX("tjLoadImage(): Cannot open input file");
2151
2152
80.0k
  if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
2153
0
    THROW_UNIX("tjLoadImage(): Could not read input file")
2154
80.0k
  else if (tempc == EOF)
2155
80.0k
    THROWG("tjLoadImage(): Input file contains no data");
2156
2157
80.0k
  if (setjmp(this->jerr.setjmp_buffer)) {
2158
    /* If we get here, the JPEG code has signaled an error. */
2159
25.2k
    retval = -1;  goto bailout;
2160
25.2k
  }
2161
2162
54.7k
  if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN;
2163
54.7k
  else cinfo->in_color_space = pf2cs[*pixelFormat];
2164
54.7k
  if (tempc == 'B') {
2165
22.1k
    if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL)
2166
22.1k
      THROWG("tjLoadImage(): Could not initialize bitmap loader");
2167
22.1k
    invert = (flags & TJFLAG_BOTTOMUP) == 0;
2168
57.3k
  } else if (tempc == 'P') {
2169
57.3k
    if ((src = jinit_read_ppm(cinfo)) == NULL)
2170
57.3k
      THROWG("tjLoadImage(): Could not initialize PPM loader");
2171
57.3k
    invert = (flags & TJFLAG_BOTTOMUP) != 0;
2172
57.3k
  } else
2173
18.4E
    THROWG("tjLoadImage(): Unsupported file type");
2174
2175
79.4k
  src->input_file = file;
2176
79.4k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2177
  /* Refuse to load images larger than 1 Megapixel when fuzzing. */
2178
79.4k
  if (flags & TJFLAG_FUZZING)
2179
79.4k
    src->max_pixels = 1048576;
2180
79.4k
#endif
2181
79.4k
  (*src->start_input) (cinfo, src);
2182
79.4k
  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
2183
2184
79.4k
  *width = cinfo->image_width;  *height = cinfo->image_height;
2185
79.4k
  *pixelFormat = cs2pf[cinfo->in_color_space];
2186
2187
79.4k
  pitch = PAD((*width) * tjPixelSize[*pixelFormat], align);
2188
79.4k
  if ((unsigned long long)pitch * (unsigned long long)(*height) >
2189
79.4k
      (unsigned long long)((size_t)-1) ||
2190
79.4k
      (dstBuf = (unsigned char *)malloc(pitch * (*height))) == NULL)
2191
79.4k
    THROWG("tjLoadImage(): Memory allocation failure");
2192
2193
79.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
2194
    /* If we get here, the JPEG code has signaled an error. */
2195
19.3k
    retval = -1;  goto bailout;
2196
19.3k
  }
2197
2198
110M
  while (cinfo->next_scanline < cinfo->image_height) {
2199
110M
    int i, nlines = (*src->get_pixel_rows) (cinfo, src);
2200
2201
220M
    for (i = 0; i < nlines; i++) {
2202
110M
      unsigned char *dstptr;
2203
110M
      int row;
2204
2205
110M
      row = cinfo->next_scanline + i;
2206
110M
      if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch];
2207
88.1M
      else dstptr = &dstBuf[row * pitch];
2208
110M
      memcpy(dstptr, src->buffer[i], (*width) * tjPixelSize[*pixelFormat]);
2209
110M
    }
2210
110M
    cinfo->next_scanline += nlines;
2211
110M
  }
2212
2213
60.1k
  (*src->finish_input) (cinfo, src);
2214
2215
80.0k
bailout:
2216
80.0k
  if (handle) tjDestroy(handle);
2217
80.0k
  if (file) fclose(file);
2218
80.0k
  if (retval < 0) { free(dstBuf);  dstBuf = NULL; }
2219
80.0k
  return dstBuf;
2220
60.1k
}
2221
2222
2223
/* TurboJPEG 2.0+ */
2224
DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
2225
                          int width, int pitch, int height, int pixelFormat,
2226
                          int flags)
2227
0
{
2228
0
  int retval = 0;
2229
0
  tjhandle handle = NULL;
2230
0
  tjinstance *this;
2231
0
  j_decompress_ptr dinfo = NULL;
2232
0
  djpeg_dest_ptr dst;
2233
0
  FILE *file = NULL;
2234
0
  char *ptr = NULL;
2235
0
  boolean invert;
2236
2237
0
  if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 ||
2238
0
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
2239
0
    THROWG("tjSaveImage(): Invalid argument");
2240
2241
0
  if ((handle = tjInitDecompress()) == NULL)
2242
0
    return -1;
2243
0
  this = (tjinstance *)handle;
2244
0
  dinfo = &this->dinfo;
2245
2246
#ifdef _MSC_VER
2247
  if (fopen_s(&file, filename, "wb") || file == NULL)
2248
#else
2249
0
  if ((file = fopen(filename, "wb")) == NULL)
2250
0
#endif
2251
0
    THROW_UNIX("tjSaveImage(): Cannot open output file");
2252
2253
0
  if (setjmp(this->jerr.setjmp_buffer)) {
2254
    /* If we get here, the JPEG code has signaled an error. */
2255
0
    retval = -1;  goto bailout;
2256
0
  }
2257
2258
0
  this->dinfo.out_color_space = pf2cs[pixelFormat];
2259
0
  dinfo->image_width = width;  dinfo->image_height = height;
2260
0
  dinfo->global_state = DSTATE_READY;
2261
0
  dinfo->scale_num = dinfo->scale_denom = 1;
2262
2263
0
  ptr = strrchr(filename, '.');
2264
0
  if (ptr && !strcasecmp(ptr, ".bmp")) {
2265
0
    if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL)
2266
0
      THROWG("tjSaveImage(): Could not initialize bitmap writer");
2267
0
    invert = (flags & TJFLAG_BOTTOMUP) == 0;
2268
0
  } else {
2269
0
    if ((dst = jinit_write_ppm(dinfo)) == NULL)
2270
0
      THROWG("tjSaveImage(): Could not initialize PPM writer");
2271
0
    invert = (flags & TJFLAG_BOTTOMUP) != 0;
2272
0
  }
2273
2274
0
  dst->output_file = file;
2275
0
  (*dst->start_output) (dinfo, dst);
2276
0
  (*dinfo->mem->realize_virt_arrays) ((j_common_ptr)dinfo);
2277
2278
0
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
2279
2280
0
  while (dinfo->output_scanline < dinfo->output_height) {
2281
0
    unsigned char *rowptr;
2282
2283
0
    if (invert)
2284
0
      rowptr = &buffer[(height - dinfo->output_scanline - 1) * pitch];
2285
0
    else
2286
0
      rowptr = &buffer[dinfo->output_scanline * pitch];
2287
0
    memcpy(dst->buffer[0], rowptr, width * tjPixelSize[pixelFormat]);
2288
0
    (*dst->put_pixel_rows) (dinfo, dst, 1);
2289
0
    dinfo->output_scanline++;
2290
0
  }
2291
2292
0
  (*dst->finish_output) (dinfo, dst);
2293
2294
0
bailout:
2295
0
  if (handle) tjDestroy(handle);
2296
0
  if (file) fclose(file);
2297
0
  return retval;
2298
0
}