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
1.24M
#define PAD(v, p)  ((v + (p) - 1) & (~((p) - 1)))
55
159k
#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
135k
{
78
135k
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
79
80
135k
  (*cinfo->err->output_message) (cinfo);
81
135k
  longjmp(myerr->setjmp_buffer, 1);
82
135k
}
83
84
/* Based on output_message() in jerror.c */
85
86
static void my_output_message(j_common_ptr cinfo)
87
198k
{
88
198k
  (*cinfo->err->format_message) (cinfo, errStr);
89
198k
}
90
91
static void my_emit_message(j_common_ptr cinfo, int msg_level)
92
441M
{
93
441M
  my_error_ptr myerr = (my_error_ptr)cinfo->err;
94
95
441M
  myerr->emit_message(cinfo, msg_level);
96
441M
  if (msg_level < 0) {
97
266M
    myerr->warning = TRUE;
98
266M
    if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
99
266M
  }
100
441M
}
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
178M
{
124
178M
  my_error_ptr myerr = (my_error_ptr)dinfo->err;
125
178M
  my_progress_ptr myprog = (my_progress_ptr)dinfo->progress;
126
127
178M
  if (dinfo->is_decompressor) {
128
178M
    int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
129
130
178M
    if (scan_no > 500) {
131
22
      snprintf(myprog->this->errStr, JMSG_LENGTH_MAX,
132
22
               "Progressive JPEG image has more than 500 scans");
133
22
      snprintf(errStr, JMSG_LENGTH_MAX,
134
22
               "Progressive JPEG image has more than 500 scans");
135
22
      myprog->this->isInstanceError = TRUE;
136
22
      myerr->warning = FALSE;
137
22
      longjmp(myerr->setjmp_buffer, 1);
138
22
    }
139
178M
  }
140
178M
}
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
253k
#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
1.88k
#define THROW(m) { \
204
1.88k
  snprintf(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
205
1.88k
  this->isInstanceError = TRUE;  THROWG(m) \
206
1.88k
}
207
208
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
209
/* Private flag that triggers different TurboJPEG API behavior when fuzzing */
210
79.4k
#define TJFLAG_FUZZING  (1 << 30)
211
#endif
212
213
#define GET_INSTANCE(handle) \
214
139k
  tjinstance *this = (tjinstance *)handle; \
215
139k
  j_compress_ptr cinfo = NULL; \
216
139k
  j_decompress_ptr dinfo = NULL; \
217
139k
  \
218
139k
  if (!this) { \
219
0
    snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
220
0
    return -1; \
221
0
  } \
222
139k
  cinfo = &this->cinfo;  dinfo = &this->dinfo; \
223
139k
  this->jerr.warning = FALSE; \
224
139k
  this->isInstanceError = FALSE;
225
226
#define GET_CINSTANCE(handle) \
227
55.9k
  tjinstance *this = (tjinstance *)handle; \
228
55.9k
  j_compress_ptr cinfo = NULL; \
229
55.9k
  \
230
55.9k
  if (!this) { \
231
0
    snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
232
0
    return -1; \
233
0
  } \
234
55.9k
  cinfo = &this->cinfo; \
235
55.9k
  this->jerr.warning = FALSE; \
236
55.9k
  this->isInstanceError = FALSE;
237
238
#define GET_DINSTANCE(handle) \
239
42.0k
  tjinstance *this = (tjinstance *)handle; \
240
42.0k
  j_decompress_ptr dinfo = NULL; \
241
42.0k
  \
242
42.0k
  if (!this) { \
243
0
    snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
244
0
    return -1; \
245
0
  } \
246
42.0k
  dinfo = &this->dinfo; \
247
42.0k
  this->jerr.warning = FALSE; \
248
42.0k
  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
28.6k
{
273
28.6k
#ifndef NO_GETENV
274
28.6k
  char *env = NULL;
275
28.6k
#endif
276
277
28.6k
  cinfo->in_color_space = pf2cs[pixelFormat];
278
28.6k
  cinfo->input_components = tjPixelSize[pixelFormat];
279
28.6k
  jpeg_set_defaults(cinfo);
280
281
28.6k
#ifndef NO_GETENV
282
28.6k
  if ((env = getenv("TJ_OPTIMIZE")) != NULL && strlen(env) > 0 &&
283
28.6k
      !strcmp(env, "1"))
284
0
    cinfo->optimize_coding = TRUE;
285
28.6k
  if ((env = getenv("TJ_ARITHMETIC")) != NULL && strlen(env) > 0 &&
286
28.6k
      !strcmp(env, "1"))
287
7.32k
    cinfo->arith_code = TRUE;
288
28.6k
  if ((env = getenv("TJ_RESTART")) != NULL && strlen(env) > 0) {
289
21.5k
    int temp = -1;
290
21.5k
    char tempc = 0;
291
292
21.5k
    if (sscanf(env, "%d%c", &temp, &tempc) >= 1 && temp >= 0 &&
293
21.5k
        temp <= 65535) {
294
21.5k
      if (toupper(tempc) == 'B') {
295
0
        cinfo->restart_interval = temp;
296
0
        cinfo->restart_in_rows = 0;
297
0
      } else
298
21.5k
        cinfo->restart_in_rows = temp;
299
21.5k
    }
300
21.5k
  }
301
28.6k
#endif
302
303
28.6k
  if (jpegQual >= 0) {
304
17.8k
    jpeg_set_quality(cinfo, jpegQual, TRUE);
305
17.8k
    if (jpegQual >= 96 || flags & TJFLAG_ACCURATEDCT)
306
2.86k
      cinfo->dct_method = JDCT_ISLOW;
307
14.9k
    else
308
14.9k
      cinfo->dct_method = JDCT_FASTEST;
309
17.8k
  }
310
28.6k
  if (subsamp == TJSAMP_GRAY)
311
8.78k
    jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
312
19.8k
  else if (pixelFormat == TJPF_CMYK)
313
1.02k
    jpeg_set_colorspace(cinfo, JCS_YCCK);
314
18.7k
  else
315
18.7k
    jpeg_set_colorspace(cinfo, JCS_YCbCr);
316
317
28.6k
#ifdef C_PROGRESSIVE_SUPPORTED
318
28.6k
  if (flags & TJFLAG_PROGRESSIVE)
319
8.36k
    jpeg_simple_progression(cinfo);
320
20.2k
#ifndef NO_GETENV
321
20.2k
  else if ((env = getenv("TJ_PROGRESSIVE")) != NULL && strlen(env) > 0 &&
322
20.2k
           !strcmp(env, "1"))
323
0
    jpeg_simple_progression(cinfo);
324
28.6k
#endif
325
28.6k
#endif
326
327
28.6k
  cinfo->comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
328
28.6k
  cinfo->comp_info[1].h_samp_factor = 1;
329
28.6k
  cinfo->comp_info[2].h_samp_factor = 1;
330
28.6k
  if (cinfo->num_components > 3)
331
1.02k
    cinfo->comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
332
28.6k
  cinfo->comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
333
28.6k
  cinfo->comp_info[1].v_samp_factor = 1;
334
28.6k
  cinfo->comp_info[2].v_samp_factor = 1;
335
28.6k
  if (cinfo->num_components > 3)
336
1.02k
    cinfo->comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
337
28.6k
}
338
339
340
static int getSubsamp(j_decompress_ptr dinfo)
341
53.7k
{
342
53.7k
  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
53.7k
  if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
349
29.3k
    return TJSAMP_GRAY;
350
351
88.5k
  for (i = 0; i < TJ_NUMSAMP; i++) {
352
85.0k
    if (dinfo->num_components == pixelsize[i] ||
353
85.0k
        ((dinfo->jpeg_color_space == JCS_YCCK ||
354
9.40k
          dinfo->jpeg_color_space == JCS_CMYK) &&
355
78.7k
         pixelsize[i] == 3 && dinfo->num_components == 4)) {
356
78.7k
      if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
357
78.7k
          dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
358
23.4k
        int match = 0;
359
360
71.2k
        for (k = 1; k < dinfo->num_components; k++) {
361
47.8k
          int href = 1, vref = 1;
362
363
47.8k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
364
47.8k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
365
951
            href = tjMCUWidth[i] / 8;  vref = tjMCUHeight[i] / 8;
366
951
          }
367
47.8k
          if (dinfo->comp_info[k].h_samp_factor == href &&
368
47.8k
              dinfo->comp_info[k].v_samp_factor == vref)
369
42.5k
            match++;
370
47.8k
        }
371
23.4k
        if (match == dinfo->num_components - 1) {
372
19.9k
          retval = i;  break;
373
19.9k
        }
374
23.4k
      }
375
      /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
376
         in non-standard ways. */
377
58.7k
      if (dinfo->comp_info[0].h_samp_factor == 2 &&
378
58.7k
          dinfo->comp_info[0].v_samp_factor == 2 &&
379
58.7k
          (i == TJSAMP_422 || i == TJSAMP_440)) {
380
16.9k
        int match = 0;
381
382
51.2k
        for (k = 1; k < dinfo->num_components; k++) {
383
34.3k
          int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
384
385
34.3k
          if ((dinfo->jpeg_color_space == JCS_YCCK ||
386
34.3k
               dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
387
566
            href = vref = 2;
388
566
          }
389
34.3k
          if (dinfo->comp_info[k].h_samp_factor == href &&
390
34.3k
              dinfo->comp_info[k].v_samp_factor == vref)
391
2.34k
            match++;
392
34.3k
        }
393
16.9k
        if (match == dinfo->num_components - 1) {
394
905
          retval = i;  break;
395
905
        }
396
16.9k
      }
397
      /* Handle 4:4:4 images whose sampling factors are specified in
398
         non-standard ways. */
399
57.8k
      if (dinfo->comp_info[0].h_samp_factor *
400
57.8k
          dinfo->comp_info[0].v_samp_factor <=
401
57.8k
          D_MAX_BLOCKS_IN_MCU / pixelsize[i] && i == TJSAMP_444) {
402
6.16k
        int match = 0;
403
18.8k
        for (k = 1; k < dinfo->num_components; k++) {
404
12.8k
          if (dinfo->comp_info[k].h_samp_factor ==
405
12.8k
              dinfo->comp_info[0].h_samp_factor &&
406
12.8k
              dinfo->comp_info[k].v_samp_factor ==
407
3.08k
              dinfo->comp_info[0].v_samp_factor)
408
976
            match++;
409
12.8k
          if (match == dinfo->num_components - 1) {
410
182
            retval = i;  break;
411
182
          }
412
12.8k
        }
413
6.16k
      }
414
57.8k
    }
415
85.0k
  }
