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
43.7k
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
53
0
#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
12.6k
{
76
12.6k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
77
78
12.6k
  (*cinfo->err->output_message) (cinfo);
79
12.6k
  longjmp(myerr->setjmp_buffer, 1);
80
12.6k
}
81
82
/* Based on output_message() in jerror.c */
83
84
static void my_output_message(j_common_ptr cinfo)
85
12.6k
{
86
12.6k
  (*cinfo->err->format_message) (cinfo, errStr);
87
12.6k
}
88
89
static void my_emit_message(j_common_ptr cinfo, int msg_level)
90
16.9k
{
91
16.9k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
92
93
16.9k
  myerr->emit_message(cinfo, msg_level);
94
16.9k
  if (msg_level < 0) {
95
0
    myerr->warning = TRUE;
96
0
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
97
0
  }
98
16.9k
}
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
0
{
122
0
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
123
0
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
124
125
0
  if (dinfo->is_decompressor) {
126
0
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
127
128
0
    if (scan_no > 500) {
129
0
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
130
0
               "Progressive JPEG image has more than 500 scans");
131
0
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
132
0
               "Progressive JPEG image has more than 500 scans");
133
0
      myprog->this->isInstanceError = TRUE;
134
0
      myerr->warning = FALSE;
135
0
      longjmp(myerr->setjmp_buffer, 1);
136
0
    }
137
0
  }
138
0
}
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
0
#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
0
#define THROW(m) { \
211
0
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
212
0
  this->isInstanceError = TRUE;  THROWG(m) \
213
0
}
214
215
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
216
/* Private flag that triggers different TurboJPEG API behavior when fuzzing */
217
19.1k
#define TJFLAG_FUZZING  (1 << 30)
218
#endif
219
220
#define GET_INSTANCE(handle) \
221
22.0k
  tjinstance *this = (tjinstance *)handle; \
222
22.0k
  j_compress_ptr cinfo = NULL; \
223
22.0k
  j_decompress_ptr dinfo = NULL; \
224
22.0k
  \
225
22.0k
  if (!this) { \
226
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
227
0
    return -1; \
228
0
  } \
229
22.0k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
230
22.0k
  this->jerr.warning = FALSE; \
231
22.0k
  this->isInstanceError = FALSE;
232
233
#define GET_CINSTANCE(handle) \
234
6.62k
  tjinstance *this = (tjinstance *)handle; \
235
6.62k
  j_compress_ptr cinfo = NULL; \
236
6.62k
  \
237
6.62k
  if (!this) { \
238
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
239
0
    return -1; \
240
0
  } \
241
6.62k
  cinfo = &this->cinfo; \
242
6.62k
  this->jerr.warning = FALSE; \
243
6.62k
  this->isInstanceError = FALSE;
244
245
#define GET_DINSTANCE(handle) \
246
0
  tjinstance *this = (tjinstance *)handle; \
247
0
  j_decompress_ptr dinfo = NULL; \
248
0
  \
249
0
  if (!this) { \
250
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
251
0
    return -1; \
252
0
  } \
253
0
  dinfo = &this->dinfo; \
254
0
  this->jerr.warning = FALSE; \
255
0
  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
6.62k
{
280
6.62k
#ifndef NO_GETENV
281
6.62k
  char env[7] = { 0 };
282
6.62k
#endif
283
284
6.62k
  cinfo->in_color_space = pf2cs[pixelFormat];
285
6.62k
  cinfo->input_components = tjPixelSize[pixelFormat];
286
6.62k
  jpeg_set_defaults(cinfo);
287
288
6.62k
#ifndef NO_GETENV
289
6.62k
  if (!GETENV_S(env, 7, "TJ_OPTIMIZE") && !strcmp(env, "1"))
290
0
    cinfo->optimize_coding = TRUE;
291
6.62k
  if (!GETENV_S(env, 7, "TJ_ARITHMETIC") && !strcmp(env, "1"))
292
0
    cinfo->arith_code = TRUE;
293
6.62k
  if (!GETENV_S(env, 7, "TJ_RESTART") && strlen(env) > 0) {
294
0
    int temp = -1;
295
0
    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
0
    if (sscanf(env, "%d%c", &temp, &tempc) >= 1 && temp >= 0 &&
302
0
        temp <= 65535) {
303
0
#endif
304
0
      if (toupper(tempc) == 'B') {
305
0
        cinfo->restart_interval = temp;
306
0
        cinfo->restart_in_rows = 0;
307
0
      } else
308
0
        cinfo->restart_in_rows = temp;
309
0
    }
310
0
  }
311
6.62k
#endif
312
313
6.62k
  if (jpegQual >= 0) {
314
6.62k
    jpeg_set_quality(cinfo, jpegQual, TRUE);
315
6.62k
    if (jpegQual >= 96 || flags & TJFLAG_ACCURATEDCT)
316
971
      cinfo->dct_method = JDCT_ISLOW;
317
5.64k
    else
318
5.64k
      cinfo->dct_method = JDCT_FASTEST;
319
6.62k
  }
320
6.62k
  if (subsamp == TJSAMP_GRAY)
321
1.77k
    jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
322
4.84k
  else if (pixelFormat == TJPF_CMYK)
323
962
    jpeg_set_colorspace(cinfo, JCS_YCCK);
324
3.88k
  else
325
3.88k
    jpeg_set_colorspace(cinfo, JCS_YCbCr);
326
327
6.62k
#ifdef C_PROGRESSIVE_SUPPORTED
328
6.62k
  if (flags & TJFLAG_PROGRESSIVE)
329
971
    jpeg_simple_progression(cinfo);
330
5.64k
#ifndef NO_GETENV
331
5.64k
  else if (!GETENV_S(env, 7, "TJ_PROGRESSIVE") && !strcmp(env, "1"))
332
0
    jpeg_simple_progression(cinfo);
333
6.62k
#endif
334
6.62k
#endif
335
336
6.62k
  cinfo->comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
337
6.62k
  cinfo->comp_info[1].h_samp_factor = 1;
338
6.62k
  cinfo->comp_info[2].h_samp_factor = 1;
339
6.62k
  if (cinfo->num_components > 3)
340
962
    cinfo->comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
341
6.62k
  cinfo->comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
342
6.62k
  cinfo->comp_info[1].v_samp_factor = 1;
343
6.62k
  cinfo->comp_info[2].v_samp_factor = 1;
344
6.62k
  if (cinfo->num_components > 3)
345
962
    cinfo->comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
346
6.62k
}
347
348
349
static int getSubsamp(j_decompress_ptr dinfo)
350
0
{
351
0
  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
0
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
358
0
    return TJSAMP_GRAY;
359
360
0
  for (i = 0; i < TJ_NUMSAMP; i++) {
361
0
    if (dinfo->num_components == pixelsize[i] ||
362
0
        ((dinfo->jpeg_color_space == JCS_YCCK ||
363
0
          dinfo->jpeg_color_space == JCS_CMYK) &&
364
0
         pixelsize[i] == 3 && dinfo->num_components == 4)) {
365
0
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
366
0
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
367
0
        int match = 0;
368
369
0
        for (k = 1; k < dinfo->num_components; k++) {
370
0
          int href = 1, vref = 1;
371
372
0
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
373
0
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
374
0
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
375
0
          }
376
0
          if (dinfo->comp_info[k].h_samp_factor == href &&
377
0
              dinfo->comp_info[k].v_samp_factor == vref)
378
0
            match++;
379
0
        }
380
0
        if (match == dinfo->num_components - 1) {
381
0
          retval = i;  break;
382
0
        }
383
0
      }
384
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
385
         in non-standard ways. */
386
0
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
387
0
          dinfo->comp_info[0].v_samp_factor == 2 &&
388
0
          (i == TJSAMP_422 || i == TJSAMP_440)) {
389
0
        int match = 0;
390
391
0
        for (k = 1; k < dinfo->num_components; k++) {
392
0
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
393
394
0
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
395
0
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
396
0
            href = vref = 2;
397
0
          }
398
0
          if (dinfo->comp_info[k].h_samp_factor == href &&
399
0
              dinfo->comp_info[k].v_samp_factor == vref)
400
0
            match++;
401
0
        }
