Coverage Report

Created: 2023-06-07 06:03

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