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