402
0
        if (match == dinfo->num_components - 1) {
403
0
          retval = i;  break;
404
0
        }
405
0
      }
406
      /* Handle 4:4:4 images whose sampling factors are specified in
407
         non-standard ways. */
408
0
      if (dinfo->comp_info[0].h_samp_factor *
409
0
          dinfo->comp_info[0].v_samp_factor <=
410
0
          D_MAX_BLOCKS_IN_MCU / pixelsize[i] && i == TJSAMP_444) {
411
0
        int match = 0;
412
0
        for (k = 1; k < dinfo->num_components; k++) {
413
0
          if (dinfo->comp_info[k].h_samp_factor ==
414
0
              dinfo->comp_info[0].h_samp_factor &&
415
0
              dinfo->comp_info[k].v_samp_factor ==
416
0
              dinfo->comp_info[0].v_samp_factor)
417
0
            match++;
418
0
          if (match == dinfo->num_components - 1) {
419
0
            retval = i;  break;
420
0
          }
421
0
        }
422
0
      }
423
0
    }
424
0
  }
425
0
  return retval;
426
0
}
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
22.0k
{
464
22.0k
  GET_INSTANCE(handle);
465
466
22.0k
  if (setjmp(this->jerr.setjmp_buffer)) return -1;
467
22.0k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
468
22.0k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
469
22.0k
  free(this);
470
22.0k
  return 0;
471
22.0k
}
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
9.37k
{
482
9.37k
  free(buf);
483
9.37k
}
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
22.0k
{
497
22.0k
  static unsigned char buffer[1];
498
22.0k
  unsigned char *buf = buffer;
499
22.0k
  unsigned long size = 1;
500
501
  /* This is also straight out of example.txt */
502
22.0k
  this->cinfo.err = jpeg_std_error(&this->jerr.pub);
503
22.0k
  this->jerr.pub.error_exit = my_error_exit;
504
22.0k
  this->jerr.pub.output_message = my_output_message;
505
22.0k
  this->jerr.emit_message = this->jerr.pub.emit_message;
506
22.0k
  this->jerr.pub.emit_message = my_emit_message;
507
22.0k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
508
22.0k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
509
22.0k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
510
511
22.0k
  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
22.0k
  jpeg_create_compress(&this->cinfo);
518
  /* Make an initial call so it will create the destination manager */
519
22.0k
  jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
520
521
22.0k
  this->init |= COMPRESS;
522
22.0k
  return (tjhandle)this;
523
22.0k
}
524
525
/* TurboJPEG 1.0+ */
526
DLLEXPORT tjhandle tjInitCompress(void)
527
22.0k
{
528
22.0k
  tjinstance *this = NULL;
529
530
22.0k
  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
22.0k
  memset(this, 0, sizeof(tjinstance));
536
22.0k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
537
22.0k
  return _tjInitCompress(this);
538
22.0k
}
539
540
541
/* TurboJPEG 1.2+ */
542
DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
543
12.2k
{
544
12.2k
  unsigned long long retval = 0;
545
12.2k
  int mcuw, mcuh, chromasf;
546
547
12.2k
  if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP)
548
12.2k
    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
12.2k
  mcuw = tjMCUWidth[jpegSubsamp];
554
12.2k
  mcuh = tjMCUHeight[jpegSubsamp];
555
12.2k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
556
12.2k
  retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
557
12.2k
  if (retval > (unsigned long long)((unsigned long)-1))
558
12.2k
    THROWG("tjBufSize(): Image is too large");
559
560
12.2k
bailout:
561
12.2k
  return (unsigned long)retval;
562
12.2k
}
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
0
{
588
0
  unsigned long long retval = 0;
589
0
  int nc, i;
590
591
0
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
592
0
    THROWG("tjBufSizeYUV2(): Invalid argument");
593
594
0
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
595
0
  for (i = 0; i < nc; i++) {
596
0
    int pw = tjPlaneWidth(i, width, subsamp);
597
0
    int stride = PAD(pw, align);
598
0
    int ph = tjPlaneHeight(i, height, subsamp);
599
600
0
    if (pw < 0 || ph < 0) return -1;
601
0
    else retval += (unsigned long long)stride * ph;
602
0
  }
603
0
  if (retval > (unsigned long long)((unsigned long)-1))
604
0
    THROWG("tjBufSizeYUV2(): Image is too large");
605
606
0
bailout:
607
0
  return (unsigned long)retval;
608
0
}
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
0
{
626
0
  unsigned long long pw, retval = 0;
627
0
  int nc;
628
629
0
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
630
0
    THROWG("tjPlaneWidth(): Invalid argument");
631
0
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
632
0
  if (componentID < 0 || componentID >= nc)
633
0
    THROWG("tjPlaneWidth(): Invalid argument");
634
635
0
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
636
0
  if (componentID == 0)
637
0
    retval = pw;
638
0
  else
639
0
    retval = pw * 8 / tjMCUWidth[subsamp];
640
641
0
  if (retval > (unsigned long long)INT_MAX)
642
0
    THROWG("tjPlaneWidth(): Width is too large");
643
644
0
bailout:
645
0
  return (int)retval;
646
0
}
647
648
649
/* TurboJPEG 1.4+ */
650
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
651
0
{
652
0
  unsigned long long ph, retval = 0;
653
0
  int nc;
654
655
0
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
656
0
    THROWG("tjPlaneHeight(): Invalid argument");
657
0
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
658
0
  if (componentID < 0 || componentID >= nc)
659
0
    THROWG("tjPlaneHeight(): Invalid argument");
660
661
0
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
662
0
  if (componentID == 0)
663
0
    retval = ph;
664
0
  else
665
0
    retval = ph * 8 / tjMCUHeight[subsamp];
666
667
0
  if (retval > (unsigned long long)INT_MAX)
668
0
    THROWG("tjPlaneHeight(): Height is too large");
669
670
0
bailout:
671
0
  return (int)retval;
672
0
}
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
6.62k
{
707
6.62k
  int i, retval = 0;
708
6.62k
  boolean alloc = TRUE;
709
6.62k
  JSAMPROW *row_pointer = NULL;
710
711
6.62k
  GET_CINSTANCE(handle)
712
6.62k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
713
6.62k
  if ((this->init & COMPRESS) == 0)
714
6.62k
    THROW("tjCompress2(): Instance has not been initialized for compression");
715
716
6.62k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
717
6.62k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
718
6.62k
      jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP ||
719
6.62k
      jpegQual < 0 || jpegQual > 100)
720
6.62k
    THROW("tjCompress2(): Invalid argument");
721
722
6.62k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
723
724
6.62k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * height)) == NULL)
725
6.62k
    THROW("tjCompress2(): Memory allocation failure");
726
727
6.62k
  if (setjmp(this->jerr.setjmp_buffer)) {
728
    /* If we get here, the JPEG code has signaled an error. */
729
41
    retval = -1;  goto bailout;
730
41
  }
731
732
6.57k
  cinfo->image_width = width;
733
6.57k
  cinfo->image_height = height;
734
735
6.57k
#ifndef NO_PUTENV
736
6.57k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
737
6.57k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
738
6.57k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
739
6.57k
#endif
740
741
6.57k
  if (flags & TJFLAG_NOREALLOC) {
742
5.64k
    alloc = FALSE;  *jpegSize = tjBufSize(width, height, jpegSubsamp);
743
5.64k
  }
744
6.57k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
745
6.57k
  setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags);
746
747
6.57k
  jpeg_start_compress(cinfo, TRUE);
748
19.7M
  for (i = 0; i < height; i++) {
749
19.7M
    if (flags & TJFLAG_BOTTOMUP)
750
2.83M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
751
16.8M
    else
752
16.8M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
753
19.7M
  }
754
13.1k
  while (cinfo->next_scanline < cinfo->image_height)
