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