Coverage Report

Created: 2024-07-03 12:02

/src/libjpeg-turbo.main/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
0
#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
180k
{
76
180k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
77
78
180k
  (*cinfo->err->output_message) (cinfo);
79
180k
  longjmp(myerr->setjmp_buffer, 1);
80
180k
}
81
82
/* Based on output_message() in jerror.c */
83
84
static void my_output_message(j_common_ptr cinfo)
85
412k
{
86
412k
  (*cinfo->err->format_message) (cinfo, errStr);
87
412k
}
88
89
static void my_emit_message(j_common_ptr cinfo, int msg_level)
90
97.1M
{
91
97.1M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
92
93
97.1M
  myerr->emit_message(cinfo, msg_level);
94
97.1M
  if (msg_level < 0) {
95
77.3M
    myerr->warning = TRUE;
96
77.3M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
97
77.3M
  }
98
97.1M
}
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
47.5M
{
122
47.5M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
123
47.5M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
124
125
47.5M
  if (dinfo->is_decompressor) {
126
47.5M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
127
128
47.5M
    if (scan_no > 500) {
129
202
      SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
130
202
               "Progressive JPEG image has more than 500 scans");
131
202
      SNPRINTF(errStr, JMSG_LENGTH_MAX,
132
202
               "Progressive JPEG image has more than 500 scans");
133
202
      myprog->this->isInstanceError = TRUE;
134
202
      myerr->warning = FALSE;
135
202
      longjmp(myerr->setjmp_buffer, 1);
136
202
    }
137
47.5M
  }
138
47.5M
}
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
1.54M
#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
33.7k
#define THROWG(m) { \
194
33.7k
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s", m); \
195
33.7k
  retval = -1;  goto bailout; \
196
33.7k
}
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
33.7k
#define THROW(m) { \
211
33.7k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
212
33.7k
  this->isInstanceError = TRUE;  THROWG(m) \
213
33.7k
}
214
215
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
216
/* Private flag that triggers different TurboJPEG API behavior when fuzzing */
217
0
#define TJFLAG_FUZZING  (1 << 30)
218
#endif
219
220
#define GET_INSTANCE(handle) \
221
147k
  tjinstance *this = (tjinstance *)handle; \
222
147k
  j_compress_ptr cinfo = NULL; \
223
147k
  j_decompress_ptr dinfo = NULL; \
224
147k
  \
225
147k
  if (!this) { \
226
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
227
0
    return -1; \
228
0
  } \
229
147k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
230
147k
  this->jerr.warning = FALSE; \
231
147k
  this->isInstanceError = FALSE;
232
233
#define GET_CINSTANCE(handle) \
234
0
  tjinstance *this = (tjinstance *)handle; \
235
0
  j_compress_ptr cinfo = NULL; \
236
0
  \
237
0
  if (!this) { \
238
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
239
0
    return -1; \
240
0
  } \
241
0
  cinfo = &this->cinfo; \
242
0
  this->jerr.warning = FALSE; \
243
0
  this->isInstanceError = FALSE;
244
245
#define GET_DINSTANCE(handle) \
246
307k
  tjinstance *this = (tjinstance *)handle; \
247
307k
  j_decompress_ptr dinfo = NULL; \
248
307k
  \
249
307k
  if (!this) { \
250
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
251
0
    return -1; \
252
0
  } \
253
307k
  dinfo = &this->dinfo; \
254
307k
  this->jerr.warning = FALSE; \
255
307k
  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
