Coverage Report

Created: 2025-03-12 04:15

/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
74.6k
{
76
74.6k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
77
78
74.6k
  (*cinfo->err->output_message) (cinfo);
79
74.6k
  longjmp(myerr->setjmp_buffer, 1);
80
74.6k
}
81
82
/* Based on output_message() in jerror.c */
83
84
static void my_output_message(j_common_ptr cinfo)
85
169k
{
86
169k
  (*cinfo->err->format_message) (cinfo, errStr);
87
169k
}
88
89
static void my_emit_message(j_common_ptr cinfo, int msg_level)
90
50.4M
{
91
50.4M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
92
93
50.4M
  myerr->emit_message(cinfo, msg_level);
94
50.4M
  if (msg_level < 0) {
95
40.7M
    myerr->warning = TRUE;
96
40.7M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
97
40.7M
  }
98
50.4M
}
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
18.5M
{
122
18.5M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
123
18.5M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
124
125
18.5M
  if (dinfo->is_decompressor) {
126
18.5M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
127
128
18.5M
    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
18.5M
  }
138
18.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
741k
#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
15.7k
#define THROWG(m) { \
194
15.7k
  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s", m); \
195
15.7k
  retval = -1;  goto bailout; \
196
15.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
15.7k
#define THROW(m) { \
211
15.7k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
212
15.7k
  this->isInstanceError = TRUE;  THROWG(m) \
213
15.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
48.8k
  tjinstance *this = (tjinstance *)handle; \
222
48.8k
  j_compress_ptr cinfo = NULL; \
223
48.8k
  j_decompress_ptr dinfo = NULL; \
224
48.8k
  \
225
48.8k
  if (!this) { \
226
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
227
0
    return -1; \
228
0
  } \
229
48.8k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
230
48.8k
  this->jerr.warning = FALSE; \
231
48.8k
  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
124k
  tjinstance *this = (tjinstance *)handle; \
247
124k
  j_decompress_ptr dinfo = NULL; \
248
124k
  \
249
124k
  if (!this) { \
250
0
    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
251
0
    return -1; \
252
0
  } \
253
124k
  dinfo = &this->dinfo; \
254
124k
  this->jerr.warning = FALSE; \
255
124k
  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
21.0k
{
351
21.0k
  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
21.0k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
358
380
    return TJSAMP_GRAY;
359
360
124k
  for (i = 0; i < TJ_NUMSAMP; i++) {
361
108k
    if (dinfo->num_components == pixelsize[i] ||
362
108k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
363
20.6k
          dinfo->jpeg_color_space == JCS_CMYK) &&
364
88.6k
         pixelsize[i] == 3 && dinfo->num_components == 4)) {
365
88.6k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
366
88.6k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
367
17.9k
        int match = 0;
368
369
54.1k
        for (k = 1; k < dinfo->num_components; k++) {
370
36.1k
          int href = 1, vref = 1;
371
372
36.1k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
373
36.1k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
374
195
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
375
195
          }
376
36.1k
          if (dinfo->comp_info[k].h_samp_factor == href &&
377
36.1k
              dinfo->comp_info[k].v_samp_factor == vref)
378
22.2k
            match++;
379
36.1k
        }
380
17.9k
        if (match == dinfo->num_components - 1) {
381
4.79k
          retval = i;  break;
382
4.79k
        }
383
17.9k
      }
384
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
385
         in non-standard ways. */
386
83.9k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
387
83.9k
          dinfo->comp_info[0].v_samp_factor == 2 &&
388
83.9k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
389
5.58k
        int match = 0;
390
391
16.8k
        for (k = 1; k < dinfo->num_components; k++) {
392
11.2k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
393
394
11.2k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
395
11.2k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
396
38
            href = vref = 2;
397
38
          }
398
11.2k
          if (dinfo->comp_info[k].h_samp_factor == href &&
399
11.2k
              dinfo->comp_info[k].v_samp_factor == vref)
400
353
            match++;
401
11.2k
        }
402
5.58k
        if (match == dinfo->num_components - 1) {
403
47
          retval = i;  break;
404
47
        }
405
5.58k
      }
406
      /* Handle 4:4:4 images whose sampling factors are specified in
407
         non-standard ways. */