416
24.4k
  return retval;
417
53.7k
}
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
123k
{
455
123k
  GET_INSTANCE(handle);
456
457
123k
  if (setjmp(this->jerr.setjmp_buffer)) return -1;
458
123k
  if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
459
123k
  if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
460
123k
  free(this);
461
123k
  return 0;
462
123k
}
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
47.2k
{
473
47.2k
  free(buf);
474
47.2k
}
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
243k
{
488
243k
  static unsigned char buffer[1];
489
243k
  unsigned char *buf = buffer;
490
243k
  unsigned long size = 1;
491
492
  /* This is also straight out of example.txt */
493
243k
  this->cinfo.err = jpeg_std_error(&this->jerr.pub);
494
243k
  this->jerr.pub.error_exit = my_error_exit;
495
243k
  this->jerr.pub.output_message = my_output_message;
496
243k
  this->jerr.emit_message = this->jerr.pub.emit_message;
497
243k
  this->jerr.pub.emit_message = my_emit_message;
498
243k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
499
243k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
500
243k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
501
502
243k
  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
243k
  jpeg_create_compress(&this->cinfo);
509
  /* Make an initial call so it will create the destination manager */
510
243k
  jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
511
512
243k
  this->init |= COMPRESS;
513
243k
  return (tjhandle)this;
514
243k
}
515
516
/* TurboJPEG 1.0+ */
517
DLLEXPORT tjhandle tjInitCompress(void)
518
92.4k
{
519
92.4k
  tjinstance *this = NULL;
520
521
92.4k
  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
92.4k
  MEMZERO(this, sizeof(tjinstance));
527
92.4k
  snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
528
92.4k
  return _tjInitCompress(this);
529
92.4k
}
530
531
532
/* TurboJPEG 1.2+ */
533
DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
534
105k
{
535
105k
  unsigned long long retval = 0;
536
105k
  int mcuw, mcuh, chromasf;
537
538
105k
  if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP)
539
105k
    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
105k
  mcuw = tjMCUWidth[jpegSubsamp];
545
105k
  mcuh = tjMCUHeight[jpegSubsamp];
546
105k
  chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
547
105k
  retval = PAD(width, mcuw) * PAD(height, mcuh) * (2ULL + chromasf) + 2048ULL;
548
105k
  if (retval > (unsigned long long)((unsigned long)-1))
549
105k
    THROWG("tjBufSize(): Image is too large");
550
551
105k
bailout:
552
105k
  return (unsigned long)retval;
553
105k
}
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
28.4k
{
579
28.4k
  unsigned long long retval = 0;
580
28.4k
  int nc, i;
581
582
28.4k
  if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
583
28.4k
    THROWG("tjBufSizeYUV2(): Invalid argument");
584
585
28.4k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
586
92.3k
  for (i = 0; i < nc; i++) {
587
63.9k
    int pw = tjPlaneWidth(i, width, subsamp);
588
63.9k
    int stride = PAD(pw, align);
589
63.9k
    int ph = tjPlaneHeight(i, height, subsamp);
590
591
63.9k
    if (pw < 0 || ph < 0) return -1;
592
63.9k
    else retval += (unsigned long long)stride * ph;
593
63.9k
  }
594
28.4k
  if (retval > (unsigned long long)((unsigned long)-1))
595
28.4k
    THROWG("tjBufSizeYUV2(): Image is too large");
596
597
28.4k
bailout:
598
28.4k
  return (unsigned long)retval;
599
28.4k
}
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
162k
{
617
162k
  unsigned long long pw, retval = 0;
618
162k
  int nc;
619
620
162k
  if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
621
162k
    THROWG("tjPlaneWidth(): Invalid argument");
622
162k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
623
162k
  if (componentID < 0 || componentID >= nc)
624
162k
    THROWG("tjPlaneWidth(): Invalid argument");
625
626
162k
  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
627
162k
  if (componentID == 0)
628
86.9k
    retval = pw;
629
75.0k
  else
630
75.0k
    retval = pw * 8 / tjMCUWidth[subsamp];
631
632
162k
  if (retval > (unsigned long long)INT_MAX)
633
162k
    THROWG("tjPlaneWidth(): Width is too large");
634
635
162k
bailout:
636
162k
  return (int)retval;
637
162k
}
638
639
640
/* TurboJPEG 1.4+ */
641
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
642
162k
{
643
162k
  unsigned long long ph, retval = 0;
644
162k
  int nc;
645
646
162k
  if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
647
162k
    THROWG("tjPlaneHeight(): Invalid argument");
648
162k
  nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
649
162k
  if (componentID < 0 || componentID >= nc)
650
162k
    THROWG("tjPlaneHeight(): Invalid argument");
651
652
162k
  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
653
162k
  if (componentID == 0)
654
86.9k
    retval = ph;
655
75.0k
  else
656
75.0k
    retval = ph * 8 / tjMCUHeight[subsamp];
657
658
162k
  if (retval > (unsigned long long)INT_MAX)
659
162k
    THROWG("tjPlaneHeight(): Height is too large");
660
661
162k
bailout:
662
162k
  return (int)retval;
663
162k
}
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
13.6k
{
698
13.6k
  int i, retval = 0;
699
13.6k
  boolean alloc = TRUE;
700
13.6k
  JSAMPROW *row_pointer = NULL;
701
702
13.6k
  GET_CINSTANCE(handle)
703
13.6k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
704
13.6k
  if ((this->init & COMPRESS) == 0)
705
13.6k
    THROW("tjCompress2(): Instance has not been initialized for compression");
706
707
13.6k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
708
13.6k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
709
13.6k
      jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP ||
710
13.6k
      jpegQual < 0 || jpegQual > 100)
711
13.6k
    THROW("tjCompress2(): Invalid argument");
712
713
13.6k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
714
715
13.6k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * height)) == NULL)
716
13.6k
    THROW("tjCompress2(): Memory allocation failure");
717
718
13.6k
  if (setjmp(this->jerr.setjmp_buffer)) {
719
    /* If we get here, the JPEG code has signaled an error. */
720
63
    retval = -1;  goto bailout;
721
63
  }
722
723
13.5k
  cinfo->image_width = width;
724
13.5k
  cinfo->image_height = height;
725
726
13.5k
#ifndef NO_PUTENV
727
13.5k
  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
728
13.5k
  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
729
13.5k
  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
730
13.5k
#endif
731
732
13.5k
  if (flags & TJFLAG_NOREALLOC) {
733
11.6k
    alloc = FALSE;  *jpegSize = tjBufSize(width, height, jpegSubsamp);
734
11.6k
  }
735
13.5k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
736
13.5k
  setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags);
737
738
13.5k
  jpeg_start_compress(cinfo, TRUE);
739
45.9M
  for (i = 0; i < height; i++) {
740
45.9M
    if (flags & TJFLAG_BOTTOMUP)
741
6.68M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
742
39.2M
    else
743
39.2M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
744
45.9M
  }
745
27.1k
  while (cinfo->next_scanline < cinfo->image_height)
746
13.5k
    jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
747
13.5k
                         cinfo->image_height - cinfo->next_scanline);
748
13.5k
  jpeg_finish_compress(cinfo);
749
750
13.6k
bailout:
751
13.6k
  if (cinfo->global_state > CSTATE_START) {
752
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
753
0
    jpeg_abort_compress(cinfo);
754
0
  }
755
13.6k
  free(row_pointer);
756
13.6k
  if (this->jerr.warning) retval = -1;