0
{
280
0
#ifndef NO_GETENV
281
0
  char env[7] = { 0 };
282
0
#endif
283
284
0
  cinfo->in_color_space = pf2cs[pixelFormat];
285
0
  cinfo->input_components = tjPixelSize[pixelFormat];
286
0
  jpeg_set_defaults(cinfo);
287
288
0
#ifndef NO_GETENV
289
0
  if (!GETENV_S(env, 7, "TJ_OPTIMIZE") && !strcmp(env, "1"))
290
0
    cinfo->optimize_coding = TRUE;
291
0
  if (!GETENV_S(env, 7, "TJ_ARITHMETIC") && !strcmp(env, "1"))
292
0
    cinfo->arith_code = TRUE;
293
0
  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
0
#endif
312
313
0
  if (jpegQual >= 0) {
314
0
    jpeg_set_quality(cinfo, jpegQual, TRUE);
315
0
    if (jpegQual >= 96 || flags & TJFLAG_ACCURATEDCT)
316
0
      cinfo->dct_method = JDCT_ISLOW;
317
0
    else
318
0
      cinfo->dct_method = JDCT_FASTEST;
319
0
  }
320
0
  if (subsamp == TJSAMP_GRAY)
321
0
    jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
322
0
  else if (pixelFormat == TJPF_CMYK)
323
0
    jpeg_set_colorspace(cinfo, JCS_YCCK);
324
0
  else
325
0
    jpeg_set_colorspace(cinfo, JCS_YCbCr);
326
327
0
#ifdef C_PROGRESSIVE_SUPPORTED
328
0
  if (flags & TJFLAG_PROGRESSIVE)
329
0
    jpeg_simple_progression(cinfo);
330
0
#ifndef NO_GETENV
331
0
  else if (!GETENV_S(env, 7, "TJ_PROGRESSIVE") && !strcmp(env, "1"))
332
0
    jpeg_simple_progression(cinfo);
333
0
#endif
334
0
#endif
335
336
0
  cinfo->comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
337
0
  cinfo->comp_info[1].h_samp_factor = 1;
338
0
  cinfo->comp_info[2].h_samp_factor = 1;
339
0
  if (cinfo->num_components > 3)
340
0
    cinfo->comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
341
0
  cinfo->comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
342
0
  cinfo->comp_info[1].v_samp_factor = 1;
343
0
  cinfo->comp_info[2].v_samp_factor = 1;
344
0
  if (cinfo->num_components > 3)
345
0
    cinfo->comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
346
0
}
347
348
349
static int getSubsamp(j_decompress_ptr dinfo)
350
42.7k
{
351
42.7k
  int retval = -1, i, k;
352
353
  /* The sampling factors actually have no meaning with grayscale JPEG files,
354
     and in fact it's possible to generate grayscale JPEGs with sampling
355
     factors > 1 (even though those sampling factors are ignored by the
356
     decompressor.)  Thus, we need to treat grayscale as a special case. */
357
42.7k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
358
1.00k
    return TJSAMP_GRAY;
359
360
258k
  for (i = 0; i < TJ_NUMSAMP; i++) {
361
224k
    if (dinfo->num_components == pixelsize[i] ||
362
224k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
363
52.3k
          dinfo->jpeg_color_space == JCS_CMYK) &&
364
185k
         pixelsize[i] == 3 && dinfo->num_components == 4)) {
365
185k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
366
185k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
367
36.6k
        int match = 0;
368
369
112k
        for (k = 1; k < dinfo->num_components; k++) {
370
75.8k
          int href = 1, vref = 1;
371
372
75.8k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
373
75.8k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
374
2.51k
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
375
2.51k
          }
376
75.8k
          if (dinfo->comp_info[k].h_samp_factor == href &&
377
75.8k
              dinfo->comp_info[k].v_samp_factor == vref)
378
39.2k
            match++;
379
75.8k
        }
380
36.6k
        if (match == dinfo->num_components - 1) {
381
7.78k
          retval = i;  break;
382
7.78k
        }
383
36.6k
      }
384
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
385
         in non-standard ways. */
386
178k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
387
178k
          dinfo->comp_info[0].v_samp_factor == 2 &&
388
178k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
389
9.04k
        int match = 0;
390
391
27.4k
        for (k = 1; k < dinfo->num_components; k++) {
392
18.3k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
393
394
18.3k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
395
18.3k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
396
294
            href = vref = 2;
397
294
          }
398
18.3k
          if (dinfo->comp_info[k].h_samp_factor == href &&
399
18.3k
              dinfo->comp_info[k].v_samp_factor == vref)
400
695
            match++;
401
18.3k
        }
402
9.04k
        if (match == dinfo->num_components - 1) {
403
121
          retval = i;  break;
404
121
        }
405
9.04k
      }
406
      /* Handle 4:4:4 images whose sampling factors are specified in
407
         non-standard ways. */
408
177k
      if (dinfo->comp_info[0].h_samp_factor *
409
177k
          dinfo->comp_info[0].v_samp_factor <=
410
177k
          D_MAX_BLOCKS_IN_MCU / pixelsize[i] && i == TJSAMP_444) {
411
26.9k
        int match = 0;
412
83.1k
        for (k = 1; k < dinfo->num_components; k++) {
413
56.2k
          if (dinfo->comp_info[k].h_samp_factor ==
414
56.2k
              dinfo->comp_info[0].h_samp_factor &&
415
56.2k
              dinfo->comp_info[k].v_samp_factor ==
416
15.9k
              dinfo->comp_info[0].v_samp_factor)
417
512
            match++;
418
56.2k
          if (match == dinfo->num_components - 1) {
419
30
            retval = i;  break;
420
30
          }
421
56.2k
        }
422
26.9k
      }