755
6.57k
    jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
756
6.57k
                         cinfo->image_height - cinfo->next_scanline);
757
6.57k
  jpeg_finish_compress(cinfo);
758
759
6.62k
bailout:
760
6.62k
  if (cinfo->global_state > CSTATE_START) {
761
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
762
0
    jpeg_abort_compress(cinfo);
763
0
  }
764
6.62k
  free(row_pointer);
765
6.62k
  if (this->jerr.warning) retval = -1;
766
6.62k
  this->jerr.stopOnWarning = FALSE;
767
6.62k
  return retval;
768
6.57k
}
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
0
{
800
0
  JSAMPROW *row_pointer = NULL;
801
0
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
802
0
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
803
0
  JSAMPROW *outbuf[MAX_COMPONENTS];
804
0
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
805
0
  JSAMPLE *ptr;
806
0
  jpeg_component_info *compptr;
807
808
0
  GET_CINSTANCE(handle);
809
0
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
810
811
0
  for (i = 0; i < MAX_COMPONENTS; i++) {
812
0
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
813
0
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
814
0
  }
815
816
0
  if ((this->init & COMPRESS) == 0)
817
0
    THROW("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
818
819
0
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
820
0
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
821
0
      !dstPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP)
822
0
    THROW("tjEncodeYUVPlanes(): Invalid argument");
823
0
  if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
824
0
    THROW("tjEncodeYUVPlanes(): Invalid argument");
825
826
0
  if (pixelFormat == TJPF_CMYK)
827
0
    THROW("tjEncodeYUVPlanes(): Cannot generate YUV images from packed-pixel CMYK images");
828
829
0
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
830
831
0
  if (setjmp(this->jerr.setjmp_buffer)) {
832
    /* If we get here, the JPEG code has signaled an error. */
833
0
    retval = -1;  goto bailout;
834
0
  }
835
836
0
  cinfo->image_width = width;
837
0
  cinfo->image_height = height;
838
839
0
#ifndef NO_PUTENV
840
0
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
841
0
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
842
0
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
843
0
#endif
844
845
0
  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
0
  if (cinfo->global_state != CSTATE_START)
852
0
    THROW("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
853
0
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
854
0
  jinit_c_master_control(cinfo, FALSE);
855
0
  jinit_color_converter(cinfo);
856
0
  jinit_downsampler(cinfo);
857
0
  (*cinfo->cconvert->start_pass) (cinfo);
858
859
0
  pw0 = PAD(width, cinfo->max_h_samp_factor);
860
0
  ph0 = PAD(height, cinfo->max_v_samp_factor);
861
862
0
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
863
0
    THROW("tjEncodeYUVPlanes(): Memory allocation failure");
864
0
  for (i = 0; i < height; i++) {
865
0
    if (flags & TJFLAG_BOTTOMUP)
866
0
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
867
0
    else
868
0
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
869
0
  }
870
0
  if (height < ph0)
871
0
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
872
873
0
  for (i = 0; i < cinfo->num_components; i++) {
874
0
    compptr = &cinfo->comp_info[i];
875
0
    _tmpbuf[i] = (JSAMPLE *)malloc(
876
0
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
877
0
          compptr->h_samp_factor, 32) *
878
0
      cinfo->max_v_samp_factor + 32);
879
0
    if (!_tmpbuf[i])
880
0
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
881
0
    tmpbuf[i] =
882
0
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
883
0
    if (!tmpbuf[i])
884
0
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
885
0
    for (row = 0; row < cinfo->max_v_samp_factor; row++) {
886
0
      unsigned char *_tmpbuf_aligned =
887
0
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
888
889
0
      tmpbuf[i][row] = &_tmpbuf_aligned[
890
0
        PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
891
0
            compptr->h_samp_factor, 32) * row];
892
0
    }
893
0
    _tmpbuf2[i] =
894
0
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
895
0
                        compptr->v_samp_factor + 32);
896
0
    if (!_tmpbuf2[i])
897
0
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
898
0
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
899
0
    if (!tmpbuf2[i])
900
0
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
901
0
    for (row = 0; row < compptr->v_samp_factor; row++) {
902
0
      unsigned char *_tmpbuf2_aligned =
903
0
        (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
904
905
0
      tmpbuf2[i][row] =
906
0
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
907
0
    }
908
0
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
909
0
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
910
0
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
911
0
    if (!outbuf[i])
912
0
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
913
0
    ptr = dstPlanes[i];
914
0
    for (row = 0; row < ph[i]; row++) {
915
0
      outbuf[i][row] = ptr;
916
0
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
917
0
    }
918
0
  }
919
920
0
  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
0
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
926
0
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
927
0
                                       cinfo->max_v_samp_factor);
928
0
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
929
0
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
930
0
         i++, compptr++)
931
0
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
932
0
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
933
0
        compptr->v_samp_factor, pw[i]);
934
0
  }
935
0
  cinfo->next_scanline += height;
936
0
  jpeg_abort_compress(cinfo);
937
938
0
bailout:
939
0
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
940
0
  free(row_pointer);
941
0
  for (i = 0; i < MAX_COMPONENTS; i++) {
942
0
    free(tmpbuf[i]);
943
0
    free(_tmpbuf[i]);
944
0
    free(tmpbuf2[i]);
945
0
    free(_tmpbuf2[i]);
946
0
    free(outbuf[i]);
947
0
  }
948
0
  if (this->jerr.warning) retval = -1;
949
0
  this->jerr.stopOnWarning = FALSE;
950
0
  return retval;
951
0
}
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
0
{
959
0
  unsigned char *dstPlanes[3];
960
0
  int pw0, ph0, strides[3], retval = -1;
961
0
  tjinstance *this = (tjinstance *)handle;
962
963
0
  if (!this) THROWG("tjEncodeYUV3(): Invalid handle");
964
0
  this->isInstanceError = FALSE;
965
966
0
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
967
0
      !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
968
0
    THROW("tjEncodeYUV3(): Invalid argument");
969
970
0
  pw0 = tjPlaneWidth(0, width, subsamp);
971
0
  ph0 = tjPlaneHeight(0, height, subsamp);
972
0
  dstPlanes[0] = dstBuf;
973
0
  strides[0] = PAD(pw0, align);
974
0
  if (subsamp == TJSAMP_GRAY) {
975
0
    strides[1] = strides[2] = 0;
976
0
    dstPlanes[1] = dstPlanes[2] = NULL;
977
0
  } else {
978
0
    int pw1 = tjPlaneWidth(1, width, subsamp);
979
0
    int ph1 = tjPlaneHeight(1, height, subsamp);
980
981
0
    strides[1] = strides[2] = PAD(pw1, align);
982
0
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
983
0
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
984
0
  }
985
986
0
  return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
987
0
                           dstPlanes, strides, subsamp, flags);
988
989
0
bailout:
990
0
  return retval;
991
0
}
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
0
{
1022
0
  int i, row, retval = 0;
1023
0
  boolean alloc = TRUE;
1024
0
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1025
0
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1026
0
  JSAMPLE *_tmpbuf = NULL, *ptr;
1027
0
  JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1028
1029
0
  GET_CINSTANCE(handle)
1030
0
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1031
1032
0
  for (i = 0; i < MAX_COMPONENTS; i++) {
1033
0
    tmpbuf[i] = NULL;  inbuf[i] = NULL;
1034
0
  }
1035
1036
0
  if ((this->init & COMPRESS) == 0)
1037
0
    THROW("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
1038
1039
0
  if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
1040
0
      subsamp < 0 || subsamp >= TJ_NUMSAMP || jpegBuf == NULL ||
1041
0
      jpegSize == NULL || jpegQual < 0 || jpegQual > 100)
1042
0
    THROW("tjCompressFromYUVPlanes(): Invalid argument");
1043
0
  if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1044
0
    THROW("tjCompressFromYUVPlanes(): Invalid argument");
1045
1046
0
  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
0
  cinfo->image_width = width;
1052
0
  cinfo->image_height = height;
1053
1054
0
#ifndef NO_PUTENV
1055
0
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1056
0
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1057
0
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1058
0
#endif
1059
1060
0
  if (flags & TJFLAG_NOREALLOC) {
1061
0
    alloc = FALSE;  *jpegSize = tjBufSize(width, height, subsamp);
1062
0
  }
1063
0
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1064
0
  setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags);