757
13.6k
  this->jerr.stopOnWarning = FALSE;
758
13.6k
  return retval;
759
13.5k
}
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
21.1k
{
791
21.1k
  JSAMPROW *row_pointer = NULL;
792
21.1k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
793
21.1k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
794
21.1k
  JSAMPROW *outbuf[MAX_COMPONENTS];
795
21.1k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
796
21.1k
  JSAMPLE *ptr;
797
21.1k
  jpeg_component_info *compptr;
798
799
21.1k
  GET_CINSTANCE(handle);
800
21.1k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
801
802
233k
  for (i = 0; i < MAX_COMPONENTS; i++) {
803
211k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
804
211k
    tmpbuf2[i] = NULL;  _tmpbuf2[i] = NULL;  outbuf[i] = NULL;
805
211k
  }
806
807
21.1k
  if ((this->init & COMPRESS) == 0)
808
21.1k
    THROW("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
809
810
21.1k
  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
811
21.1k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
812
21.1k
      !dstPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP)
813
21.1k
    THROW("tjEncodeYUVPlanes(): Invalid argument");
814
21.1k
  if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
815
21.1k
    THROW("tjEncodeYUVPlanes(): Invalid argument");
816
817
21.1k
  if (pixelFormat == TJPF_CMYK)
818
21.1k
    THROW("tjEncodeYUVPlanes(): Cannot generate YUV images from packed-pixel CMYK images");
819
820
21.1k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
821
822
21.1k
  if (setjmp(this->jerr.setjmp_buffer)) {
823
    /* If we get here, the JPEG code has signaled an error. */
824
57
    retval = -1;  goto bailout;
825
57
  }
826
827
21.1k
  cinfo->image_width = width;
828
21.1k
  cinfo->image_height = height;
829
830
21.1k
#ifndef NO_PUTENV
831
21.1k
  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
832
21.1k
  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
833
21.1k
  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
834
21.1k
#endif
835
836
21.1k
  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
21.1k
  if (cinfo->global_state != CSTATE_START)
843
21.1k
    THROW("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
844
21.1k
  (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
845
21.1k
  jinit_c_master_control(cinfo, FALSE);
846
21.1k
  jinit_color_converter(cinfo);
847
21.1k
  jinit_downsampler(cinfo);
848
21.1k
  (*cinfo->cconvert->start_pass) (cinfo);
849
850
21.1k
  pw0 = PAD(width, cinfo->max_h_samp_factor);
851
21.1k
  ph0 = PAD(height, cinfo->max_v_samp_factor);
852
853
21.1k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
854
21.1k
    THROW("tjEncodeYUVPlanes(): Memory allocation failure");
855
60.5M
  for (i = 0; i < height; i++) {
856
60.5M
    if (flags & TJFLAG_BOTTOMUP)
857
10.1M
      row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
858
50.3M
    else
859
50.3M
      row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
860
60.5M
  }
861
21.1k
  if (height < ph0)
862
3.90k
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
863
864
71.0k
  for (i = 0; i < cinfo->num_components; i++) {
865
49.9k
    compptr = &cinfo->comp_info[i];
866
49.9k
    _tmpbuf[i] = (JSAMPLE *)malloc(
867
49.9k
      PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
868
49.9k
          compptr->h_samp_factor, 32) *
869
49.9k
      cinfo->max_v_samp_factor + 32);
870
49.9k
    if (!_tmpbuf[i])
871
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
872
49.9k
    tmpbuf[i] =
873
49.9k
      (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
874
49.9k
    if (!tmpbuf[i])
875
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
876
110k
    for (row = 0; row < cinfo->max_v_samp_factor; row++) {
877
60.7k
      unsigned char *_tmpbuf_aligned =
878
60.7k
        (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
879
880
60.7k
      tmpbuf[i][row] = &_tmpbuf_aligned[
881
60.7k
        PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
882
60.7k
            compptr->h_samp_factor, 32) * row];
883
60.7k
    }
884
49.9k
    _tmpbuf2[i] =
885
49.9k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
886
49.9k
                        compptr->v_samp_factor + 32);
887
49.9k
    if (!_tmpbuf2[i])
888
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
889
49.9k
    tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
890
49.9k
    if (!tmpbuf2[i])
891
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
892
103k
    for (row = 0; row < compptr->v_samp_factor; row++) {
893
53.5k
      unsigned char *_tmpbuf2_aligned =
894
53.5k
        (unsigned char *)PAD((size_t)_tmpbuf2[i], 32);
895
896
53.5k
      tmpbuf2[i][row] =
897
53.5k
        &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
898
53.5k
    }
899
49.9k
    pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
900
49.9k
    ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
901
49.9k
    outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
902
49.9k
    if (!outbuf[i])
903
49.9k
      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
904
49.9k
    ptr = dstPlanes[i];
905
131M
    for (row = 0; row < ph[i]; row++) {
906
131M
      outbuf[i][row] = ptr;
907
131M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
908
131M
    }
909
49.9k
  }
910
911
21.1k
  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
55.5M
  for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
917
55.4M
    (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
918
55.4M
                                       cinfo->max_v_samp_factor);
919
55.4M
    (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
920
182M
    for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
921
126M
         i++, compptr++)
922
126M
      jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
923
126M
        row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
924
126M
        compptr->v_samp_factor, pw[i]);
925
55.4M
  }
926
21.1k
  cinfo->next_scanline += height;
927
21.1k
  jpeg_abort_compress(cinfo);
928
929
21.1k
bailout:
930
21.1k
  if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
931
21.1k
  free(row_pointer);
932
233k
  for (i = 0; i < MAX_COMPONENTS; i++) {
933
211k
    free(tmpbuf[i]);
934
211k
    free(_tmpbuf[i]);
935
211k
    free(tmpbuf2[i]);
936
211k
    free(_tmpbuf2[i]);
937
211k
    free(outbuf[i]);
938
211k
  }
939
21.1k
  if (this->jerr.warning) retval = -1;
940
21.1k
  this->jerr.stopOnWarning = FALSE;
941
21.1k
  return retval;
942
21.1k
}
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
21.1k
{
950
21.1k
  unsigned char *dstPlanes[3];
951
21.1k
  int pw0, ph0, strides[3], retval = -1;
952
21.1k
  tjinstance *this = (tjinstance *)handle;
953
954
21.1k
  if (!this) THROWG("tjEncodeYUV3(): Invalid handle");
955
21.1k
  this->isInstanceError = FALSE;
956
957
21.1k
  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
958
21.1k
      !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
959
21.1k
    THROW("tjEncodeYUV3(): Invalid argument");
960
961
21.1k
  pw0 = tjPlaneWidth(0, width, subsamp);
962
21.1k
  ph0 = tjPlaneHeight(0, height, subsamp);
963
21.1k
  dstPlanes[0] = dstBuf;
964
21.1k
  strides[0] = PAD(pw0, align);
965
21.1k
  if (subsamp == TJSAMP_GRAY) {
966
6.75k
    strides[1] = strides[2] = 0;
967
6.75k
    dstPlanes[1] = dstPlanes[2] = NULL;
968
14.4k
  } else {
969
14.4k
    int pw1 = tjPlaneWidth(1, width, subsamp);
970
14.4k
    int ph1 = tjPlaneHeight(1, height, subsamp);
971
972
14.4k
    strides[1] = strides[2] = PAD(pw1, align);
973
14.4k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
974
14.4k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
975
14.4k
  }
976
977
21.1k
  return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
978
21.1k
                           dstPlanes, strides, subsamp, flags);
979
980
0
bailout:
981
0
  return retval;
982
21.1k
}
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
21.1k
{
1013
21.1k
  int i, row, retval = 0;
1014
21.1k
  boolean alloc = TRUE;
1015
21.1k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1016
21.1k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1017
21.1k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1018
21.1k
  JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1019
1020
21.1k
  GET_CINSTANCE(handle)
1021
21.1k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1022
1023
232k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1024
211k
    tmpbuf[i] = NULL;  inbuf[i] = NULL;
1025
211k
  }
1026
1027
21.1k
  if ((this->init & COMPRESS) == 0)
1028
21.1k
    THROW("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
1029
1030
21.1k
  if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
1031
21.1k
      subsamp < 0 || subsamp >= TJ_NUMSAMP || jpegBuf == NULL ||
1032
21.1k
      jpegSize == NULL || jpegQual < 0 || jpegQual > 100)
1033
21.1k
    THROW("tjCompressFromYUVPlanes(): Invalid argument");
1034
21.1k
  if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1035
21.1k
    THROW("tjCompressFromYUVPlanes(): Invalid argument");
1036
1037
21.1k
  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
21.1k
  cinfo->image_width = width;
1043
21.1k
  cinfo->image_height = height;
1044
1045
21.1k
#ifndef NO_PUTENV
1046
21.1k
  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1047
21.1k
  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1048
21.1k
  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1049
21.1k
#endif
1050
1051
21.1k
  if (flags & TJFLAG_NOREALLOC) {
1052
21.1k
    alloc = FALSE;  *jpegSize = tjBufSize(width, height, subsamp);
1053
21.1k
  }