408
83.8k
      if (dinfo->comp_info[0].h_samp_factor *
409
83.8k
          dinfo->comp_info[0].v_samp_factor <=
410
83.8k
          D_MAX_BLOCKS_IN_MCU / pixelsize[i] && i == TJSAMP_444) {
411
11.8k
        int match = 0;
412
35.5k
        for (k = 1; k < dinfo->num_components; k++) {
413
23.7k
          if (dinfo->comp_info[k].h_samp_factor ==
414
23.7k
              dinfo->comp_info[0].h_samp_factor &&
415
23.7k
              dinfo->comp_info[k].v_samp_factor ==
416
6.26k
              dinfo->comp_info[0].v_samp_factor)
417
246
            match++;
418
23.7k
          if (match == dinfo->num_components - 1) {
419
8
            retval = i;  break;
420
8
          }
421
23.7k
        }
422
11.8k
      }
423
83.8k
    }
424
108k
  }
425
20.6k
  return retval;
426
21.0k
}
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
48.8k
{
464
48.8k
  GET_INSTANCE(handle);
465
466
48.8k
  if (setjmp(this->jerr.setjmp_buffer)) return -1;
467
48.8k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
468
48.8k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
469
48.8k
  free(this);
470
48.8k
  return 0;
471
48.8k
}
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
48.8k
{
1198
48.8k
  static unsigned char buffer[1];
1199
1200
  /* This is also straight out of example.txt */
1201
48.8k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1202
48.8k
  this->jerr.pub.error_exit = my_error_exit;
1203
48.8k
  this->jerr.pub.output_message = my_output_message;
1204
48.8k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1205
48.8k
  this->jerr.pub.emit_message = my_emit_message;
1206
48.8k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1207
48.8k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1208
48.8k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1209
1210
48.8k
  if (setjmp(this->jerr.setjmp_buffer)) {
1211
    /* If we get here, the JPEG code has signaled an error. */
1212
0
    free(this);
1213
0
    return NULL;
1214
0
  }
1215
1216
48.8k
  jpeg_create_decompress(&this->dinfo);
1217
  /* Make an initial call so it will create the source manager */
1218
48.8k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1219
1220
48.8k
  this->init |= DECOMPRESS;
1221
48.8k
  return (tjhandle)this;
1222
48.8k
}
1223
1224
/* TurboJPEG 1.0+ */
1225
DLLEXPORT tjhandle tjInitDecompress(void)
1226
48.8k
{
1227
48.8k
  tjinstance *this;
1228
1229
48.8k
  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
48.8k
  memset(this, 0, sizeof(tjinstance));
1235
48.8k
  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "No error");
1236
48.8k
  return _tjInitDecompress(this);
1237
48.8k
}
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
48.8k
{
1247
48.8k
  int retval = 0;
1248
1249
48.8k
  GET_DINSTANCE(handle);
1250
48.8k
  if ((this->init & DECOMPRESS) == 0)
1251
48.8k
    THROW("tjDecompressHeader3(): Instance has not been initialized for decompression");
1252
1253
48.8k
  if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL ||
1254
48.8k
      jpegSubsamp == NULL || jpegColorspace == NULL)
1255
48.8k
    THROW("tjDecompressHeader3(): Invalid argument");
1256
1257
48.8k
  if (setjmp(this->jerr.setjmp_buffer)) {
1258
    /* If we get here, the JPEG code has signaled an error. */
1259
25.9k
    return -1;
1260
25.9k
  }
1261
1262
22.9k
  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
22.9k
  if (jpeg_read_header(dinfo, FALSE) == JPEG_HEADER_TABLES_ONLY)
1269
1.89k
    return 0;
1270
1271
21.0k
  *width = dinfo->image_width;
1272
21.0k
  *height = dinfo->image_height;
1273
21.0k
  *jpegSubsamp = getSubsamp(dinfo);
1274
21.0k
  switch (dinfo->jpeg_color_space) {
1275
380
  case JCS_GRAYSCALE:  *jpegColorspace = TJCS_GRAY;  break;
1276
587
  case JCS_RGB:        *jpegColorspace = TJCS_RGB;  break;
1277
19.1k
  case JCS_YCbCr:      *jpegColorspace = TJCS_YCbCr;  break;
1278
105
  case JCS_CMYK:       *jpegColorspace = TJCS_CMYK;  break;
1279
91
  case JCS_YCCK:       *jpegColorspace = TJCS_YCCK;  break;
1280
733
  default:             *jpegColorspace = -1;  break;
1281
21.0k
  }
1282
1283
21.0k
  jpeg_abort_decompress(dinfo);