423
177k
    }
424
224k
  }
425
41.7k
  return retval;
426
42.7k
}
427
428
429
/*************************** General API functions ***************************/
430
431
/* TurboJPEG 2.0+ */
432
DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
433
0
{
434
0
  tjinstance *this = (tjinstance *)handle;
435
436
0
  if (this && this->isInstanceError) {
437
0
    this->isInstanceError = FALSE;
438
0
    return this->errStr;
439
0
  } else
440
0
    return errStr;
441
0
}
442
443
444
/* TurboJPEG 1.0+ */
445
DLLEXPORT char *tjGetErrorStr(void)
446
0
{
447
0
  return errStr;
448
0
}
449
450
451
/* TurboJPEG 2.0+ */
452
DLLEXPORT int tjGetErrorCode(tjhandle handle)
453
0
{
454
0
  tjinstance *this = (tjinstance *)handle;
455
456
0
  if (this && this->jerr.warning) return TJERR_WARNING;
457
0
  else return TJERR_FATAL;
458
0
}
459
460
461
/* TurboJPEG 1.0+ */
462
DLLEXPORT int tjDestroy(tjhandle handle)
463
147k
{
464
147k
  GET_INSTANCE(handle);
465
466
147k
  if (setjmp(this->jerr.setjmp_buffer)) return -1;
467
147k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
468
147k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
469
147k
  free(this);
470
147k
  return 0;
471
147k
}
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
0
{
482
0
  free(buf);
483
0
}
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
0
{
497
0
  static unsigned char buffer[1];
498
0
  unsigned char *buf = buffer;
499
0
  unsigned long size = 1;
500
501
  /* This is also straight out of example.txt */
502
0
  this->cinfo.err = jpeg_std_error(&this->jerr.pub);
503
0
  this->jerr.pub.error_exit = my_error_exit;
504
0
  this->jerr.pub.output_message = my_output_message;
505
0
  this->jerr.emit_message = this->jerr.pub.emit_message;
506
0
  this->jerr.pub.emit_message = my_emit_message;
507
0
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
508
0
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
509
0
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
510
511
0
  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
0
  jpeg_create_compress(&this->cinfo);
518
  /* Make an initial call so it will create the destination manager */
519
0
  jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
520
521
0
  this->init |= COMPRESS;
522
0
  return (tjhandle)this;
523
0
}
524
525
/* TurboJPEG 1.0+ */
526
DLLEXPORT tjhandle tjInitCompress(void)
527
0
{
528
0
  tjinstance *this = NULL;
529
530
0
  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
0
  memset(this, 0, sizeof(tjinstance));
536
0
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
537
0
  return _tjInitCompress(this);
538
0
}
539
540
541
/* TurboJPEG 1.2+ */
542
DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
543
0
{
544
0
  unsigned long long retval = 0;
545
0
  int mcuw, mcuh, chromasf;
546
547
0
  if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP)
548
0
    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
0
  mcuw = tjMCUWidth[jpegSubsamp];
554
0
  mcuh = tjMCUHeight[jpegSubsamp];
555
0
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
556
0
  retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
557
0
  if (retval > (unsigned long long)((unsigned long)-1))
558
0
    THROWG("tjBufSize(): Image is too large");
559
560
0
bailout:
561
0
  return (unsigned long)retval;
562
0
}
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
0
{
707
0
  int i, retval = 0;
708
0
  boolean alloc = TRUE;
709
0
  JSAMPROW *row_pointer = NULL;
710
711
0
  GET_CINSTANCE(handle)
712
0
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
713
0
  if ((this->init & COMPRESS) == 0)
714
0
    THROW("tjCompress2(): Instance has not been initialized for compression");
715
716
0
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
717
0
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
718
0
      jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP ||
719
0
      jpegQual < 0 || jpegQual > 100)
720
0
    THROW("tjCompress2(): Invalid argument");
721
722
0
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
723
724
0
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * height)) == NULL)
725
0
    THROW("tjCompress2(): Memory allocation failure");