1065
0
  cinfo->raw_data_in = TRUE;
1066
1067
0
  jpeg_start_compress(cinfo, TRUE);
1068
0
  for (i = 0; i < cinfo->num_components; i++) {
1069
0
    jpeg_component_info *compptr = &cinfo->comp_info[i];
1070
0
    int ih;
1071
1072
0
    iw[i] = compptr->width_in_blocks * DCTSIZE;
1073
0
    ih = compptr->height_in_blocks * DCTSIZE;
1074
0
    pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
1075
0
            compptr->h_samp_factor / cinfo->max_h_samp_factor;
1076
0
    ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
1077
0
            compptr->v_samp_factor / cinfo->max_v_samp_factor;
1078
0
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1079
0
    th[i] = compptr->v_samp_factor * DCTSIZE;
1080
0
    tmpbufsize += iw[i] * th[i];
1081
0
    if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1082
0
      THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
1083
0
    ptr = (JSAMPLE *)srcPlanes[i];
1084
0
    for (row = 0; row < ph[i]; row++) {
1085
0
      inbuf[i][row] = ptr;
1086
0
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1087
0
    }
1088
0
  }
1089
0
  if (usetmpbuf) {
1090
0
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1091
0
      THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
1092
0
    ptr = _tmpbuf;
1093
0
    for (i = 0; i < cinfo->num_components; i++) {
1094
0
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1095
0
        THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
1096
0
      for (row = 0; row < th[i]; row++) {
1097
0
        tmpbuf[i][row] = ptr;
1098
0
        ptr += iw[i];
1099
0
      }
1100
0
    }
1101
0
  }
1102
1103
0
  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
0
  for (row = 0; row < (int)cinfo->image_height;
1109
0
       row += cinfo->max_v_samp_factor * DCTSIZE) {
1110
0
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1111
0
    int crow[MAX_COMPONENTS];
1112
1113
0
    for (i = 0; i < cinfo->num_components; i++) {
1114
0
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1115
1116
0
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1117
0
      if (usetmpbuf) {
1118
0
        int j, k;
1119
1120
0
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1121
0
          memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1122
          /* Duplicate last sample in row to fill out MCU */
1123
0
          for (k = pw[i]; k < iw[i]; k++)
1124
0
            tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1125
0
        }
1126
        /* Duplicate last row to fill out MCU */
1127
0
        for (j = ph[i] - crow[i]; j < th[i]; j++)
1128
0
          memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1129
0
        yuvptr[i] = tmpbuf[i];
1130
0
      } else
1131
0
        yuvptr[i] = &inbuf[i][crow[i]];
1132
0
    }
1133
0
    jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1134
0
  }
1135
0
  jpeg_finish_compress(cinfo);
1136
1137
0
bailout:
1138
0
  if (cinfo->global_state > CSTATE_START) {
1139
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
1140
0
    jpeg_abort_compress(cinfo);
1141
0
  }
1142
0
  for (i = 0; i < MAX_COMPONENTS; i++) {
1143
0
    free(tmpbuf[i]);
1144
0
    free(inbuf[i]);
1145
0
  }
1146
0
  free(_tmpbuf);
1147
0
  if (this->jerr.warning) retval = -1;
1148
0
  this->jerr.stopOnWarning = FALSE;
1149
0
  return retval;
1150
0
}
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
0
{
1159
0
  const unsigned char *srcPlanes[3];
1160
0
  int pw0, ph0, strides[3], retval = -1;
1161
0
  tjinstance *this = (tjinstance *)handle;
1162
1163
0
  if (!this) THROWG("tjCompressFromYUV(): Invalid handle");
1164
0
  this->isInstanceError = FALSE;
1165
1166
0
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1167
0
      height <= 0 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1168
0
    THROW("tjCompressFromYUV(): Invalid argument");
1169
1170
0
  pw0 = tjPlaneWidth(0, width, subsamp);
1171
0
  ph0 = tjPlaneHeight(0, height, subsamp);
1172
0
  srcPlanes[0] = srcBuf;
1173
0
  strides[0] = PAD(pw0, align);
1174
0
  if (subsamp == TJSAMP_GRAY) {
1175
0
    strides[1] = strides[2] = 0;
1176
0
    srcPlanes[1] = srcPlanes[2] = NULL;
1177
0
  } else {
1178
0
    int pw1 = tjPlaneWidth(1, width, subsamp);
1179
0
    int ph1 = tjPlaneHeight(1, height, subsamp);
1180
1181
0
    strides[1] = strides[2] = PAD(pw1, align);
1182
0
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1183
0
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1184
0
  }
1185
1186
0
  return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1187
0
                                 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1188
1189
0
bailout:
1190
0
  return retval;
1191
0
}
1192
1193
1194
/******************************* Decompressor ********************************/
1195
1196
static tjhandle _tjInitDecompress(tjinstance *this)
1197
0
{
1198
0
  static unsigned char buffer[1];
1199
1200
  /* This is also straight out of example.txt */
1201
0
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1202
0
  this->jerr.pub.error_exit = my_error_exit;
1203
0
  this->jerr.pub.output_message = my_output_message;
1204
0
  this->jerr.emit_message = this->jerr.pub.emit_message;
1205
0
  this->jerr.pub.emit_message = my_emit_message;
1206
0
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1207
0
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1208
0
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1209
1210
0
  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
0
  jpeg_create_decompress(&this->dinfo);
1217
  /* Make an initial call so it will create the source manager */
1218
0
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1219
1220
0
  this->init |= DECOMPRESS;
1221
0
  return (tjhandle)this;
1222
0
}
1223
1224
/* TurboJPEG 1.0+ */
1225
DLLEXPORT tjhandle tjInitDecompress(void)
1226
0
{
1227
0
  tjinstance *this;
1228
1229
0
  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
0
  memset(this, 0, sizeof(tjinstance));
1235
0
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
1236
0
  return _tjInitDecompress(this);
1237
0
}
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
0
{
1247
0
  int retval = 0;
1248
1249
0
  GET_DINSTANCE(handle);
1250
0
  if ((this->init & DECOMPRESS) == 0)
1251
0
    THROW("tjDecompressHeader3(): Instance has not been initialized for decompression");
1252
1253
0
  if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL ||
1254
0
      jpegSubsamp == NULL || jpegColorspace == NULL)
1255
0
    THROW("tjDecompressHeader3(): Invalid argument");
1256
1257
0
  if (setjmp(this->jerr.setjmp_buffer)) {
1258
    /* If we get here, the JPEG code has signaled an error. */
1259
0
    return -1;
1260
0
  }
1261
1262
0
  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
0
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1269
0
    return 0;
1270
1271
0
  *width = dinfo->image_width;
1272
0
  *height = dinfo->image_height;
1273
0
  *jpegSubsamp = getSubsamp(dinfo);
1274
0
  switch (dinfo->jpeg_color_space) {
1275
0
  case JCS_GRAYSCALE:  *jpegColorspace = TJCS_GRAY;  break;
1276
0
  case JCS_RGB:        *jpegColorspace = TJCS_RGB;  break;
1277
0
  case JCS_YCbCr:      *jpegColorspace = TJCS_YCbCr;  break;
1278
0
  case JCS_CMYK:       *jpegColorspace = TJCS_CMYK;  break;
1279
0
  case JCS_YCCK:       *jpegColorspace = TJCS_YCCK;  break;
1280
0
  default:             *jpegColorspace = -1;  break;
1281
0
  }
1282
1283
0
  jpeg_abort_decompress(dinfo);
1284
1285
0
  if (*jpegSubsamp < 0)