1054
21.1k
  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1055
21.1k
  setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags);
1056
21.1k
  cinfo->raw_data_in = TRUE;
1057
1058
21.1k
  jpeg_start_compress(cinfo, TRUE);
1059
71.0k
  for (i = 0; i < cinfo->num_components; i++) {
1060
49.9k
    jpeg_component_info *compptr = &cinfo->comp_info[i];
1061
49.9k
    int ih;
1062
1063
49.9k
    iw[i] = compptr->width_in_blocks * DCTSIZE;
1064
49.9k
    ih = compptr->height_in_blocks * DCTSIZE;
1065
49.9k
    pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
1066
49.9k
            compptr->h_samp_factor / cinfo->max_h_samp_factor;
1067
49.9k
    ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
1068
49.9k
            compptr->v_samp_factor / cinfo->max_v_samp_factor;
1069
49.9k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1070
49.9k
    th[i] = compptr->v_samp_factor * DCTSIZE;
1071
49.9k
    tmpbufsize += iw[i] * th[i];
1072
49.9k
    if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1073
49.9k
      THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
1074
49.9k
    ptr = (JSAMPLE *)srcPlanes[i];
1075
131M
    for (row = 0; row < ph[i]; row++) {
1076
131M
      inbuf[i][row] = ptr;
1077
131M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1078
131M
    }
1079
49.9k
  }
1080
21.1k
  if (usetmpbuf) {
1081
21.0k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1082
21.0k
      THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
1083
21.0k
    ptr = _tmpbuf;
1084
70.8k
    for (i = 0; i < cinfo->num_components; i++) {
1085
49.7k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1086
49.7k
        THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
1087
476k
      for (row = 0; row < th[i]; row++) {
1088
426k
        tmpbuf[i][row] = ptr;
1089
426k
        ptr += iw[i];
1090
426k
      }
1091
49.7k
    }
1092
21.0k
  }
1093
1094
21.1k
  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
6.96M
  for (row = 0; row < (int)cinfo->image_height;
1100
6.94M
       row += cinfo->max_v_samp_factor * DCTSIZE) {
1101
6.94M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1102
6.94M
    int crow[MAX_COMPONENTS];
1103
1104
22.8M
    for (i = 0; i < cinfo->num_components; i++) {
1105
15.8M
      jpeg_component_info *compptr = &cinfo->comp_info[i];
1106
1107
15.8M
      crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1108
15.8M
      if (usetmpbuf) {
1109
15.8M
        int j, k;
1110
1111
147M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1112
131M
          memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1113
          /* Duplicate last sample in row to fill out MCU */
1114
995M
          for (k = pw[i]; k < iw[i]; k++)
1115
863M
            tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1116
131M
        }
1117
        /* Duplicate last row to fill out MCU */
1118
16.1M
        for (j = ph[i] - crow[i]; j < th[i]; j++)
1119
261k
          memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1120
15.8M
        yuvptr[i] = tmpbuf[i];
1121
15.8M
      } else
1122
704
        yuvptr[i] = &inbuf[i][crow[i]];
1123
15.8M
    }
1124
6.94M
    jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1125
6.94M
  }
1126
21.1k
  jpeg_finish_compress(cinfo);
1127
1128
21.1k
bailout:
1129
21.1k
  if (cinfo->global_state > CSTATE_START) {
1130
0
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
1131
0
    jpeg_abort_compress(cinfo);
1132
0
  }
1133
232k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1134
211k
    free(tmpbuf[i]);
1135
211k
    free(inbuf[i]);
1136
211k
  }
1137
21.1k
  free(_tmpbuf);
1138
21.1k
  if (this->jerr.warning) retval = -1;
1139
21.1k
  this->jerr.stopOnWarning = FALSE;
1140
21.1k
  return retval;
1141
21.1k
}
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
21.1k
{
1150
21.1k
  const unsigned char *srcPlanes[3];
1151
21.1k
  int pw0, ph0, strides[3], retval = -1;
1152
21.1k
  tjinstance *this = (tjinstance *)handle;
1153
1154
21.1k
  if (!this) THROWG("tjCompressFromYUV(): Invalid handle");
1155
21.1k
  this->isInstanceError = FALSE;
1156
1157
21.1k
  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
1158
21.1k
      height <= 0 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
1159
21.1k
    THROW("tjCompressFromYUV(): Invalid argument");
1160
1161
21.1k
  pw0 = tjPlaneWidth(0, width, subsamp);
1162
21.1k
  ph0 = tjPlaneHeight(0, height, subsamp);
1163
21.1k
  srcPlanes[0] = srcBuf;
1164
21.1k
  strides[0] = PAD(pw0, align);
1165
21.1k
  if (subsamp == TJSAMP_GRAY) {
1166
6.74k
    strides[1] = strides[2] = 0;
1167
6.74k
    srcPlanes[1] = srcPlanes[2] = NULL;
1168
14.3k
  } else {
1169
14.3k
    int pw1 = tjPlaneWidth(1, width, subsamp);
1170
14.3k
    int ph1 = tjPlaneHeight(1, height, subsamp);
1171
1172
14.3k
    strides[1] = strides[2] = PAD(pw1, align);
1173
14.3k
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1174
14.3k
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1175
14.3k
  }
1176
1177
21.1k
  return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1178
21.1k
                                 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1179
1180
0
bailout:
1181
0
  return retval;
1182
21.1k
}
1183
1184
1185
/******************************* Decompressor ********************************/
1186
1187
static tjhandle _tjInitDecompress(tjinstance *this)
1188
48.8k
{
1189
48.8k
  static unsigned char buffer[1];
1190
1191
  /* This is also straight out of example.txt */
1192
48.8k
  this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1193
48.8k
  this->jerr.pub.error_exit = my_error_exit;
1194
48.8k
  this->jerr.pub.output_message = my_output_message;
1195
48.8k
  this->jerr.emit_message = this->jerr.pub.emit_message;
1196
48.8k
  this->jerr.pub.emit_message = my_emit_message;
1197
48.8k
  this->jerr.pub.addon_message_table = turbojpeg_message_table;
1198
48.8k
  this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1199
48.8k
  this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1200
1201
48.8k
  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
48.8k
  jpeg_create_decompress(&this->dinfo);
1208
  /* Make an initial call so it will create the source manager */
1209
48.8k
  jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1210
1211
48.8k
  this->init |= DECOMPRESS;
1212
48.8k
  return (tjhandle)this;
1213
48.8k
}
1214
1215
/* TurboJPEG 1.0+ */
1216
DLLEXPORT tjhandle tjInitDecompress(void)
1217
20.0k
{
1218
20.0k
  tjinstance *this;
1219
1220
20.0k
  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
20.0k
  MEMZERO(this, sizeof(tjinstance));
1226
20.0k
  snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
1227
20.0k
  return _tjInitDecompress(this);
1228
20.0k
}
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
15.3k
{
1238
15.3k
  int retval = 0;
1239
1240
15.3k
  GET_DINSTANCE(handle);
1241
15.3k
  if ((this->init & DECOMPRESS) == 0)
1242
15.3k
    THROW("tjDecompressHeader3(): Instance has not been initialized for decompression");
1243
1244
15.3k
  if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL ||
1245
15.3k
      jpegSubsamp == NULL || jpegColorspace == NULL)
1246
15.3k
    THROW("tjDecompressHeader3(): Invalid argument");
1247
1248
15.3k
  if (setjmp(this->jerr.setjmp_buffer)) {
1249
    /* If we get here, the JPEG code has signaled an error. */
1250
4.11k
    return -1;
1251
4.11k
  }
1252
1253
11.2k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1254
11.2k
  jpeg_read_header(dinfo, TRUE);
1255
1256
11.2k
  *width = dinfo->image_width;
1257
11.2k
  *height = dinfo->image_height;
1258
11.2k
  *jpegSubsamp = getSubsamp(dinfo);
1259
11.2k
  switch (dinfo->jpeg_color_space) {
1260
5.96k
  case JCS_GRAYSCALE:  *jpegColorspace = TJCS_GRAY;  break;
1261
194
  case JCS_RGB:        *jpegColorspace = TJCS_RGB;  break;
1262
4.87k
  case JCS_YCbCr:      *jpegColorspace = TJCS_YCbCr;  break;
1263
139
  case JCS_CMYK:       *jpegColorspace = TJCS_CMYK;  break;
1264
52
  case JCS_YCCK:       *jpegColorspace = TJCS_YCCK;  break;
1265
26
  default:             *jpegColorspace = -1;  break;
1266
11.2k
  }
1267
1268
11.2k
  jpeg_abort_decompress(dinfo);
1269
1270
11.2k
  if (*jpegSubsamp < 0)
