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