1286
0
    THROW("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1287
0
  if (*jpegColorspace < 0)
1288
0
    THROW("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1289
0
  if (*width < 1 || *height < 1)
1290
0
    THROW("tjDecompressHeader3(): Invalid data returned in header");
1291
1292
0
bailout:
1293
0
  if (this->jerr.warning) retval = -1;
1294
0
  return retval;
1295
0
}
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
0
{
1340
0
  JSAMPROW *row_pointer = NULL;
1341
0
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
1342
0
  struct my_progress_mgr progress;
1343
1344
0
  GET_DINSTANCE(handle);
1345
0
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1346
0
  if ((this->init & DECOMPRESS) == 0)
1347
0
    THROW("tjDecompress2(): Instance has not been initialized for decompression");
1348
1349
0
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1350
0
      pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1351
0
    THROW("tjDecompress2(): Invalid argument");
1352
1353
0
#ifndef NO_PUTENV
1354
0
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1355
0
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1356
0
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1357
0
#endif
1358
1359
0
  if (flags & TJFLAG_LIMITSCANS) {
1360
0
    memset(&progress, 0, sizeof(struct my_progress_mgr));
1361
0
    progress.pub.progress_monitor = my_progress_monitor;
1362
0
    progress.this = this;
1363
0
    dinfo->progress = &progress.pub;
1364
0
  } else
1365
0
    dinfo->progress = NULL;
1366
1367
0
  if (setjmp(this->jerr.setjmp_buffer)) {
1368
    /* If we get here, the JPEG code has signaled an error. */
1369
0
    retval = -1;  goto bailout;
1370
0
  }
1371
1372
0
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1373
0
  jpeg_read_header(dinfo, TRUE);
1374
0
  this->dinfo.out_color_space = pf2cs[pixelFormat];
1375
0
  if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1376
0
  if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1377
1378
0
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1379
0
  if (width == 0) width = jpegwidth;
1380
0
  if (height == 0) height = jpegheight;
1381
0
  for (i = 0; i < NUMSF; i++) {
1382
0
    scaledw = TJSCALED(jpegwidth, sf[i]);
1383
0
    scaledh = TJSCALED(jpegheight, sf[i]);
1384
0
    if (scaledw <= width && scaledh <= height)
1385
0
      break;
1386
0
  }
1387
0
  if (i >= NUMSF)
1388
0
    THROW("tjDecompress2(): Could not scale down to desired image dimensions");
1389
0
  width = scaledw;  height = scaledh;
1390
0
  dinfo->scale_num = sf[i].num;
1391
0
  dinfo->scale_denom = sf[i].denom;
1392
1393
0
  jpeg_start_decompress(dinfo);
1394
0
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1395
1396
0
  if ((row_pointer =
1397
0
       (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL)
1398
0
    THROW("tjDecompress2(): Memory allocation failure");
1399
0
  if (setjmp(this->jerr.setjmp_buffer)) {
1400
    /* If we get here, the JPEG code has signaled an error. */
1401
0
    retval = -1;  goto bailout;
1402
0
  }
1403
0
  for (i = 0; i < (int)dinfo->output_height; i++) {
1404
0
    if (flags & TJFLAG_BOTTOMUP)
1405
0
      row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * (size_t)pitch];
1406
0
    else
1407
0
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
1408
0
  }
1409
0
  while (dinfo->output_scanline < dinfo->output_height)
1410
0
    jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1411
0
                        dinfo->output_height - dinfo->output_scanline);
1412
0
  jpeg_finish_decompress(dinfo);
1413
1414
0
bailout:
1415
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1416
0
  free(row_pointer);
1417
0
  if (this->jerr.warning) retval = -1;
1418
0
  this->jerr.stopOnWarning = FALSE;
1419
0
  return retval;
1420
0
}
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
0
{
1439
0
  int i;
1440
1441
0
  dinfo->scale_num = dinfo->scale_denom = 1;
1442
1443
0
  if (subsamp == TJSAMP_GRAY) {
1444
0
    dinfo->num_components = dinfo->comps_in_scan = 1;
1445
0
    dinfo->jpeg_color_space = JCS_GRAYSCALE;
1446
0
  } else {
1447
0
    dinfo->num_components = dinfo->comps_in_scan = 3;
1448
0
    dinfo->jpeg_color_space = JCS_YCbCr;
1449
0
  }
1450
1451
0
  dinfo->comp_info = (jpeg_component_info *)
1452
0
    (*dinfo->mem->alloc_small) ((j_common_ptr)dinfo, JPOOL_IMAGE,
1453
0
                                dinfo->num_components *
1454
0
                                sizeof(jpeg_component_info));
1455
1456
0
  for (i = 0; i < dinfo->num_components; i++) {
1457
0
    jpeg_component_info *compptr = &dinfo->comp_info[i];
1458
1459
0
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[subsamp] / 8 : 1;
1460
0
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[subsamp] / 8 : 1;
1461
0
    compptr->component_index = i;
1462
0
    compptr->component_id = i + 1;
1463
0
    compptr->quant_tbl_no = compptr->dc_tbl_no =
1464
0
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
1465
0
    dinfo->cur_comp_info[i] = compptr;
1466
0
  }
1467
0
  dinfo->data_precision = 8;
1468
0
  for (i = 0; i < 2; i++) {
1469
0
    if (dinfo->quant_tbl_ptrs[i] == NULL)
1470
0
      dinfo->quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)dinfo);
1471
0
  }
1472
0
}
1473
1474
1475
static int my_read_markers(j_decompress_ptr dinfo)
1476
0
{
1477
0
  return JPEG_REACHED_SOS;
1478
0
}
1479
1480
static void my_reset_marker_reader(j_decompress_ptr dinfo)
1481
0
{
1482
0
}
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
0
{
1491
0
  JSAMPROW *row_pointer = NULL;
1492
0
  JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1493
0
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
1494
0
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1495
0
  JSAMPLE *ptr;
1496
0
  jpeg_component_info *compptr;
1497
0
  int (*old_read_markers) (j_decompress_ptr);
1498
0
  void (*old_reset_marker_reader) (j_decompress_ptr);
1499
1500
0
  GET_DINSTANCE(handle);
1501
0
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1502
1503
0
  for (i = 0; i < MAX_COMPONENTS; i++) {
1504
0
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;  inbuf[i] = NULL;
1505
0
  }
1506
1507
0
  if ((this->init & DECOMPRESS) == 0)
1508
0
    THROW("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
1509
1510
0
  if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP ||
1511
0
      dstBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1512
0
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1513
0
    THROW("tjDecodeYUVPlanes(): Invalid argument");
1514
0
  if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1515
0
    THROW("tjDecodeYUVPlanes(): Invalid argument");
1516
1517
0
  if (setjmp(this->jerr.setjmp_buffer)) {
1518
    /* If we get here, the JPEG code has signaled an error. */
1519
0
    retval = -1;  goto bailout;
1520
0
  }
1521
1522
0
  if (pixelFormat == TJPF_CMYK)
1523
0
    THROW("tjDecodeYUVPlanes(): Cannot decode YUV images into packed-pixel CMYK images.");
1524
1525
0
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1526
0
  dinfo->image_width = width;
1527
0
  dinfo->image_height = height;
1528
1529
0
#ifndef NO_PUTENV
1530
0
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1531
0
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1532
0
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1533
0
#endif
1534
1535
0
  dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
1536
0
  dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
1537
0
  dinfo->Se = DCTSIZE2 - 1;
1538
0
  setDecodeDefaults(dinfo, pixelFormat, subsamp, flags);
1539
0
  old_read_markers = dinfo->marker->read_markers;
1540
0
  dinfo->marker->read_markers = my_read_markers;
1541
0
  old_reset_marker_reader = dinfo->marker->reset_marker_reader;
1542
0
  dinfo->marker->reset_marker_reader = my_reset_marker_reader;
1543
0
  jpeg_read_header(dinfo, TRUE);
1544
0
  dinfo->marker->read_markers = old_read_markers;
1545
0
  dinfo->marker->reset_marker_reader = old_reset_marker_reader;
1546
1547
0
  this->dinfo.out_color_space = pf2cs[pixelFormat];
1548
0
  if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1549
0
  dinfo->do_fancy_upsampling = FALSE;
1550
0
  dinfo->Se = DCTSIZE2 - 1;
1551
0
  jinit_master_decompress(dinfo);
1552
0
  (*dinfo->upsample->start_pass) (dinfo);
1553
1554
0
  pw0 = PAD(width, dinfo->max_h_samp_factor);
1555
0
  ph0 = PAD(height, dinfo->max_v_samp_factor);
1556
1557
0
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1558
1559
0
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1560
0
    THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1561
0
  for (i = 0; i < height; i++) {
1562
0
    if (flags & TJFLAG_BOTTOMUP)
1563
0
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
1564
0
    else
1565
0
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
1566
0
  }
1567
0
  if (height < ph0)
1568
0
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1569
1570
0
  for (i = 0; i < dinfo->num_components; i++) {
1571
0
    compptr = &dinfo->comp_info[i];
1572
0
    _tmpbuf[i] =
1573
0
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1574
0
                        compptr->v_samp_factor + 32);
1575
0
    if (!_tmpbuf[i])
1576
0
      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1577
0
    tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1578
0
    if (!tmpbuf[i])
1579
0
      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1580
0
    for (row = 0; row < compptr->v_samp_factor; row++) {
1581
0
      unsigned char *_tmpbuf_aligned =
1582
0
        (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
1583
1584
0
      tmpbuf[i][row] =
1585
0
        &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1586
0
    }
1587
0
    pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
1588
0
    ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1589
0
    inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1590
0
    if (!inbuf[i])
1591
0
      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1592
0
    ptr = (JSAMPLE *)srcPlanes[i];
1593
0
    for (row = 0; row < ph[i]; row++) {
1594
0
      inbuf[i][row] = ptr;
1595
0
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1596
0
    }
1597
0
  }
1598
1599
0
  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
0
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
1605
0
    JDIMENSION inrow = 0, outrow = 0;
1606
1607
0
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
1608
0
         i++, compptr++)
1609
0
      jcopy_sample_rows(inbuf[i],
1610
0
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
1611
0
        compptr->v_samp_factor, pw[i]);
1612
0
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
1613
0
                                 dinfo->max_v_samp_factor, &row_pointer[row],
1614
0
                                 &outrow, dinfo->max_v_samp_factor);