1284
1285
21.0k
  if (*jpegSubsamp < 0)
1286
15.7k
    THROW("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1287
5.22k
  if (*jpegColorspace < 0)
1288
5.22k
    THROW("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1289
5.22k
  if (*width < 1 || *height < 1)
1290
5.22k
    THROW("tjDecompressHeader3(): Invalid data returned in header");
1291
1292
21.0k
bailout:
1293
21.0k
  if (this->jerr.warning) retval = -1;
1294
21.0k
  return retval;
1295
5.22k
}
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
75.7k
{
1340
75.7k
  JSAMPROW *row_pointer = NULL;
1341
75.7k
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
1342
75.7k
  struct my_progress_mgr progress;
1343
1344
75.7k
  GET_DINSTANCE(handle);
1345
75.7k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1346
75.7k
  if ((this->init & DECOMPRESS) == 0)
1347
75.7k
    THROW("tjDecompress2(): Instance has not been initialized for decompression");
1348
1349
75.7k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1350
75.7k
      pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1351
75.7k
    THROW("tjDecompress2(): Invalid argument");
1352
1353
75.7k
#ifndef NO_PUTENV
1354
75.7k
  if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1");
1355
75.7k
  else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1");
1356
75.7k
  else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1");
1357
75.7k
#endif
1358
1359
75.7k
  if (flags & TJFLAG_LIMITSCANS) {
1360
75.7k
    memset(&progress, 0, sizeof(struct my_progress_mgr));
1361
75.7k
    progress.pub.progress_monitor = my_progress_monitor;
1362
75.7k
    progress.this = this;
1363
75.7k
    dinfo->progress = &progress.pub;
1364
75.7k
  } else
1365
0
    dinfo->progress = NULL;
1366
1367
75.7k
  if (setjmp(this->jerr.setjmp_buffer)) {
1368
    /* If we get here, the JPEG code has signaled an error. */
1369
45.7k
    retval = -1;  goto bailout;
1370
45.7k
  }
1371
1372
29.9k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1373
29.9k
  jpeg_read_header(dinfo, TRUE);
1374
29.9k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
1375
29.9k
  if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1376
29.9k
  if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1377
1378
29.9k
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1379
29.9k
  if (width == 0) width = jpegwidth;
1380
29.9k
  if (height == 0) height = jpegheight;
1381
756k
  for (i = 0; i < NUMSF; i++) {
1382
756k
    scaledw = TJSCALED(jpegwidth, sf[i]);
1383
756k
    scaledh = TJSCALED(jpegheight, sf[i]);
1384
756k
    if (scaledw <= width && scaledh <= height)
1385
75.7k
      break;
1386
756k
  }
1387
29.9k
  if (i >= NUMSF)
1388
29.9k
    THROW("tjDecompress2(): Could not scale down to desired image dimensions");
1389
29.9k
  width = scaledw;  height = scaledh;
1390
29.9k
  dinfo->scale_num = sf[i].num;
1391
29.9k
  dinfo->scale_denom = sf[i].denom;
1392
1393
29.9k
  jpeg_start_decompress(dinfo);
1394
29.9k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1395
1396
29.9k
  if ((row_pointer =
1397
29.9k
       (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL)
1398
29.9k
    THROW("tjDecompress2(): Memory allocation failure");
1399
29.9k
  if (setjmp(this->jerr.setjmp_buffer)) {
1400
    /* If we get here, the JPEG code has signaled an error. */
1401
2.98k
    retval = -1;  goto bailout;
1402
2.98k
  }
1403
19.5M
  for (i = 0; i < (int)dinfo->output_height; i++) {
1404
19.5M
    if (flags & TJFLAG_BOTTOMUP)
1405
7.72M
      row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * (size_t)pitch];
1406
11.7M
    else
1407
11.7M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
1408
19.5M
  }
1409
8.48M
  while (dinfo->output_scanline < dinfo->output_height)
1410
8.46M
    jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1411
8.46M
                        dinfo->output_height - dinfo->output_scanline);
1412
27.0k
  jpeg_finish_decompress(dinfo);
1413
1414
75.7k
bailout:
1415
75.7k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1416
75.7k
  free(row_pointer);
1417
75.7k
  if (this->jerr.warning) retval = -1;
1418
75.7k
  this->jerr.stopOnWarning = FALSE;
1419
75.7k
  return retval;
1420
27.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
}