726
727
0
  if (setjmp(this->jerr.setjmp_buffer)) {
728
    /* If we get here, the JPEG code has signaled an error. */
729
0
    retval = -1;  goto bailout;
730
0
  }
731
732
0
  cinfo->image_width = width;
733
0
  cinfo->image_height = height;
734
735
0
#ifndef NO_PUTENV
736
0
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
737
0
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
738
0
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
739
0
#endif
740
741
0
  if (flags & TJFLAG_NOREALLOC) {
742
0
    alloc = FALSE;  *jpegSize = tjBufSize(width, height, jpegSubsamp);
743
0
  }
744
0
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
745
0
  setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags);
746
747
0
  jpeg_start_compress(cinfo, TRUE);
748
0
  for (i = 0; i < height; i++) {
749
0
    if (flags & TJFLAG_BOTTOMUP)
750
0
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
751
0
    else
752
0
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
753
0
  }
754
0
  while (cinfo->next_scanline < cinfo->image_height)
755
0
    jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
756
0
                         cinfo->image_height - cinfo->next_scanline);
757
0
  jpeg_finish_compress(cinfo);
758
759
0
bailout:
760
0
  if (cinfo->global_state > CSTATE_START) {
761
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
762
0
    jpeg_abort_compress(cinfo);
763
0
  }
764
0
  free(row_pointer);
765
0
  if (this->jerr.warning) retval = -1;
766
0
  this->jerr.stopOnWarning = FALSE;
767
0
  return retval;
768
0
}
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
147k
{
1198
147k
  static unsigned char buffer[1];
1199
1200
  /* This is also straight out of example.txt */
1201
147k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1202
147k
  this->jerr.pub.error_exit = my_error_exit;
1203
147k
  this->jerr.pub.output_message = my_output_message;
1204
147k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1205
147k
  this->jerr.pub.emit_message = my_emit_message;
1206
147k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1207
147k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1208
147k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1209
1210
147k
  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
147k
  jpeg_create_decompress(&this->dinfo);
1217
  /* Make an initial call so it will create the source manager */
1218
147k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1219
1220
147k
  this->init |= DECOMPRESS;
1221
147k
  return (tjhandle)this;
1222
147k
}
1223
1224
/* TurboJPEG 1.0+ */
1225
DLLEXPORT tjhandle tjInitDecompress(void)
1226
147k
{
1227
147k
  tjinstance *this;
1228
1229
147k
  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
147k
  memset(this, 0, sizeof(tjinstance));
1235
147k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
1236
147k
  return _tjInitDecompress(this);
1237
147k
}
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
147k
{
1247
147k
  int retval = 0;
1248
1249
147k
  GET_DINSTANCE(handle);
1250
147k
  if ((this->init & DECOMPRESS) == 0)
1251
147k
    THROW("tjDecompressHeader3(): Instance has not been initialized for decompression");
1252
1253
147k
  if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL ||
1254
147k
      jpegSubsamp == NULL || jpegColorspace == NULL)
1255
147k
    THROW("tjDecompressHeader3(): Invalid argument");
1256
1257
147k
  if (setjmp(this->jerr.setjmp_buffer)) {
1258
    /* If we get here, the JPEG code has signaled an error. */
1259
69.4k
    return -1;
1260
69.4k
  }
1261
1262
78.3k
  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
78.3k
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1269
35.6k
    return 0;
1270
1271
42.7k
  *width = dinfo->image_width;
1272
42.7k
  *height = dinfo->image_height;
1273
42.7k
  *jpegSubsamp = getSubsamp(dinfo);
1274
42.7k
  switch (dinfo->jpeg_color_space) {
1275
1.00k
  case JCS_GRAYSCALE:  *jpegColorspace = TJCS_GRAY;  break;
1276
1.26k
  case JCS_RGB:        *jpegColorspace = TJCS_RGB;  break;
1277
36.7k
  case JCS_YCbCr:      *jpegColorspace = TJCS_YCbCr;  break;
1278
1.56k
  case JCS_CMYK:       *jpegColorspace = TJCS_CMYK;  break;
1279
1.10k
  case JCS_YCCK:       *jpegColorspace = TJCS_YCCK;  break;
1280
1.00k
  default:             *jpegColorspace = -1;  break;
1281
42.7k
  }
1282
1283
42.7k
  jpeg_abort_decompress(dinfo);