1615
0
  }
1616
0
  jpeg_abort_decompress(dinfo);
1617
1618
0
bailout:
1619
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1620
0
  free(row_pointer);
1621
0
  for (i = 0; i < MAX_COMPONENTS; i++) {
1622
0
    free(tmpbuf[i]);
1623
0
    free(_tmpbuf[i]);
1624
0
    free(inbuf[i]);
1625
0
  }
1626
0
  if (this->jerr.warning) retval = -1;
1627
0
  this->jerr.stopOnWarning = FALSE;
1628
0
  return retval;
1629
0
}
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
0
{
1637
0
  const unsigned char *srcPlanes[3];
1638
0
  int pw0, ph0, strides[3], retval = -1;
1639
0
  tjinstance *this = (tjinstance *)handle;
1640
1641
0
  if (!this) THROWG("tjDecodeYUV(): Invalid handle");
1642
0
  this->isInstanceError = FALSE;
1643
1644
0
  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || subsamp < 0 ||
1645
0
      subsamp >= TJ_NUMSAMP || width <= 0 || height <= 0)
1646
0
    THROW("tjDecodeYUV(): Invalid argument");
1647
1648
0
  pw0 = tjPlaneWidth(0, width, subsamp);
1649
0
  ph0 = tjPlaneHeight(0, height, subsamp);
1650
0
  srcPlanes[0] = srcBuf;
1651
0
  strides[0] = PAD(pw0, align);
1652
0
  if (subsamp == TJSAMP_GRAY) {
1653
0
    strides[1] = strides[2] = 0;
1654
0
    srcPlanes[1] = srcPlanes[2] = NULL;
1655
0
  } else {
1656
0
    int pw1 = tjPlaneWidth(1, width, subsamp);
1657
0
    int ph1 = tjPlaneHeight(1, height, subsamp);
1658
1659
0
    strides[1] = strides[2] = PAD(pw1, align);
1660
0
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1661
0
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1662
0
  }
1663
1664
0
  return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1665
0
                           pitch, height, pixelFormat, flags);
1666
1667
0
bailout:
1668
0
  return retval;
1669
0
}
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
0
{
1678
0
  int i, sfi, row, retval = 0;
1679
0
  int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
1680
0
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1681
0
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1682
0
  JSAMPLE *_tmpbuf = NULL, *ptr;
1683
0
  JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1684
0
  int dctsize;
1685
0
  struct my_progress_mgr progress;
1686
1687
0
  GET_DINSTANCE(handle);
1688
0
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1689
1690
0
  for (i = 0; i < MAX_COMPONENTS; i++) {
1691
0
    tmpbuf[i] = NULL;  outbuf[i] = NULL;
1692
0
  }
1693
1694
0
  if ((this->init & DECOMPRESS) == 0)
1695
0
    THROW("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
1696
1697
0
  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0] ||
1698
0
      width < 0 || height < 0)
1699
0
    THROW("tjDecompressToYUVPlanes(): Invalid argument");
1700
1701
0
#ifndef NO_PUTENV
1702
0
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1703
0
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1704
0
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1705
0
#endif
1706
1707
0
  if (flags & TJFLAG_LIMITSCANS) {
1708
0
    memset(&progress, 0, sizeof(struct my_progress_mgr));
1709
0
    progress.pub.progress_monitor = my_progress_monitor;
1710
0
    progress.this = this;
1711
0
    dinfo->progress = &progress.pub;
1712
0
  } else
1713
0
    dinfo->progress = NULL;
1714
1715
0
  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
0
  if (!this->headerRead) {
1721
0
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1722
0
    jpeg_read_header(dinfo, TRUE);
1723
0
  }
1724
0
  this->headerRead = 0;
1725
0
  jpegSubsamp = getSubsamp(dinfo);
1726
0
  if (jpegSubsamp < 0)