1271
9.75k
    THROW("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1272
9.75k
  if (*jpegColorspace < 0)
1273
9.75k
    THROW("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1274
9.75k
  if (*width < 1 || *height < 1)
1275
9.75k
    THROW("tjDecompressHeader3(): Invalid data returned in header");
1276
1277
11.2k
bailout:
1278
11.2k
  if (this->jerr.warning) retval = -1;
1279
11.2k
  return retval;
1280
9.75k
}
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
10.4k
{
1325
10.4k
  JSAMPROW *row_pointer = NULL;
1326
10.4k
  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
1327
10.4k
  struct my_progress_mgr progress;
1328
1329
10.4k
  GET_DINSTANCE(handle);
1330
10.4k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1331
10.4k
  if ((this->init & DECOMPRESS) == 0)
1332
10.4k
    THROW("tjDecompress2(): Instance has not been initialized for decompression");
1333
1334
10.4k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1335
10.4k
      pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1336
10.4k
    THROW("tjDecompress2(): Invalid argument");
1337
1338
10.4k
#ifndef NO_PUTENV
1339
10.4k
  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1340
10.4k
  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1341
10.4k
  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1342
10.4k
#endif
1343
1344
10.4k
  if (flags & TJFLAG_LIMITSCANS) {
1345
10.4k
    MEMZERO(&progress, sizeof(struct my_progress_mgr));
1346
10.4k
    progress.pub.progress_monitor = my_progress_monitor;
1347
10.4k
    progress.this = this;
1348
10.4k
    dinfo->progress = &progress.pub;
1349
10.4k
  } else
1350
0
    dinfo->progress = NULL;
1351
1352
10.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
1353
    /* If we get here, the JPEG code has signaled an error. */
1354
2.98k
    retval = -1;  goto bailout;
1355
2.98k
  }
1356
1357
7.44k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1358
7.44k
  jpeg_read_header(dinfo, TRUE);
1359
7.44k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
1360
7.65k
  if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1361
7.65k
  if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1362
1363
7.44k
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1364
7.44k
  if (width == 0) width = jpegwidth;
1365
7.44k
  if (height == 0) height = jpegheight;
1366
97.3k
  for (i = 0; i < NUMSF; i++) {
1367
97.3k
    scaledw = TJSCALED(jpegwidth, sf[i]);
1368
97.3k
    scaledh = TJSCALED(jpegheight, sf[i]);
1369
97.3k
    if (scaledw <= width && scaledh <= height)
1370
10.4k
      break;
1371
97.3k
  }
1372
7.44k
  if (i >= NUMSF)
1373
7.44k
    THROW("tjDecompress2(): Could not scale down to desired image dimensions");
1374
7.44k
  width = scaledw;  height = scaledh;
1375
7.44k
  dinfo->scale_num = sf[i].num;
1376
7.44k
  dinfo->scale_denom = sf[i].denom;
1377
1378
7.44k
  jpeg_start_decompress(dinfo);
1379
7.44k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1380
1381
7.44k
  if ((row_pointer =
1382
7.44k
       (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL)
1383
7.44k
    THROW("tjDecompress2(): Memory allocation failure");
1384
7.44k
  if (setjmp(this->jerr.setjmp_buffer)) {
1385
    /* If we get here, the JPEG code has signaled an error. */
1386
627
    retval = -1;  goto bailout;
1387
627
  }
1388
33.5M
  for (i = 0; i < (int)dinfo->output_height; i++) {
1389
33.5M
    if (flags & TJFLAG_BOTTOMUP)
1390
27.7M
      row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * (size_t)pitch];
1391
5.74M
    else
1392
5.74M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
1393
33.5M
  }
1394
18.4M
  while (dinfo->output_scanline < dinfo->output_height)
1395
18.4M
    jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1396
18.4M
                        dinfo->output_height - dinfo->output_scanline);
1397
6.81k
  jpeg_finish_decompress(dinfo);
1398
1399
10.4k
bailout:
1400
10.4k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1401
10.4k
  free(row_pointer);
1402
10.4k
  if (this->jerr.warning) retval = -1;
1403
10.4k
  this->jerr.stopOnWarning = FALSE;
1404
10.4k
  return retval;
1405
6.81k
}
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
2.41k
{
1424
2.41k
  int i;
1425
1426
2.41k
  dinfo->scale_num = dinfo->scale_denom = 1;
1427
1428
2.41k
  if (subsamp == TJSAMP_GRAY) {
1429
1.09k
    dinfo->num_components = dinfo->comps_in_scan = 1;
1430
1.09k
    dinfo->jpeg_color_space = JCS_GRAYSCALE;
1431
1.32k
  } else {
1432
1.32k
    dinfo->num_components = dinfo->comps_in_scan = 3;
1433
1.32k
    dinfo->jpeg_color_space = JCS_YCbCr;
1434
1.32k
  }
1435
1436
2.41k
  dinfo->comp_info = (jpeg_component_info *)
1437
2.41k
    (*dinfo->mem->alloc_small) ((j_common_ptr)dinfo, JPOOL_IMAGE,
1438
2.41k
                                dinfo->num_components *
1439
2.41k
                                sizeof(jpeg_component_info));
1440
1441
7.47k
  for (i = 0; i < dinfo->num_components; i++) {
1442
5.06k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
1443
1444
5.06k
    compptr->h_samp_factor = (i == 0) ? tjMCUWidth[subsamp] / 8 : 1;
1445
5.06k
    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[subsamp] / 8 : 1;
1446
5.06k
    compptr->component_index = i;
1447
5.06k
    compptr->component_id = i + 1;
1448
5.06k
    compptr->quant_tbl_no = compptr->dc_tbl_no =
1449
5.06k
      compptr->ac_tbl_no = (i == 0) ? 0 : 1;
1450
5.06k
    dinfo->cur_comp_info[i] = compptr;
1451
5.06k
  }
1452
2.41k
  dinfo->data_precision = 8;
1453
7.24k
  for (i = 0; i < 2; i++) {
1454
4.83k
    if (dinfo->quant_tbl_ptrs[i] == NULL)
1455
760
      dinfo->quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)dinfo);
1456
4.83k
  }
1457
2.41k
}
1458
1459
1460
static int my_read_markers(j_decompress_ptr dinfo)
1461
2.41k
{
1462
2.41k
  return JPEG_REACHED_SOS;
1463
2.41k
}
1464
1465
static void my_reset_marker_reader(j_decompress_ptr dinfo)
1466
2.41k
{
1467
2.41k
}
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
1.66k
{
1476
1.66k
  JSAMPROW *row_pointer = NULL;
1477
1.66k
  JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1478
1.66k
  JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
1479
1.66k
  int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1480
1.66k
  JSAMPLE *ptr;
1481
1.66k
  jpeg_component_info *compptr;
1482
1.66k
  int (*old_read_markers) (j_decompress_ptr);
1483
1.66k
  void (*old_reset_marker_reader) (j_decompress_ptr);
1484
1485
1.66k
  GET_DINSTANCE(handle);
1486
1.66k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1487
1488
18.2k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1489
16.6k
    tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;  inbuf[i] = NULL;
1490
16.6k
  }
1491
1492
1.66k
  if ((this->init & DECOMPRESS) == 0)