1284
1285
42.7k
  if (*jpegSubsamp < 0)
1286
33.7k
    THROW("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1287
8.94k
  if (*jpegColorspace < 0)
1288
8.94k
    THROW("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1289
8.94k
  if (*width < 1 || *height < 1)
1290
8.94k
    THROW("tjDecompressHeader3(): Invalid data returned in header");
1291
1292
42.7k
bailout:
1293
42.7k
  if (this->jerr.warning) retval = -1;
1294
42.7k
  return retval;
1295
8.94k
}
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
159k
{
1340
159k
  JSAMPROW *row_pointer = NULL;
1341
159k
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
1342
159k
  struct my_progress_mgr progress;
1343
1344
159k
  GET_DINSTANCE(handle);
1345
159k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1346
159k
  if ((this->init & DECOMPRESS) == 0)
1347
159k
    THROW("tjDecompress2(): Instance has not been initialized for decompression");
1348
1349
159k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1350
159k
      pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1351
159k
    THROW("tjDecompress2(): Invalid argument");
1352
1353
159k
#ifndef NO_PUTENV
1354
159k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1355
159k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1356
159k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1357
159k
#endif
1358
1359
159k
  if (flags & TJFLAG_LIMITSCANS) {
1360
159k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
1361
159k
    progress.pub.progress_monitor = my_progress_monitor;
1362
159k
    progress.this = this;
1363
159k
    dinfo->progress = &progress.pub;
1364
159k
  } else
1365
0
    dinfo->progress = NULL;
1366
1367
159k
  if (setjmp(this->jerr.setjmp_buffer)) {
1368
    /* If we get here, the JPEG code has signaled an error. */
1369
106k
    retval = -1;  goto bailout;
1370
106k
  }
1371
1372
52.8k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1373
52.8k
  jpeg_read_header(dinfo, TRUE);
1374
52.8k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
1375
52.8k
  if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1376
52.8k
  if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1377
1378
52.8k
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1379
52.8k
  if (width == 0) width = jpegwidth;
1380
52.8k
  if (height == 0) height = jpegheight;
1381
1.59M
  for (i = 0; i < NUMSF; i++) {
1382
1.59M
    scaledw = TJSCALED(jpegwidth, sf[i]);
1383
1.59M
    scaledh = TJSCALED(jpegheight, sf[i]);
1384
1.59M
    if (scaledw <= width && scaledh <= height)
1385
159k
      break;
1386
1.59M
  }
1387
52.8k
  if (i >= NUMSF)
1388
52.8k
    THROW("tjDecompress2(): Could not scale down to desired image dimensions");
1389
52.8k
  width = scaledw;  height = scaledh;
1390
52.8k
  dinfo->scale_num = sf[i].num;
1391
52.8k
  dinfo->scale_denom = sf[i].denom;
1392
1393
52.8k
  jpeg_start_decompress(dinfo);
1394
52.8k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1395
1396
52.8k
  if ((row_pointer =
1397
52.8k
       (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL)
1398
52.8k
    THROW("tjDecompress2(): Memory allocation failure");
1399
52.8k
  if (setjmp(this->jerr.setjmp_buffer)) {
1400
    /* If we get here, the JPEG code has signaled an error. */
1401
4.82k
    retval = -1;  goto bailout;
1402
4.82k
  }
1403
59.9M
  for (i = 0; i < (int)dinfo->output_height; i++) {
1404
59.8M
    if (flags & TJFLAG_BOTTOMUP)
1405
20.3M
      row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * (size_t)pitch];
1406
39.4M
    else
1407
39.4M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
1408
59.8M
  }
1409
25.3M
  while (dinfo->output_scanline < dinfo->output_height)
1410
25.3M
    jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1411
25.3M
                        dinfo->output_height - dinfo->output_scanline);
1412
48.0k
  jpeg_finish_decompress(dinfo);
1413
1414
159k
bailout:
1415
159k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1416
159k
  free(row_pointer);
1417
159k
  if (this->jerr.warning) retval = -1;
1418
159k
  this->jerr.stopOnWarning = FALSE;
1419
159k
  return retval;
1420
48.0k
}
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
0
{
2125
0
  int retval = 0, tempc;
2126
0
  size_t pitch;
2127
0
  tjhandle handle = NULL;
2128
0
  tjinstance *this;
2129
0
  j_compress_ptr cinfo = NULL;
2130
0
  cjpeg_source_ptr src;
2131
0
  unsigned char *dstBuf = NULL;
2132
0
  FILE *file = NULL;
2133
0
  boolean invert;
2134
2135
0
  if (!filename || !width || align < 1 || !height || !pixelFormat ||
2136
0
      *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF)
2137
0
    THROWG("tjLoadImage(): Invalid argument");
2138
0
  if ((align & (align - 1)) != 0)
2139
0
    THROWG("tjLoadImage(): Alignment must be a power of 2");
2140
2141
0
  if ((handle = tjInitCompress()) == NULL) return NULL;
2142
0
  this = (tjinstance *)handle;
2143
0
  cinfo = &this->cinfo;
2144
2145
#ifdef _MSC_VER
2146
  if (fopen_s(&file, filename, "rb") || file == NULL)
2147
#else
2148
0
  if ((file = fopen(filename, "rb")) == NULL)
2149
0
#endif
2150
0
    THROW_UNIX("tjLoadImage(): Cannot open input file");
2151
2152
0
  if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
2153
0
    THROW_UNIX("tjLoadImage(): Could not read input file")
2154
0
  else if (tempc == EOF)
2155
0
    THROWG("tjLoadImage(): Input file contains no data");
2156
2157
0
  if (setjmp(this->jerr.setjmp_buffer)) {
2158
    /* If we get here, the JPEG code has signaled an error. */
2159
0
    retval = -1;  goto bailout;
2160
0
  }
2161
2162
0
  if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN;
2163
0
  else cinfo->in_color_space = pf2cs[*pixelFormat];
2164
0
  if (tempc == 'B') {
2165
0
    if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL)
2166
0
      THROWG("tjLoadImage(): Could not initialize bitmap loader");
2167
0
    invert = (flags & TJFLAG_BOTTOMUP) == 0;
2168
0
  } else if (tempc == 'P') {
2169
0
    if ((src = jinit_read_ppm(cinfo)) == NULL)
2170
0
      THROWG("tjLoadImage(): Could not initialize PPM loader");
2171
0
    invert = (flags & TJFLAG_BOTTOMUP) != 0;
2172
0
  } else
2173
0
    THROWG("tjLoadImage(): Unsupported file type");
2174
2175
0
  src->input_file = file;
2176
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2177
  /* Refuse to load images larger than 1 Megapixel when fuzzing. */
2178
0
  if (flags & TJFLAG_FUZZING)
2179
0
    src->max_pixels = 1048576;
2180
0
#endif
2181
0
  (*src->start_input) (cinfo, src);
2182
0
  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
2183
2184
0
  *width = cinfo->image_width;  *height = cinfo->image_height;
2185
0
  *pixelFormat = cs2pf[cinfo->in_color_space];
2186
2187
0
  pitch = PAD((*width) * tjPixelSize[*pixelFormat], align);
2188
0
  if ((unsigned long long)pitch * (unsigned long long)(*height) >
2189
0
      (unsigned long long)((size_t)-1) ||
2190
0
      (dstBuf = (unsigned char *)malloc(pitch * (*height))) == NULL)
2191
0
    THROWG("tjLoadImage(): Memory allocation failure");
2192
2193
0
  if (setjmp(this->jerr.setjmp_buffer)) {
2194
    /* If we get here, the JPEG code has signaled an error. */
2195
0
    retval = -1;  goto bailout;
2196
0
  }
2197
2198
0
  while (cinfo->next_scanline < cinfo->image_height) {
2199
0
    int i, nlines = (*src->get_pixel_rows) (cinfo, src);
2200
2201
0
    for (i = 0; i < nlines; i++) {
2202
0
      unsigned char *dstptr;
2203
0
      int row;
2204
2205
0
      row = cinfo->next_scanline + i;
2206
0
      if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch];
2207
0
      else dstptr = &dstBuf[row * pitch];
2208
0
      memcpy(dstptr, src->buffer[i], (*width) * tjPixelSize[*pixelFormat]);
2209
0
    }
2210
0
    cinfo->next_scanline += nlines;
2211
0
  }
2212
2213
0
  (*src->finish_input) (cinfo, src);
2214
2215
0
bailout:
2216
0
  if (handle) tjDestroy(handle);
2217
0
  if (file) fclose(file);
2218
0
  if (retval < 0) { free(dstBuf);  dstBuf = NULL; }
2219
0
  return dstBuf;
2220
0
}
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
}