1727
0
    THROW("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1728
1729
0
  if (jpegSubsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1730
0
    THROW("tjDecompressToYUVPlanes(): Invalid argument");
1731
1732
0
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1733
0
  if (width == 0) width = jpegwidth;
1734
0
  if (height == 0) height = jpegheight;
1735
0
  for (i = 0; i < NUMSF; i++) {
1736
0
    scaledw = TJSCALED(jpegwidth, sf[i]);
1737
0
    scaledh = TJSCALED(jpegheight, sf[i]);
1738
0
    if (scaledw <= width && scaledh <= height)
1739
0
      break;
1740
0
  }
1741
0
  if (i >= NUMSF)
1742
0
    THROW("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
1743
0
  if (dinfo->num_components > 3)
1744
0
    THROW("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
1745
1746
0
  width = scaledw;  height = scaledh;
1747
0
  dinfo->scale_num = sf[i].num;
1748
0
  dinfo->scale_denom = sf[i].denom;
1749
0
  sfi = i;
1750
0
  jpeg_calc_output_dimensions(dinfo);
1751
1752
0
  dctsize = DCTSIZE * sf[sfi].num / sf[sfi].denom;
1753
1754
0
  for (i = 0; i < dinfo->num_components; i++) {
1755
0
    jpeg_component_info *compptr = &dinfo->comp_info[i];
1756
0
    int ih;
1757
1758
0
    iw[i] = compptr->width_in_blocks * dctsize;
1759
0
    ih = compptr->height_in_blocks * dctsize;
1760
0
    pw[i] = tjPlaneWidth(i, dinfo->output_width, jpegSubsamp);
1761
0
    ph[i] = tjPlaneHeight(i, dinfo->output_height, jpegSubsamp);
1762
0
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1763
0
    th[i] = compptr->v_samp_factor * dctsize;
1764
0
    tmpbufsize += iw[i] * th[i];
1765
0
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1766
0
      THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
1767
0
    ptr = dstPlanes[i];
1768
0
    for (row = 0; row < ph[i]; row++) {
1769
0
      outbuf[i][row] = ptr;
1770
0
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1771
0
    }
1772
0
  }
1773
0
  if (usetmpbuf) {
1774
0
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1775
0
      THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
1776
0
    ptr = _tmpbuf;
1777
0
    for (i = 0; i < dinfo->num_components; i++) {
1778
0
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1779
0
        THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
1780
0
      for (row = 0; row < th[i]; row++) {
1781
0
        tmpbuf[i][row] = ptr;
1782
0
        ptr += iw[i];
1783
0
      }
1784
0
    }
1785
0
  }
1786
1787
0
  if (setjmp(this->jerr.setjmp_buffer)) {
1788
    /* If we get here, the JPEG code has signaled an error. */
1789
0
    retval = -1;  goto bailout;
1790
0
  }
1791
1792
0
  if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1793
0
  if (flags & TJFLAG_FASTDCT) dinfo->dct_method = JDCT_FASTEST;
1794
0
  dinfo->raw_data_out = TRUE;
1795
1796
0
  jpeg_start_decompress(dinfo);
1797
0
  for (row = 0; row < (int)dinfo->output_height;
1798
0
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
1799
0
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1800
0
    int crow[MAX_COMPONENTS];
1801
1802
0
    for (i = 0; i < dinfo->num_components; i++) {
1803
0
      jpeg_component_info *compptr = &dinfo->comp_info[i];
1804
1805
0
      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
0
        compptr->_DCT_scaled_size = dctsize;
1817
0
        compptr->MCU_sample_width = tjMCUWidth[jpegSubsamp] *
1818
0
          sf[sfi].num / sf[sfi].denom *
1819
0
          compptr->v_samp_factor / dinfo->max_v_samp_factor;
1820
0
        dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1821
0
      }
1822
0
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1823
0
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
1824
0
      else yuvptr[i] = &outbuf[i][crow[i]];
1825
0
    }
1826
0
    jpeg_read_raw_data(dinfo, yuvptr,
1827
0
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
1828
0
    if (usetmpbuf) {
1829
0
      int j;
1830
1831
0
      for (i = 0; i < dinfo->num_components; i++) {
1832
0
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1833
0
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
1834
0
        }
1835
0
      }
1836
0
    }
1837
0
  }
1838
0
  jpeg_finish_decompress(dinfo);
1839
1840
0
bailout:
1841
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1842
0
  for (i = 0; i < MAX_COMPONENTS; i++) {
1843
0
    free(tmpbuf[i]);
1844
0
    free(outbuf[i]);
1845
0
  }
1846
0
  free(_tmpbuf);
1847
0
  if (this->jerr.warning) retval = -1;
1848
0
  this->jerr.stopOnWarning = FALSE;
1849
0
  return retval;
1850
0
}
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
0
{
1857
0
  unsigned char *dstPlanes[3];
1858
0
  int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1;
1859
0
  int i, jpegwidth, jpegheight, scaledw, scaledh;
1860
1861
0
  GET_DINSTANCE(handle);
1862
0
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1863
1864
0
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1865
0
      align < 1 || !IS_POW2(align) || height < 0)
1866
0
    THROW("tjDecompressToYUV2(): Invalid argument");
1867
1868
0
  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
0
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1874
0
  jpeg_read_header(dinfo, TRUE);
1875
0
  jpegSubsamp = getSubsamp(dinfo);
1876
0
  if (jpegSubsamp < 0)
1877
0
    THROW("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1878
1879
0
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1880
0
  if (width == 0) width = jpegwidth;
1881
0
  if (height == 0) height = jpegheight;
1882
0
  for (i = 0; i < NUMSF; i++) {
1883
0
    scaledw = TJSCALED(jpegwidth, sf[i]);
1884
0
    scaledh = TJSCALED(jpegheight, sf[i]);
1885
0
    if (scaledw <= width && scaledh <= height)
1886
0
      break;
1887
0
  }
1888
0
  if (i >= NUMSF)
1889
0
    THROW("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1890
1891
0
  width = scaledw;  height = scaledh;
1892
1893
0
  pw0 = tjPlaneWidth(0, width, jpegSubsamp);
1894
0
  ph0 = tjPlaneHeight(0, height, jpegSubsamp);
1895
0
  dstPlanes[0] = dstBuf;
1896
0
  strides[0] = PAD(pw0, align);
1897
0
  if (jpegSubsamp == TJSAMP_GRAY) {
1898
0
    strides[1] = strides[2] = 0;
1899
0
    dstPlanes[1] = dstPlanes[2] = NULL;
1900
0
  } else {
1901
0
    int pw1 = tjPlaneWidth(1, width, jpegSubsamp);
1902
0
    int ph1 = tjPlaneHeight(1, height, jpegSubsamp);
1903
1904
0
    strides[1] = strides[2] = PAD(pw1, align);
1905
0
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1906
0
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1907
0
  }
1908
1909
0
  this->headerRead = 1;
1910
0
  return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1911
0
                                 strides, height, flags);
1912
1913
0
bailout:
1914
0
  this->jerr.stopOnWarning = FALSE;
1915
0
  return retval;
1916
0
}
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
0
{
1932
0
  tjinstance *this = NULL;
1933
0
  tjhandle handle = NULL;
1934
1935
0
  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
0
  memset(this, 0, sizeof(tjinstance));
1941
0
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
1942
0
  handle = _tjInitCompress(this);
1943
0
  if (!handle) return NULL;
1944
0
  handle = _tjInitDecompress(this);
1945
0
  return handle;
1946
0
}
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
0
{
1955
0
  jpeg_transform_info *xinfo = NULL;
1956
0
  jvirt_barray_ptr *srccoefs, *dstcoefs;
1957
0
  int retval = 0, i, jpegSubsamp, saveMarkers = 0;
1958
0
  boolean alloc = TRUE;
1959
0
  struct my_progress_mgr progress;
1960
1961
0
  GET_INSTANCE(handle);
1962
0
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1963
0
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
1964
0
    THROW("tjTransform(): Instance has not been initialized for transformation");
1965
1966
0
  if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
1967
0
      dstSizes == NULL || t == NULL || flags < 0)
1968
0
    THROW("tjTransform(): Invalid argument");
1969
1970
0
#ifndef NO_PUTENV
1971
0
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1972
0
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1973
0
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1974
0
#endif
1975
1976
0
  if (flags & TJFLAG_LIMITSCANS) {
1977
0
    memset(&progress, 0, sizeof(struct my_progress_mgr));
1978
0
    progress.pub.progress_monitor = my_progress_monitor;
1979
0
    progress.this = this;
1980
0
    dinfo->progress = &progress.pub;
1981
0
  } else
1982
0
    dinfo->progress = NULL;
1983
1984
0
  if ((xinfo =
1985
0
       (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
1986
0
    THROW("tjTransform(): Memory allocation failure");
1987
0
  memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
1988
1989
0
  if (setjmp(this->jerr.setjmp_buffer)) {
1990
    /* If we get here, the JPEG code has signaled an error. */
1991
0
    retval = -1;  goto bailout;
1992
0
  }
1993
1994
0
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1995
1996
0
  for (i = 0; i < n; i++) {
1997
0
    xinfo[i].transform = xformtypes[t[i].op];
1998
0
    xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
1999
0
    xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
2000
0
    xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
2001
0
    xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
2002
0
    if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
2003
0
    else xinfo[i].slow_hflip = 0;
2004
2005
0
    if (xinfo[i].crop) {
2006
0
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
2007
0
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
2008
0
      if (t[i].r.w != 0) {
2009
0
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
2010
0
      } else
2011
0
        xinfo[i].crop_width = JCROP_UNSET;
2012
0
      if (t[i].r.h != 0) {
2013
0
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
2014
0
      } else
2015
0
        xinfo[i].crop_height = JCROP_UNSET;
2016
0
    }
2017
0
    if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
2018
0
  }
2019
2020
0
  jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
2021
0
  jpeg_read_header(dinfo, TRUE);
2022
0
  jpegSubsamp = getSubsamp(dinfo);
2023
0
  if (jpegSubsamp < 0)
2024
0
    THROW("tjTransform(): Could not determine subsampling type for JPEG image");
2025
2026
0
  for (i = 0; i < n; i++) {
2027
0
    if (!jtransform_request_workspace(dinfo, &xinfo[i]))
2028
0
      THROW("tjTransform(): Transform is not perfect");
2029
2030
0
    if (xinfo[i].crop) {
2031
0
      if ((t[i].r.x % tjMCUWidth[jpegSubsamp]) != 0 ||
2032
0
          (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
0
    }
2041
0
  }
2042
2043
0
  srccoefs = jpeg_read_coefficients(dinfo);
2044
2045
0
  for (i = 0; i < n; i++) {
2046
0
    int w, h;
2047
2048
0
    if (!xinfo[i].crop) {
2049
0
      w = dinfo->image_width;  h = dinfo->image_height;
2050
0
    } else {
2051
0
      w = xinfo[i].crop_width;  h = xinfo[i].crop_height;
2052
0
    }
2053
0
    if (flags & TJFLAG_NOREALLOC) {
2054
0
      alloc = FALSE;  dstSizes[i] = tjBufSize(w, h, jpegSubsamp);
2055
0
    }
2056
0
    if (!(t[i].options & TJXOPT_NOOUTPUT))
2057
0
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2058
0
    jpeg_copy_critical_parameters(dinfo, cinfo);
2059
0
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
2060
0
#ifdef C_PROGRESSIVE_SUPPORTED
2061
0
    if (flags & TJFLAG_PROGRESSIVE || t[i].options & TJXOPT_PROGRESSIVE)
2062
0
      jpeg_simple_progression(cinfo);
2063
0
#endif
2064
0
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
2065
0
      jpeg_write_coefficients(cinfo, dstcoefs);
2066
0
      jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
2067
0
                                          JCOPYOPT_NONE : JCOPYOPT_ALL);
2068
0
    } else
2069
0
      jinit_c_master_control(cinfo, TRUE);
2070
0
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
2071
0
    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
0
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2101
0
  }
2102
2103
0
  jpeg_finish_decompress(dinfo);
2104
2105
0
bailout:
2106
0
  if (cinfo->global_state > CSTATE_START) {
2107
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
2108
0
    jpeg_abort_compress(cinfo);
2109
0
  }
2110
0
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2111
0
  free(xinfo);
2112
0
  if (this->jerr.warning) retval = -1;
2113
0
  this->jerr.stopOnWarning = FALSE;
2114
0
  return retval;
2115
0
}
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
19.3k
{
2125
19.3k
  int retval = 0, tempc;
2126
19.3k
  size_t pitch;
2127
19.3k
  tjhandle handle = NULL;
2128
19.3k
  tjinstance *this;
2129
19.3k
  j_compress_ptr cinfo = NULL;
2130
19.3k
  cjpeg_source_ptr src;
2131
19.3k
  unsigned char *dstBuf = NULL;
2132
19.3k
  FILE *file = NULL;
2133
19.3k
  boolean invert;
2134
2135
19.3k
  if (!filename || !width || align < 1 || !height || !pixelFormat ||
2136
19.3k
      *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF)
2137
19.3k
    THROWG("tjLoadImage(): Invalid argument");
2138
19.3k
  if ((align & (align - 1)) != 0)
2139
19.3k
    THROWG("tjLoadImage(): Alignment must be a power of 2");
2140
2141
19.3k
  if ((handle = tjInitCompress()) == NULL) return NULL;
2142
19.3k
  this = (tjinstance *)handle;
2143
19.3k
  cinfo = &this->cinfo;
2144
2145
#ifdef _MSC_VER
2146
  if (fopen_s(&file, filename, "rb") || file == NULL)
2147
#else
2148
19.3k
  if ((file = fopen(filename, "rb")) == NULL)
2149
0
#endif
2150
19.3k
    THROW_UNIX("tjLoadImage(): Cannot open input file");
2151
2152
19.3k
  if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
2153
0
    THROW_UNIX("tjLoadImage(): Could not read input file")
2154
19.3k
  else if (tempc == EOF)
2155
19.3k
    THROWG("tjLoadImage(): Input file contains no data");
2156
2157
19.3k
  if (setjmp(this->jerr.setjmp_buffer)) {
2158
    /* If we get here, the JPEG code has signaled an error. */
2159
6.78k
    retval = -1;  goto bailout;
2160
6.78k
  }
2161
2162
12.5k
  if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN;
2163
12.5k
  else cinfo->in_color_space = pf2cs[*pixelFormat];
2164
12.5k
  if (tempc == 'B') {
2165
6.04k
    if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL)
2166
6.04k
      THROWG("tjLoadImage(): Could not initialize bitmap loader");
2167
6.04k
    invert = (flags & TJFLAG_BOTTOMUP) == 0;
2168
13.1k
  } else if (tempc == 'P') {
2169
13.1k
    if ((src = jinit_read_ppm(cinfo)) == NULL)
2170
13.1k
      THROWG("tjLoadImage(): Could not initialize PPM loader");
2171
13.1k
    invert = (flags & TJFLAG_BOTTOMUP) != 0;
2172
13.1k
  } else
2173
18.4E
    THROWG("tjLoadImage(): Unsupported file type");
2174
2175
19.1k
  src->input_file = file;
2176
19.1k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2177
  /* Refuse to load images larger than 1 Megapixel when fuzzing. */
2178
19.1k
  if (flags & TJFLAG_FUZZING)
2179
19.1k
    src->max_pixels = 1048576;
2180
19.1k
#endif
2181
19.1k
  (*src->start_input) (cinfo, src);
2182
19.1k
  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
2183
2184
19.1k
  *width = cinfo->image_width;  *height = cinfo->image_height;
2185
19.1k
  *pixelFormat = cs2pf[cinfo->in_color_space];
2186
2187
19.1k
  pitch = PAD((*width) * tjPixelSize[*pixelFormat], align);
2188
19.1k
  if ((unsigned long long)pitch * (unsigned long long)(*height) >
2189
19.1k
      (unsigned long long)((size_t)-1) ||
2190
19.1k
      (dstBuf = (unsigned char *)malloc(pitch * (*height))) == NULL)
2191
19.1k
    THROWG("tjLoadImage(): Memory allocation failure");
2192
2193
19.1k
  if (setjmp(this->jerr.setjmp_buffer)) {
2194
    /* If we get here, the JPEG code has signaled an error. */
2195
5.77k
    retval = -1;  goto bailout;
2196
5.77k
  }
2197
2198
20.7M
  while (cinfo->next_scanline < cinfo->image_height) {
2199
20.7M
    int i, nlines = (*src->get_pixel_rows) (cinfo, src);
2200
2201
41.5M
    for (i = 0; i < nlines; i++) {
2202
20.7M
      unsigned char *dstptr;
2203
20.7M
      int row;
2204
2205
20.7M
      row = cinfo->next_scanline + i;
2206
20.7M
      if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch];
2207
17.5M
      else dstptr = &dstBuf[row * pitch];
2208
20.7M
      memcpy(dstptr, src->buffer[i], (*width) * tjPixelSize[*pixelFormat]);
2209
20.7M
    }
2210
20.7M
    cinfo->next_scanline += nlines;
2211
20.7M
  }
2212
2213
13.4k
  (*src->finish_input) (cinfo, src);
2214
2215
19.3k
bailout:
2216
19.3k
  if (handle) tjDestroy(handle);
2217
19.3k
  if (file) fclose(file);
2218
19.3k
  if (retval < 0) { free(dstBuf);  dstBuf = NULL; }
2219
19.3k
  return dstBuf;
2220
13.4k
}
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
}