1493
1.66k
    THROW("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
1494
1495
1.66k
  if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP ||
1496
1.66k
      dstBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1497
1.66k
      pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1498
1.66k
    THROW("tjDecodeYUVPlanes(): Invalid argument");
1499
1.66k
  if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1500
1.66k
    THROW("tjDecodeYUVPlanes(): Invalid argument");
1501
1502
1.66k
  if (setjmp(this->jerr.setjmp_buffer)) {
1503
    /* If we get here, the JPEG code has signaled an error. */
1504
8
    retval = -1;  goto bailout;
1505
8
  }
1506
1507
1.65k
  if (pixelFormat == TJPF_CMYK)
1508
1.65k
    THROW("tjDecodeYUVPlanes(): Cannot decode YUV images into packed-pixel CMYK images.");
1509
1510
1.66k
  if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1511
1.65k
  dinfo->image_width = width;
1512
1.65k
  dinfo->image_height = height;
1513
1514
1.65k
#ifndef NO_PUTENV
1515
1.65k
  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1516
1.65k
  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1517
1.65k
  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1518
1.65k
#endif
1519
1520
1.65k
  dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
1521
1.65k
  dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
1522
1.65k
  dinfo->Se = DCTSIZE2 - 1;
1523
1.65k
  setDecodeDefaults(dinfo, pixelFormat, subsamp, flags);
1524
1.65k
  old_read_markers = dinfo->marker->read_markers;
1525
1.65k
  dinfo->marker->read_markers = my_read_markers;
1526
1.65k
  old_reset_marker_reader = dinfo->marker->reset_marker_reader;
1527
1.65k
  dinfo->marker->reset_marker_reader = my_reset_marker_reader;
1528
1.65k
  jpeg_read_header(dinfo, TRUE);
1529
1.65k
  dinfo->marker->read_markers = old_read_markers;
1530
1.65k
  dinfo->marker->reset_marker_reader = old_reset_marker_reader;
1531
1532
1.65k
  this->dinfo.out_color_space = pf2cs[pixelFormat];
1533
1.65k
  if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1534
1.65k
  dinfo->do_fancy_upsampling = FALSE;
1535
1.65k
  dinfo->Se = DCTSIZE2 - 1;
1536
1.65k
  jinit_master_decompress(dinfo);
1537
1.65k
  (*dinfo->upsample->start_pass) (dinfo);
1538
1539
1.65k
  pw0 = PAD(width, dinfo->max_h_samp_factor);
1540
1.65k
  ph0 = PAD(height, dinfo->max_v_samp_factor);
1541
1542
1.65k
  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1543
1544
1.65k
  if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1545
1.65k
    THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1546
9.76M
  for (i = 0; i < height; i++) {
1547
9.75M
    if (flags & TJFLAG_BOTTOMUP)
1548
4.38M
      row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
1549
5.37M
    else
1550
5.37M
      row_pointer[i] = &dstBuf[i * (size_t)pitch];
1551
9.75M
  }
1552
1.65k
  if (height < ph0)
1553
606
    for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1554
1555
5.11k
  for (i = 0; i < dinfo->num_components; i++) {
1556
3.46k
    compptr = &dinfo->comp_info[i];
1557
3.46k
    _tmpbuf[i] =
1558
3.46k
      (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1559
3.46k
                        compptr->v_samp_factor + 32);
1560
3.46k
    if (!_tmpbuf[i])
1561
3.46k
      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1562
3.46k
    tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1563
3.46k
    if (!tmpbuf[i])
1564
3.46k
      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1565
7.52k
    for (row = 0; row < compptr->v_samp_factor; row++) {
1566
4.05k
      unsigned char *_tmpbuf_aligned =
1567
4.05k
        (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
1568
1569
4.05k
      tmpbuf[i][row] =
1570
4.05k
        &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1571
4.05k
    }
1572
3.46k
    pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
1573
3.46k
    ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1574
3.46k
    inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1575
3.46k
    if (!inbuf[i])
1576
3.46k
      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
1577
3.46k
    ptr = (JSAMPLE *)srcPlanes[i];
1578
17.0M
    for (row = 0; row < ph[i]; row++) {
1579
17.0M
      inbuf[i][row] = ptr;
1580
17.0M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1581
17.0M
    }
1582
3.46k
  }
1583
1584
1.65k
  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
8.42M
  for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
1590
8.42M
    JDIMENSION inrow = 0, outrow = 0;
1591
1592
24.0M
    for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
1593
15.6M
         i++, compptr++)
1594
15.6M
      jcopy_sample_rows(inbuf[i],
1595
15.6M
        row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
1596
15.6M
        compptr->v_samp_factor, pw[i]);
1597
8.42M
    (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
1598
8.42M
                                 dinfo->max_v_samp_factor, &row_pointer[row],
1599
8.42M
                                 &outrow, dinfo->max_v_samp_factor);
1600
8.42M
  }
1601
1.65k
  jpeg_abort_decompress(dinfo);
1602
1603
1.66k
bailout:
1604
1.66k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1605
1.66k
  free(row_pointer);
1606
18.2k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1607
16.6k
    free(tmpbuf[i]);
1608
16.6k
    free(_tmpbuf[i]);
1609
16.6k
    free(inbuf[i]);
1610
16.6k
  }
1611
1.66k
  if (this->jerr.warning) retval = -1;
1612
1.66k
  this->jerr.stopOnWarning = FALSE;
1613
1.66k
  return retval;
1614
1.65k
}
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
1.66k
{
1622
1.66k
  const unsigned char *srcPlanes[3];
1623
1.66k
  int pw0, ph0, strides[3], retval = -1;
1624
1.66k
  tjinstance *this = (tjinstance *)handle;
1625
1626
1.66k
  if (!this) THROWG("tjDecodeYUV(): Invalid handle");
1627
1.66k
  this->isInstanceError = FALSE;
1628
1629
1.66k
  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || subsamp < 0 ||
1630
1.66k
      subsamp >= TJ_NUMSAMP || width <= 0 || height <= 0)
1631
1.66k
    THROW("tjDecodeYUV(): Invalid argument");
1632
1633
1.66k
  pw0 = tjPlaneWidth(0, width, subsamp);
1634
1.66k
  ph0 = tjPlaneHeight(0, height, subsamp);
1635
1.66k
  srcPlanes[0] = srcBuf;
1636
1.66k
  strides[0] = PAD(pw0, align);
1637
1.66k
  if (subsamp == TJSAMP_GRAY) {
1638
752
    strides[1] = strides[2] = 0;
1639
752
    srcPlanes[1] = srcPlanes[2] = NULL;
1640
910
  } else {
1641
910
    int pw1 = tjPlaneWidth(1, width, subsamp);
1642
910
    int ph1 = tjPlaneHeight(1, height, subsamp);
1643
1644
910
    strides[1] = strides[2] = PAD(pw1, align);
1645
910
    srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1646
910
    srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1647
910
  }
1648
1649
1.66k
  return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1650
1.66k
                           pitch, height, pixelFormat, flags);
1651
1652
0
bailout:
1653
0
  return retval;
1654
1.66k
}
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
7.27k
{
1663
7.27k
  int i, sfi, row, retval = 0;
1664
7.27k
  int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
1665
7.27k
  int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1666
7.27k
    tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1667
7.27k
  JSAMPLE *_tmpbuf = NULL, *ptr;
1668
7.27k
  JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1669
7.27k
  int dctsize;
1670
7.27k
  struct my_progress_mgr progress;
1671
1672
7.27k
  GET_DINSTANCE(handle);
1673
7.27k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1674
1675
79.9k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1676
72.7k
    tmpbuf[i] = NULL;  outbuf[i] = NULL;
1677
72.7k
  }
1678
1679
7.27k
  if ((this->init & DECOMPRESS) == 0)
1680
7.27k
    THROW("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
1681
1682
7.27k
  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0] ||
1683
7.27k
      width < 0 || height < 0)
1684
7.27k
    THROW("tjDecompressToYUVPlanes(): Invalid argument");
1685
1686
7.27k
#ifndef NO_PUTENV
1687
7.27k
  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1688
7.27k
  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1689
7.27k
  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1690
7.27k
#endif
1691
1692
7.27k
  if (flags & TJFLAG_LIMITSCANS) {
1693
7.27k
    MEMZERO(&progress, sizeof(struct my_progress_mgr));
1694
7.27k
    progress.pub.progress_monitor = my_progress_monitor;
1695
7.27k
    progress.this = this;
1696
7.27k
    dinfo->progress = &progress.pub;
1697
7.27k
  } else
1698
0
    dinfo->progress = NULL;
1699
1700
7.27k
  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
7.27k
  if (!this->headerRead) {
1706
0
    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1707
0
    jpeg_read_header(dinfo, TRUE);
1708
0
  }
1709
7.27k
  this->headerRead = 0;
1710
7.27k
  jpegSubsamp = getSubsamp(dinfo);
1711
7.27k
  if (jpegSubsamp < 0)
