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