1712
7.27k
    THROW("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1713
1714
7.27k
  if (jpegSubsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1715
7.27k
    THROW("tjDecompressToYUVPlanes(): Invalid argument");
1716
1717
7.27k
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1718
7.27k
  if (width == 0) width = jpegwidth;
1719
7.27k
  if (height == 0) height = jpegheight;
1720
68.6k
  for (i = 0; i < NUMSF; i++) {
1721
68.6k
    scaledw = TJSCALED(jpegwidth, sf[i]);
1722
68.6k
    scaledh = TJSCALED(jpegheight, sf[i]);
1723
68.6k
    if (scaledw <= width && scaledh <= height)
1724
7.27k
      break;
1725
68.6k
  }
1726
7.27k
  if (i >= NUMSF)
1727
7.27k
    THROW("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
1728
7.27k
  if (dinfo->num_components > 3)
1729
7.26k
    THROW("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
1730
1731
7.26k
  width = scaledw;  height = scaledh;
1732
7.26k
  dinfo->scale_num = sf[i].num;
1733
7.26k
  dinfo->scale_denom = sf[i].denom;
1734
7.26k
  sfi = i;
1735
7.26k
  jpeg_calc_output_dimensions(dinfo);
1736
1737
7.26k
  dctsize = DCTSIZE * sf[sfi].num / sf[sfi].denom;
1738
1739
21.0k
  for (i = 0; i < dinfo->num_components; i++) {
1740
13.8k
    jpeg_component_info *compptr = &dinfo->comp_info[i];
1741
13.8k
    int ih;
1742
1743
13.8k
    iw[i] = compptr->width_in_blocks * dctsize;
1744
13.8k
    ih = compptr->height_in_blocks * dctsize;
1745
13.8k
    pw[i] = tjPlaneWidth(i, dinfo->output_width, jpegSubsamp);
1746
13.8k
    ph[i] = tjPlaneHeight(i, dinfo->output_height, jpegSubsamp);
1747
13.8k
    if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1748
13.8k
    th[i] = compptr->v_samp_factor * dctsize;
1749
13.8k
    tmpbufsize += iw[i] * th[i];
1750
13.8k
    if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1751
13.8k
      THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
1752
13.8k
    ptr = dstPlanes[i];
1753
88.9M
    for (row = 0; row < ph[i]; row++) {
1754
88.9M
      outbuf[i][row] = ptr;
1755
88.9M
      ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1756
88.9M
    }
1757
13.8k
  }
1758
7.26k
  if (usetmpbuf) {
1759
6.41k
    if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1760
6.41k
      THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
1761
6.41k
    ptr = _tmpbuf;
1762
18.4k
    for (i = 0; i < dinfo->num_components; i++) {
1763
12.0k
      if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1764
12.0k
        THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
1765
155k
      for (row = 0; row < th[i]; row++) {
1766
143k
        tmpbuf[i][row] = ptr;
1767
143k
        ptr += iw[i];
1768
143k
      }
1769
12.0k
    }
1770
6.41k
  }
1771
1772
7.26k
  if (setjmp(this->jerr.setjmp_buffer)) {
1773
    /* If we get here, the JPEG code has signaled an error. */
1774
1.84k
    retval = -1;  goto bailout;
1775
1.84k
  }
1776
1777
6.16k
  if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1778
6.16k
  if (flags & TJFLAG_FASTDCT) dinfo->dct_method = JDCT_FASTEST;
1779
5.41k
  dinfo->raw_data_out = TRUE;
1780
1781
5.41k
  jpeg_start_decompress(dinfo);
1782
3.63M
  for (row = 0; row < (int)dinfo->output_height;
1783
3.63M
       row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
1784
3.63M
    JSAMPARRAY yuvptr[MAX_COMPONENTS];
1785
3.63M
    int crow[MAX_COMPONENTS];
1786
1787
10.4M
    for (i = 0; i < dinfo->num_components; i++) {
1788
6.81M
      jpeg_component_info *compptr = &dinfo->comp_info[i];
1789
1790
6.81M
      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
2.38M
        compptr->_DCT_scaled_size = dctsize;
1802
2.38M
        compptr->MCU_sample_width = tjMCUWidth[jpegSubsamp] *
1803
2.38M
          sf[sfi].num / sf[sfi].denom *
1804
2.38M
          compptr->v_samp_factor / dinfo->max_v_samp_factor;
1805
2.38M
        dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1806
2.38M
      }
1807
6.81M
      crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1808
6.81M
      if (usetmpbuf) yuvptr[i] = tmpbuf[i];
1809
289k
      else yuvptr[i] = &outbuf[i][crow[i]];
1810
6.81M
    }
1811
3.63M
    jpeg_read_raw_data(dinfo, yuvptr,
1812
3.63M
                       dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
1813
3.63M
    if (usetmpbuf) {
1814
3.42M
      int j;
1815
1816
9.94M
      for (i = 0; i < dinfo->num_components; i++) {
1817
75.7M
        for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1818
69.2M
          memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
1819
69.2M
        }
1820
6.52M
      }
1821
3.42M
    }
1822
3.63M
  }
1823
5.41k
  jpeg_finish_decompress(dinfo);
1824
1825
7.27k
bailout:
1826
7.27k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1827
79.9k
  for (i = 0; i < MAX_COMPONENTS; i++) {
1828
72.7k
    free(tmpbuf[i]);
1829
72.7k
    free(outbuf[i]);
1830
72.7k
  }
1831
7.27k
  free(_tmpbuf);
1832
7.27k
  if (this->jerr.warning) retval = -1;
1833
7.27k
  this->jerr.stopOnWarning = FALSE;
1834
7.27k
  return retval;
1835
5.41k
}
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
7.27k
{
1842
7.27k
  unsigned char *dstPlanes[3];
1843
7.27k
  int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1;
1844
7.27k
  int i, jpegwidth, jpegheight, scaledw, scaledh;
1845
1846
7.27k
  GET_DINSTANCE(handle);
1847
7.27k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1848
1849
7.27k
  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1850
7.27k
      align < 1 || !IS_POW2(align) || height < 0)
1851
7.27k
    THROW("tjDecompressToYUV2(): Invalid argument");
1852
1853
7.27k
  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
7.27k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1859
7.27k
  jpeg_read_header(dinfo, TRUE);
1860
7.27k
  jpegSubsamp = getSubsamp(dinfo);
1861
7.27k
  if (jpegSubsamp < 0)
1862
7.27k
    THROW("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1863
1864
7.27k
  jpegwidth = dinfo->image_width;  jpegheight = dinfo->image_height;
1865
7.27k
  if (width == 0) width = jpegwidth;
1866
7.27k
  if (height == 0) height = jpegheight;
1867
68.6k
  for (i = 0; i < NUMSF; i++) {
1868
68.6k
    scaledw = TJSCALED(jpegwidth, sf[i]);
1869
68.6k
    scaledh = TJSCALED(jpegheight, sf[i]);
1870
68.6k
    if (scaledw <= width && scaledh <= height)
1871
7.27k
      break;
1872
68.6k
  }
1873
7.27k
  if (i >= NUMSF)
1874
7.27k
    THROW("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1875
1876
7.27k
  width = scaledw;  height = scaledh;
1877
1878
7.27k
  pw0 = tjPlaneWidth(0, width, jpegSubsamp);
1879
7.27k
  ph0 = tjPlaneHeight(0, height, jpegSubsamp);
1880
7.27k
  dstPlanes[0] = dstBuf;
1881
7.27k
  strides[0] = PAD(pw0, align);
1882
7.27k
  if (jpegSubsamp == TJSAMP_GRAY) {
1883
3.97k
    strides[1] = strides[2] = 0;
1884
3.97k
    dstPlanes[1] = dstPlanes[2] = NULL;
1885
3.97k
  } else {
1886
3.29k
    int pw1 = tjPlaneWidth(1, width, jpegSubsamp);
1887
3.29k
    int ph1 = tjPlaneHeight(1, height, jpegSubsamp);
1888
1889
3.29k
    strides[1] = strides[2] = PAD(pw1, align);
1890
3.29k
    dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1891
3.29k
    dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1892
3.29k
  }
1893
1894
7.27k
  this->headerRead = 1;
1895
7.27k
  return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1896
7.27k
                                 strides, height, flags);
1897
1898
0
bailout:
1899
0
  this->jerr.stopOnWarning = FALSE;
1900
0
  return retval;
1901
7.27k
}
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
10.8k
{
1917
10.8k
  tjinstance *this = NULL;
1918
10.8k
  tjhandle handle = NULL;
1919
1920
10.8k
  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
10.8k
  MEMZERO(this, sizeof(tjinstance));
1926
10.8k
  snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
1927
10.8k
  handle = _tjInitCompress(this);
1928
10.8k
  if (!handle) return NULL;
1929
10.8k
  handle = _tjInitDecompress(this);
1930
10.8k
  return handle;
1931
10.8k
}
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
16.4k
{
1940
16.4k
  jpeg_transform_info *xinfo = NULL;
1941
16.4k
  jvirt_barray_ptr *srccoefs, *dstcoefs;
1942
16.4k
  int retval = 0, i, jpegSubsamp, saveMarkers = 0;
1943
16.4k
  boolean alloc = TRUE;
1944
16.4k
  struct my_progress_mgr progress;
1945
1946
16.4k
  GET_INSTANCE(handle);
1947
16.4k
  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1948
16.4k
  if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
1949
16.4k
    THROW("tjTransform(): Instance has not been initialized for transformation");
1950
1951
16.4k
  if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
1952
16.4k
      dstSizes == NULL || t == NULL || flags < 0)
1953
16.4k
    THROW("tjTransform(): Invalid argument");
1954
1955
16.4k
#ifndef NO_PUTENV
1956
16.4k
  if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1957
16.4k
  else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1958
16.4k
  else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1959
16.4k
#endif
1960
1961
16.4k
  if (flags & TJFLAG_LIMITSCANS) {
1962
16.4k
    MEMZERO(&progress, sizeof(struct my_progress_mgr));
1963
16.4k
    progress.pub.progress_monitor = my_progress_monitor;
1964
16.4k
    progress.this = this;
1965
16.4k
    dinfo->progress = &progress.pub;
1966
16.4k
  } else
1967
0
    dinfo->progress = NULL;
1968
1969
16.4k
  if ((xinfo =
1970
16.4k
       (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
1971
16.4k
    THROW("tjTransform(): Memory allocation failure");
1972
16.4k
  MEMZERO(xinfo, sizeof(jpeg_transform_info) * n);
1973
1974
16.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
1975
    /* If we get here, the JPEG code has signaled an error. */
1976
11.8k
    retval = -1;  goto bailout;
1977
11.8k
  }
1978
1979
4.59k
  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1980
1981
37.5k
  for (i = 0; i < n; i++) {
1982
32.9k
    xinfo[i].transform = xformtypes[t[i].op];
1983
32.9k
    xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
1984
32.9k
    xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
1985
32.9k
    xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
1986
32.9k
    xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
1987
32.9k
    if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
1988
32.9k
    else xinfo[i].slow_hflip = 0;
1989
1990
32.9k
    if (xinfo[i].crop) {
1991
8.24k
      xinfo[i].crop_xoffset = t[i].r.x;  xinfo[i].crop_xoffset_set = JCROP_POS;
1992
8.24k
      xinfo[i].crop_yoffset = t[i].r.y;  xinfo[i].crop_yoffset_set = JCROP_POS;
1993
8.24k
      if (t[i].r.w != 0) {
1994
8.24k
        xinfo[i].crop_width = t[i].r.w;  xinfo[i].crop_width_set = JCROP_POS;
1995
8.24k
      } else
1996
0
        xinfo[i].crop_width = JCROP_UNSET;
1997
8.24k
      if (t[i].r.h != 0) {
1998
8.24k
        xinfo[i].crop_height = t[i].r.h;  xinfo[i].crop_height_set = JCROP_POS;
1999
8.24k
      } else
2000
0
        xinfo[i].crop_height = JCROP_UNSET;
2001
8.24k
    }
2002
32.9k
    if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
2003
32.9k
  }
2004
2005
18.4E
  jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
2006
4.59k
  jpeg_read_header(dinfo, TRUE);
2007
4.59k
  jpegSubsamp = getSubsamp(dinfo);
2008
4.59k
  if (jpegSubsamp < 0)
2009
4.22k
    THROW("tjTransform(): Could not determine subsampling type for JPEG image");
2010
2011
32.4k
  for (i = 0; i < n; i++) {
2012
28.2k
    if (!jtransform_request_workspace(dinfo, &xinfo[i]))
2013
28.2k
      THROW("tjTransform(): Transform is not perfect");
2014
2015
28.2k
    if (xinfo[i].crop) {
2016
4.01k
      if ((t[i].r.x % tjMCUWidth[jpegSubsamp]) != 0 ||
2017
4.01k
          (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
4.01k
    }
2026
28.2k
  }
2027
2028
4.22k
  srccoefs = jpeg_read_coefficients(dinfo);
2029
2030
14.5k
  for (i = 0; i < n; i++) {
2031
10.3k
    int w, h;
2032
2033
10.3k
    if (!xinfo[i].crop) {
2034
8.89k
      w = dinfo->image_width;  h = dinfo->image_height;
2035
8.89k
    } else {
2036
1.47k
      w = xinfo[i].crop_width;  h = xinfo[i].crop_height;
2037
1.47k
    }
2038
10.3k
    if (flags & TJFLAG_NOREALLOC) {
2039
5.23k
      alloc = FALSE;  dstSizes[i] = tjBufSize(w, h, jpegSubsamp);
2040
5.23k
    }
2041
10.3k
    if (!(t[i].options & TJXOPT_NOOUTPUT))
2042
10.3k
      jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2043
10.3k
    jpeg_copy_critical_parameters(dinfo, cinfo);
2044
10.3k
    dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
2045
10.3k
#ifdef C_PROGRESSIVE_SUPPORTED
2046
10.3k
    if (flags & TJFLAG_PROGRESSIVE || t[i].options & TJXOPT_PROGRESSIVE)
2047
5.46k
      jpeg_simple_progression(cinfo);
2048
10.3k
#endif
2049
10.3k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) {
2050
8.17k
      jpeg_write_coefficients(cinfo, dstcoefs);
2051
8.17k
      jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
2052
4.41k
                                          JCOPYOPT_NONE : JCOPYOPT_ALL);
2053
8.17k
    } else
2054
2.19k
      jinit_c_master_control(cinfo, TRUE);
2055
10.3k
    jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
2056
10.3k
    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
10.3k
    if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2086
10.3k
  }
2087
2088
4.22k
  jpeg_finish_decompress(dinfo);
2089
2090
16.4k
bailout:
2091
16.4k
  if (cinfo->global_state > CSTATE_START) {
2092
1.12k
    if (alloc) (*cinfo->dest->term_destination) (cinfo);
2093
1.12k
    jpeg_abort_compress(cinfo);
2094
1.12k
  }
2095
16.4k
  if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
2096
16.4k
  free(xinfo);
2097
16.4k
  if (this->jerr.warning) retval = -1;
2098
16.4k
  this->jerr.stopOnWarning = FALSE;
2099
16.4k
  return retval;
2100
4.22k
}
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
80.0k
{
2110
80.0k
  int retval = 0, tempc;
2111
80.0k
  size_t pitch;
2112
80.0k
  tjhandle handle = NULL;
2113
80.0k
  tjinstance *this;
2114
80.0k
  j_compress_ptr cinfo = NULL;
2115
80.0k
  cjpeg_source_ptr src;
2116
80.0k
  unsigned char *dstBuf = NULL;
2117
80.0k
  FILE *file = NULL;
2118
80.0k
  boolean invert;
2119
2120
80.0k
  if (!filename || !width || align < 1 || !height || !pixelFormat ||
2121
80.0k
      *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF)
2122
80.0k
    THROWG("tjLoadImage(): Invalid argument");
2123
80.0k
  if ((align & (align - 1)) != 0)
2124
80.0k
    THROWG("tjLoadImage(): Alignment must be a power of 2");
2125
2126
80.0k
  if ((handle = tjInitCompress()) == NULL) return NULL;
2127
80.0k
  this = (tjinstance *)handle;
2128
80.0k
  cinfo = &this->cinfo;
2129
2130
80.0k
  if ((file = fopen(filename, "rb")) == NULL)
2131
80.0k
    THROW_UNIX("tjLoadImage(): Cannot open input file");
2132
2133
80.0k
  if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
2134
0
    THROW_UNIX("tjLoadImage(): Could not read input file")
2135
80.0k
  else if (tempc == EOF)
2136
80.0k
    THROWG("tjLoadImage(): Input file contains no data");
2137
2138
80.0k
  if (setjmp(this->jerr.setjmp_buffer)) {
2139
    /* If we get here, the JPEG code has signaled an error. */
2140
25.2k
    retval = -1;  goto bailout;
2141
25.2k
  }
2142
2143
54.7k
  if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN;
2144
54.7k
  else cinfo->in_color_space = pf2cs[*pixelFormat];
2145
54.7k
  if (tempc == 'B') {
2146
22.1k
    if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL)
2147
22.1k
      THROWG("tjLoadImage(): Could not initialize bitmap loader");
2148
22.1k
    invert = (flags & TJFLAG_BOTTOMUP) == 0;
2149
57.3k
  } else if (tempc == 'P') {
2150
57.3k
    if ((src = jinit_read_ppm(cinfo)) == NULL)
2151
57.3k
      THROWG("tjLoadImage(): Could not initialize PPM loader");
2152
57.3k
    invert = (flags & TJFLAG_BOTTOMUP) != 0;
2153
57.3k
  } else
2154
18.4E
    THROWG("tjLoadImage(): Unsupported file type");
2155
2156
79.4k
  src->input_file = file;
2157
79.4k
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
2158
  /* Refuse to load images larger than 1 Megapixel when fuzzing. */
2159
79.4k
  if (flags & TJFLAG_FUZZING)
2160
79.4k
    src->max_pixels = 1048576;
2161
79.4k
#endif
2162
79.4k
  (*src->start_input) (cinfo, src);
2163
79.4k
  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
2164
2165
79.4k
  *width = cinfo->image_width;  *height = cinfo->image_height;
2166
79.4k
  *pixelFormat = cs2pf[cinfo->in_color_space];
2167
2168
79.4k
  pitch = PAD((*width) * tjPixelSize[*pixelFormat], align);
2169
79.4k
  if ((unsigned long long)pitch * (unsigned long long)(*height) >
2170
79.4k
      (unsigned long long)((size_t)-1) ||
2171
79.4k
      (dstBuf = (unsigned char *)malloc(pitch * (*height))) == NULL)
2172
79.4k
    THROWG("tjLoadImage(): Memory allocation failure");
2173
2174
79.4k
  if (setjmp(this->jerr.setjmp_buffer)) {
2175
    /* If we get here, the JPEG code has signaled an error. */
2176
19.3k
    retval = -1;  goto bailout;
2177
19.3k
  }
2178
2179
110M
  while (cinfo->next_scanline < cinfo->image_height) {
2180
110M
    int i, nlines = (*src->get_pixel_rows) (cinfo, src);
2181
2182
220M
    for (i = 0; i < nlines; i++) {
2183
110M
      unsigned char *dstptr;
2184
110M
      int row;
2185
2186
110M
      row = cinfo->next_scanline + i;
2187
110M
      if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch];
2188
88.1M
      else dstptr = &dstBuf[row * pitch];
2189
110M
      memcpy(dstptr, src->buffer[i], (*width) * tjPixelSize[*pixelFormat]);
2190
110M
    }
2191
110M
    cinfo->next_scanline += nlines;
2192
110M
  }
2193
2194
60.1k
  (*src->finish_input) (cinfo, src);
2195
2196
80.0k
bailout:
2197
80.0k
  if (handle) tjDestroy(handle);
2198
80.0k
  if (file) fclose(file);
2199
80.0k
  if (retval < 0) { free(dstBuf);  dstBuf = NULL; }
2200
80.0k
  return dstBuf;
2201
60.1k
}
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
}