2 * Copyright (C)2009-2018 D. R. Commander. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of the libjpeg-turbo Project nor the names of its
13 * contributors may be used to endorse or promote products derived from this
14 * software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 /* TurboJPEG/LJT: this implements the TurboJPEG API using libjpeg or
36 #define JPEG_INTERNALS
41 #include "./turbojpeg.h"
44 #include "./jpegcomp.h"
47 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, unsigned long *,
49 extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
52 #define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
53 #define isPow2(x) (((x) & (x - 1)) == 0)
56 /* Error handling (based on example in example.txt) */
58 static char errStr[JMSG_LENGTH_MAX] = "No error";
61 struct jpeg_error_mgr pub;
62 jmp_buf setjmp_buffer;
63 void (*emit_message) (j_common_ptr, int);
64 boolean warning, stopOnWarning;
66 typedef struct my_error_mgr *my_error_ptr;
68 #define JMESSAGE(code, string) string,
69 static const char *turbojpeg_message_table[] = {
74 static void my_error_exit(j_common_ptr cinfo)
76 my_error_ptr myerr = (my_error_ptr)cinfo->err;
78 (*cinfo->err->output_message) (cinfo);
79 longjmp(myerr->setjmp_buffer, 1);
82 /* Based on output_message() in jerror.c */
84 static void my_output_message(j_common_ptr cinfo)
86 (*cinfo->err->format_message) (cinfo, errStr);
89 static void my_emit_message(j_common_ptr cinfo, int msg_level)
91 my_error_ptr myerr = (my_error_ptr)cinfo->err;
93 myerr->emit_message(cinfo, msg_level);
95 myerr->warning = TRUE;
96 if (myerr->stopOnWarning) longjmp(myerr->setjmp_buffer, 1);
101 /* Global structures, macros, etc. */
103 enum { COMPRESS = 1, DECOMPRESS = 2 };
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;
114 static const int pixelsize[TJ_NUMSAMP] = { 3, 3, 3, 1, 3, 3 };
116 static const JXFORM_CODE xformtypes[TJ_NUMXOP] = {
117 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
118 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
122 static const tjscalingfactor sf[NUMSF] = {
141 static J_COLOR_SPACE pf2cs[TJ_NUMPF] = {
142 JCS_EXT_RGB, JCS_EXT_BGR, JCS_EXT_RGBX, JCS_EXT_BGRX, JCS_EXT_XBGR,
143 JCS_EXT_XRGB, JCS_GRAYSCALE, JCS_EXT_RGBA, JCS_EXT_BGRA, JCS_EXT_ABGR,
144 JCS_EXT_ARGB, JCS_CMYK
147 static int cs2pf[JPEG_NUMCS] = {
148 TJPF_UNKNOWN, TJPF_GRAY,
149 #if RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 3
151 #elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 3
153 #elif RGB_RED == 0 && RGB_GREEN == 1 && RGB_BLUE == 2 && RGB_PIXELSIZE == 4
155 #elif RGB_RED == 2 && RGB_GREEN == 1 && RGB_BLUE == 0 && RGB_PIXELSIZE == 4
157 #elif RGB_RED == 3 && RGB_GREEN == 2 && RGB_BLUE == 1 && RGB_PIXELSIZE == 4
159 #elif RGB_RED == 1 && RGB_GREEN == 2 && RGB_BLUE == 3 && RGB_PIXELSIZE == 4
162 TJPF_UNKNOWN, TJPF_CMYK, TJPF_UNKNOWN, TJPF_RGB, TJPF_RGBX, TJPF_BGR,
163 TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_RGBA, TJPF_BGRA, TJPF_ABGR, TJPF_ARGB,
167 #define _throwg(m) { \
168 snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
169 retval = -1; goto bailout; \
171 #define _throwunix(m) { \
172 snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \
173 retval = -1; goto bailout; \
175 #define _throw(m) { \
176 snprintf(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
177 this->isInstanceError = TRUE; _throwg(m) \
180 #define getinstance(handle) \
181 tjinstance *this = (tjinstance *)handle; \
182 j_compress_ptr cinfo = NULL; \
183 j_decompress_ptr dinfo = NULL; \
186 snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
189 cinfo = &this->cinfo; dinfo = &this->dinfo; \
190 this->jerr.warning = FALSE; \
191 this->isInstanceError = FALSE;
193 #define getcinstance(handle) \
194 tjinstance *this = (tjinstance *)handle; \
195 j_compress_ptr cinfo = NULL; \
198 snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
201 cinfo = &this->cinfo; \
202 this->jerr.warning = FALSE; \
203 this->isInstanceError = FALSE;
205 #define getdinstance(handle) \
206 tjinstance *this = (tjinstance *)handle; \
207 j_decompress_ptr dinfo = NULL; \
210 snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
213 dinfo = &this->dinfo; \
214 this->jerr.warning = FALSE; \
215 this->isInstanceError = FALSE;
217 static int getPixelFormat(int pixelSize, int flags)
219 if (pixelSize == 1) return TJPF_GRAY;
220 if (pixelSize == 3) {
221 if (flags & TJ_BGR) return TJPF_BGR;
222 else return TJPF_RGB;
224 if (pixelSize == 4) {
225 if (flags & TJ_ALPHAFIRST) {
226 if (flags & TJ_BGR) return TJPF_XBGR;
227 else return TJPF_XRGB;
229 if (flags & TJ_BGR) return TJPF_BGRX;
230 else return TJPF_RGBX;
236 static int setCompDefaults(struct jpeg_compress_struct *cinfo, int pixelFormat,
237 int subsamp, int jpegQual, int flags)
242 cinfo->in_color_space = pf2cs[pixelFormat];
243 cinfo->input_components = tjPixelSize[pixelFormat];
244 jpeg_set_defaults(cinfo);
247 if ((env = getenv("TJ_OPTIMIZE")) != NULL && strlen(env) > 0 &&
249 cinfo->optimize_coding = TRUE;
250 if ((env = getenv("TJ_ARITHMETIC")) != NULL && strlen(env) > 0 &&
252 cinfo->arith_code = TRUE;
253 if ((env = getenv("TJ_RESTART")) != NULL && strlen(env) > 0) {
257 if (sscanf(env, "%d%c", &temp, &tempc) >= 1 && temp >= 0 &&
259 if (toupper(tempc) == 'B') {
260 cinfo->restart_interval = temp;
261 cinfo->restart_in_rows = 0;
263 cinfo->restart_in_rows = temp;
269 jpeg_set_quality(cinfo, jpegQual, TRUE);
270 if (jpegQual >= 96 || flags & TJFLAG_ACCURATEDCT)
271 cinfo->dct_method = JDCT_ISLOW;
273 cinfo->dct_method = JDCT_FASTEST;
275 if (subsamp == TJSAMP_GRAY)
276 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
277 else if (pixelFormat == TJPF_CMYK)
278 jpeg_set_colorspace(cinfo, JCS_YCCK);
280 jpeg_set_colorspace(cinfo, JCS_YCbCr);
282 if (flags & TJFLAG_PROGRESSIVE)
283 jpeg_simple_progression(cinfo);
285 else if ((env = getenv("TJ_PROGRESSIVE")) != NULL && strlen(env) > 0 &&
287 jpeg_simple_progression(cinfo);
290 cinfo->comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
291 cinfo->comp_info[1].h_samp_factor = 1;
292 cinfo->comp_info[2].h_samp_factor = 1;
293 if (cinfo->num_components > 3)
294 cinfo->comp_info[3].h_samp_factor = tjMCUWidth[subsamp] / 8;
295 cinfo->comp_info[0].v_samp_factor = tjMCUHeight[subsamp] / 8;
296 cinfo->comp_info[1].v_samp_factor = 1;
297 cinfo->comp_info[2].v_samp_factor = 1;
298 if (cinfo->num_components > 3)
299 cinfo->comp_info[3].v_samp_factor = tjMCUHeight[subsamp] / 8;
305 static int getSubsamp(j_decompress_ptr dinfo)
307 int retval = -1, i, k;
309 /* The sampling factors actually have no meaning with grayscale JPEG files,
310 and in fact it's possible to generate grayscale JPEGs with sampling
311 factors > 1 (even though those sampling factors are ignored by the
312 decompressor.) Thus, we need to treat grayscale as a special case. */
313 if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
316 for (i = 0; i < NUMSUBOPT; i++) {
317 if (dinfo->num_components == pixelsize[i] ||
318 ((dinfo->jpeg_color_space == JCS_YCCK ||
319 dinfo->jpeg_color_space == JCS_CMYK) &&
320 pixelsize[i] == 3 && dinfo->num_components == 4)) {
321 if (dinfo->comp_info[0].h_samp_factor == tjMCUWidth[i] / 8 &&
322 dinfo->comp_info[0].v_samp_factor == tjMCUHeight[i] / 8) {
325 for (k = 1; k < dinfo->num_components; k++) {
326 int href = 1, vref = 1;
328 if ((dinfo->jpeg_color_space == JCS_YCCK ||
329 dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
330 href = tjMCUWidth[i] / 8; vref = tjMCUHeight[i] / 8;
332 if (dinfo->comp_info[k].h_samp_factor == href &&
333 dinfo->comp_info[k].v_samp_factor == vref)
336 if (match == dinfo->num_components - 1) {
340 /* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
341 in non-standard ways. */
342 if (dinfo->comp_info[0].h_samp_factor == 2 &&
343 dinfo->comp_info[0].v_samp_factor == 2 &&
344 (i == TJSAMP_422 || i == TJSAMP_440)) {
347 for (k = 1; k < dinfo->num_components; k++) {
348 int href = tjMCUHeight[i] / 8, vref = tjMCUWidth[i] / 8;
350 if ((dinfo->jpeg_color_space == JCS_YCCK ||
351 dinfo->jpeg_color_space == JCS_CMYK) && k == 3) {
354 if (dinfo->comp_info[k].h_samp_factor == href &&
355 dinfo->comp_info[k].v_samp_factor == vref)
358 if (match == dinfo->num_components - 1) {
368 /* General API functions */
370 DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
372 tjinstance *this = (tjinstance *)handle;
374 if (this && this->isInstanceError) {
375 this->isInstanceError = FALSE;
382 DLLEXPORT char *tjGetErrorStr(void)
388 DLLEXPORT int tjGetErrorCode(tjhandle handle)
390 tjinstance *this = (tjinstance *)handle;
392 if (this && this->jerr.warning) return TJERR_WARNING;
393 else return TJERR_FATAL;
397 DLLEXPORT int tjDestroy(tjhandle handle)
401 if (setjmp(this->jerr.setjmp_buffer)) return -1;
402 if (this->init & COMPRESS) jpeg_destroy_compress(cinfo);
403 if (this->init & DECOMPRESS) jpeg_destroy_decompress(dinfo);
409 /* These are exposed mainly because Windows can't malloc() and free() across
410 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
411 with turbojpeg.dll for compatibility reasons. However, these functions
412 can potentially be used for other purposes by different implementations. */
414 DLLEXPORT void tjFree(unsigned char *buf)
420 DLLEXPORT unsigned char *tjAlloc(int bytes)
422 return (unsigned char *)malloc(bytes);
428 static tjhandle _tjInitCompress(tjinstance *this)
430 static unsigned char buffer[1];
431 unsigned char *buf = buffer;
432 unsigned long size = 1;
434 /* This is also straight out of example.txt */
435 this->cinfo.err = jpeg_std_error(&this->jerr.pub);
436 this->jerr.pub.error_exit = my_error_exit;
437 this->jerr.pub.output_message = my_output_message;
438 this->jerr.emit_message = this->jerr.pub.emit_message;
439 this->jerr.pub.emit_message = my_emit_message;
440 this->jerr.pub.addon_message_table = turbojpeg_message_table;
441 this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
442 this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
444 if (setjmp(this->jerr.setjmp_buffer)) {
445 /* If we get here, the JPEG code has signaled an error. */
446 if (this) free(this);
450 jpeg_create_compress(&this->cinfo);
451 /* Make an initial call so it will create the destination manager */
452 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
454 this->init |= COMPRESS;
455 return (tjhandle)this;
458 DLLEXPORT tjhandle tjInitCompress(void)
460 tjinstance *this = NULL;
462 if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
463 snprintf(errStr, JMSG_LENGTH_MAX,
464 "tjInitCompress(): Memory allocation failure");
467 MEMZERO(this, sizeof(tjinstance));
468 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
469 return _tjInitCompress(this);
473 DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
475 unsigned long retval = 0;
476 int mcuw, mcuh, chromasf;
478 if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT)
479 _throwg("tjBufSize(): Invalid argument");
481 /* This allows for rare corner cases in which a JPEG image can actually be
482 larger than the uncompressed input (we wouldn't mention it if it hadn't
484 mcuw = tjMCUWidth[jpegSubsamp];
485 mcuh = tjMCUHeight[jpegSubsamp];
486 chromasf = jpegSubsamp == TJSAMP_GRAY ? 0 : 4 * 64 / (mcuw * mcuh);
487 retval = PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
493 DLLEXPORT unsigned long TJBUFSIZE(int width, int height)
495 unsigned long retval = 0;
497 if (width < 1 || height < 1)
498 _throwg("TJBUFSIZE(): Invalid argument");
500 /* This allows for rare corner cases in which a JPEG image can actually be
501 larger than the uncompressed input (we wouldn't mention it if it hadn't
503 retval = PAD(width, 16) * PAD(height, 16) * 6 + 2048;
510 DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
513 int retval = 0, nc, i;
515 if (subsamp < 0 || subsamp >= NUMSUBOPT)
516 _throwg("tjBufSizeYUV2(): Invalid argument");
518 nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
519 for (i = 0; i < nc; i++) {
520 int pw = tjPlaneWidth(i, width, subsamp);
521 int stride = PAD(pw, pad);
522 int ph = tjPlaneHeight(i, height, subsamp);
524 if (pw < 0 || ph < 0) return -1;
525 else retval += stride * ph;
532 DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
534 return tjBufSizeYUV2(width, 4, height, subsamp);
537 DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
539 return tjBufSizeYUV(width, height, subsamp);
543 DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
545 int pw, nc, retval = 0;
547 if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
548 _throwg("tjPlaneWidth(): Invalid argument");
549 nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
550 if (componentID < 0 || componentID >= nc)
551 _throwg("tjPlaneWidth(): Invalid argument");
553 pw = PAD(width, tjMCUWidth[subsamp] / 8);
554 if (componentID == 0)
557 retval = pw * 8 / tjMCUWidth[subsamp];
564 DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
566 int ph, nc, retval = 0;
568 if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
569 _throwg("tjPlaneHeight(): Invalid argument");
570 nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
571 if (componentID < 0 || componentID >= nc)
572 _throwg("tjPlaneHeight(): Invalid argument");
574 ph = PAD(height, tjMCUHeight[subsamp] / 8);
575 if (componentID == 0)
578 retval = ph * 8 / tjMCUHeight[subsamp];
585 DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
586 int height, int subsamp)
588 unsigned long retval = 0;
591 if (width < 1 || height < 1 || subsamp < 0 || subsamp >= NUMSUBOPT)
592 _throwg("tjPlaneSizeYUV(): Invalid argument");
594 pw = tjPlaneWidth(componentID, width, subsamp);
595 ph = tjPlaneHeight(componentID, height, subsamp);
596 if (pw < 0 || ph < 0) return -1;
598 if (stride == 0) stride = pw;
599 else stride = abs(stride);
601 retval = stride * (ph - 1) + pw;
608 DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
609 int width, int pitch, int height, int pixelFormat,
610 unsigned char **jpegBuf, unsigned long *jpegSize,
611 int jpegSubsamp, int jpegQual, int flags)
613 int i, retval = 0, alloc = 1;
614 JSAMPROW *row_pointer = NULL;
617 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
618 if ((this->init & COMPRESS) == 0)
619 _throw("tjCompress2(): Instance has not been initialized for compression");
621 if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
622 pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
623 jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT ||
624 jpegQual < 0 || jpegQual > 100)
625 _throw("tjCompress2(): Invalid argument");
627 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
629 if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * height)) == NULL)
630 _throw("tjCompress2(): Memory allocation failure");
632 if (setjmp(this->jerr.setjmp_buffer)) {
633 /* If we get here, the JPEG code has signaled an error. */
634 retval = -1; goto bailout;
637 cinfo->image_width = width;
638 cinfo->image_height = height;
641 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
642 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
643 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
646 if (flags & TJFLAG_NOREALLOC) {
647 alloc = 0; *jpegSize = tjBufSize(width, height, jpegSubsamp);
649 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
650 if (setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags) == -1)
653 jpeg_start_compress(cinfo, TRUE);
654 for (i = 0; i < height; i++) {
655 if (flags & TJFLAG_BOTTOMUP)
656 row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * pitch];
658 row_pointer[i] = (JSAMPROW)&srcBuf[i * pitch];
660 while (cinfo->next_scanline < cinfo->image_height)
661 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
662 cinfo->image_height - cinfo->next_scanline);
663 jpeg_finish_compress(cinfo);
666 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
667 if (row_pointer) free(row_pointer);
668 if (this->jerr.warning) retval = -1;
669 this->jerr.stopOnWarning = FALSE;
673 DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
674 int pitch, int height, int pixelSize,
675 unsigned char *jpegBuf, unsigned long *jpegSize,
676 int jpegSubsamp, int jpegQual, int flags)
681 if (flags & TJ_YUV) {
682 size = tjBufSizeYUV(width, height, jpegSubsamp);
683 retval = tjEncodeYUV2(handle, srcBuf, width, pitch, height,
684 getPixelFormat(pixelSize, flags), jpegBuf,
687 retval = tjCompress2(handle, srcBuf, width, pitch, height,
688 getPixelFormat(pixelSize, flags), &jpegBuf, &size,
689 jpegSubsamp, jpegQual, flags | TJFLAG_NOREALLOC);
696 DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
697 int width, int pitch, int height,
698 int pixelFormat, unsigned char **dstPlanes,
699 int *strides, int subsamp, int flags)
701 JSAMPROW *row_pointer = NULL;
702 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
703 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
704 JSAMPROW *outbuf[MAX_COMPONENTS];
705 int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
707 jpeg_component_info *compptr;
709 getcinstance(handle);
710 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
712 for (i = 0; i < MAX_COMPONENTS; i++) {
713 tmpbuf[i] = NULL; _tmpbuf[i] = NULL;
714 tmpbuf2[i] = NULL; _tmpbuf2[i] = NULL; outbuf[i] = NULL;
717 if ((this->init & COMPRESS) == 0)
718 _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
720 if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
721 pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
722 !dstPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT)
723 _throw("tjEncodeYUVPlanes(): Invalid argument");
724 if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
725 _throw("tjEncodeYUVPlanes(): Invalid argument");
727 if (pixelFormat == TJPF_CMYK)
728 _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
730 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
732 if (setjmp(this->jerr.setjmp_buffer)) {
733 /* If we get here, the JPEG code has signaled an error. */
734 retval = -1; goto bailout;
737 cinfo->image_width = width;
738 cinfo->image_height = height;
741 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
742 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
743 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
746 if (setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags) == -1) return -1;
748 /* Execute only the parts of jpeg_start_compress() that we need. If we
749 were to call the whole jpeg_start_compress() function, then it would try
750 to write the file headers, which could overflow the output buffer if the
751 YUV image were very small. */
752 if (cinfo->global_state != CSTATE_START)
753 _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
754 (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo);
755 jinit_c_master_control(cinfo, FALSE);
756 jinit_color_converter(cinfo);
757 jinit_downsampler(cinfo);
758 (*cinfo->cconvert->start_pass) (cinfo);
760 pw0 = PAD(width, cinfo->max_h_samp_factor);
761 ph0 = PAD(height, cinfo->max_v_samp_factor);
763 if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
764 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
765 for (i = 0; i < height; i++) {
766 if (flags & TJFLAG_BOTTOMUP)
767 row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * pitch];
769 row_pointer[i] = (JSAMPROW)&srcBuf[i * pitch];
772 for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
774 for (i = 0; i < cinfo->num_components; i++) {
775 compptr = &cinfo->comp_info[i];
776 _tmpbuf[i] = (JSAMPLE *)malloc(
777 PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
778 compptr->h_samp_factor, 32) *
779 cinfo->max_v_samp_factor + 32);
781 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
783 (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
785 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
786 for (row = 0; row < cinfo->max_v_samp_factor; row++) {
787 unsigned char *_tmpbuf_aligned =
788 (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
790 tmpbuf[i][row] = &_tmpbuf_aligned[
791 PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) /
792 compptr->h_samp_factor, 32) * row];
795 (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
796 compptr->v_samp_factor + 32);
798 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
799 tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
801 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
802 for (row = 0; row < compptr->v_samp_factor; row++) {
803 unsigned char *_tmpbuf2_aligned =
804 (unsigned char *)PAD((size_t)_tmpbuf2[i], 32);
807 &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
809 pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor;
810 ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor;
811 outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
813 _throw("tjEncodeYUVPlanes(): Memory allocation failure");
815 for (row = 0; row < ph[i]; row++) {
816 outbuf[i][row] = ptr;
817 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
821 if (setjmp(this->jerr.setjmp_buffer)) {
822 /* If we get here, the JPEG code has signaled an error. */
823 retval = -1; goto bailout;
826 for (row = 0; row < ph0; row += cinfo->max_v_samp_factor) {
827 (*cinfo->cconvert->color_convert) (cinfo, &row_pointer[row], tmpbuf, 0,
828 cinfo->max_v_samp_factor);
829 (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0);
830 for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components;
832 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
833 row * compptr->v_samp_factor / cinfo->max_v_samp_factor,
834 compptr->v_samp_factor, pw[i]);
836 cinfo->next_scanline += height;
837 jpeg_abort_compress(cinfo);
840 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
841 if (row_pointer) free(row_pointer);
842 for (i = 0; i < MAX_COMPONENTS; i++) {
843 if (tmpbuf[i] != NULL) free(tmpbuf[i]);
844 if (_tmpbuf[i] != NULL) free(_tmpbuf[i]);
845 if (tmpbuf2[i] != NULL) free(tmpbuf2[i]);
846 if (_tmpbuf2[i] != NULL) free(_tmpbuf2[i]);
847 if (outbuf[i] != NULL) free(outbuf[i]);
849 if (this->jerr.warning) retval = -1;
850 this->jerr.stopOnWarning = FALSE;
854 DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
855 int width, int pitch, int height, int pixelFormat,
856 unsigned char *dstBuf, int pad, int subsamp,
859 unsigned char *dstPlanes[3];
860 int pw0, ph0, strides[3], retval = -1;
861 tjinstance *this = (tjinstance *)handle;
863 if (!this) _throwg("tjEncodeYUV3(): Invalid handle");
864 this->isInstanceError = FALSE;
866 if (width <= 0 || height <= 0 || dstBuf == NULL || pad < 0 || !isPow2(pad) ||
867 subsamp < 0 || subsamp >= NUMSUBOPT)
868 _throw("tjEncodeYUV3(): Invalid argument");
870 pw0 = tjPlaneWidth(0, width, subsamp);
871 ph0 = tjPlaneHeight(0, height, subsamp);
872 dstPlanes[0] = dstBuf;
873 strides[0] = PAD(pw0, pad);
874 if (subsamp == TJSAMP_GRAY) {
875 strides[1] = strides[2] = 0;
876 dstPlanes[1] = dstPlanes[2] = NULL;
878 int pw1 = tjPlaneWidth(1, width, subsamp);
879 int ph1 = tjPlaneHeight(1, height, subsamp);
881 strides[1] = strides[2] = PAD(pw1, pad);
882 dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
883 dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
886 return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
887 dstPlanes, strides, subsamp, flags);
893 DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
894 int pitch, int height, int pixelFormat,
895 unsigned char *dstBuf, int subsamp, int flags)
897 return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
898 dstBuf, 4, subsamp, flags);
901 DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
902 int pitch, int height, int pixelSize,
903 unsigned char *dstBuf, int subsamp, int flags)
905 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
906 getPixelFormat(pixelSize, flags), dstBuf, subsamp,
911 DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
912 const unsigned char **srcPlanes,
913 int width, const int *strides,
914 int height, int subsamp,
915 unsigned char **jpegBuf,
916 unsigned long *jpegSize, int jpegQual,
919 int i, row, retval = 0, alloc = 1;
920 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
921 tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
922 JSAMPLE *_tmpbuf = NULL, *ptr;
923 JSAMPROW *inbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
926 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
928 for (i = 0; i < MAX_COMPONENTS; i++) {
929 tmpbuf[i] = NULL; inbuf[i] = NULL;
932 if ((this->init & COMPRESS) == 0)
933 _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
935 if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
936 subsamp < 0 || subsamp >= NUMSUBOPT || jpegBuf == NULL ||
937 jpegSize == NULL || jpegQual < 0 || jpegQual > 100)
938 _throw("tjCompressFromYUVPlanes(): Invalid argument");
939 if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
940 _throw("tjCompressFromYUVPlanes(): Invalid argument");
942 if (setjmp(this->jerr.setjmp_buffer)) {
943 /* If we get here, the JPEG code has signaled an error. */
944 retval = -1; goto bailout;
947 cinfo->image_width = width;
948 cinfo->image_height = height;
951 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
952 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
953 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
956 if (flags & TJFLAG_NOREALLOC) {
957 alloc = 0; *jpegSize = tjBufSize(width, height, subsamp);
959 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
960 if (setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags) == -1)
962 cinfo->raw_data_in = TRUE;
964 jpeg_start_compress(cinfo, TRUE);
965 for (i = 0; i < cinfo->num_components; i++) {
966 jpeg_component_info *compptr = &cinfo->comp_info[i];
969 iw[i] = compptr->width_in_blocks * DCTSIZE;
970 ih = compptr->height_in_blocks * DCTSIZE;
971 pw[i] = PAD(cinfo->image_width, cinfo->max_h_samp_factor) *
972 compptr->h_samp_factor / cinfo->max_h_samp_factor;
973 ph[i] = PAD(cinfo->image_height, cinfo->max_v_samp_factor) *
974 compptr->v_samp_factor / cinfo->max_v_samp_factor;
975 if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
976 th[i] = compptr->v_samp_factor * DCTSIZE;
977 tmpbufsize += iw[i] * th[i];
978 if ((inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
979 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
980 ptr = (JSAMPLE *)srcPlanes[i];
981 for (row = 0; row < ph[i]; row++) {
983 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
987 if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
988 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
990 for (i = 0; i < cinfo->num_components; i++) {
991 if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
992 _throw("tjCompressFromYUVPlanes(): Memory allocation failure");
993 for (row = 0; row < th[i]; row++) {
994 tmpbuf[i][row] = ptr;
1000 if (setjmp(this->jerr.setjmp_buffer)) {
1001 /* If we get here, the JPEG code has signaled an error. */
1002 retval = -1; goto bailout;
1005 for (row = 0; row < (int)cinfo->image_height;
1006 row += cinfo->max_v_samp_factor * DCTSIZE) {
1007 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1008 int crow[MAX_COMPONENTS];
1010 for (i = 0; i < cinfo->num_components; i++) {
1011 jpeg_component_info *compptr = &cinfo->comp_info[i];
1013 crow[i] = row * compptr->v_samp_factor / cinfo->max_v_samp_factor;
1017 for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1018 memcpy(tmpbuf[i][j], inbuf[i][crow[i] + j], pw[i]);
1019 /* Duplicate last sample in row to fill out MCU */
1020 for (k = pw[i]; k < iw[i]; k++)
1021 tmpbuf[i][j][k] = tmpbuf[i][j][pw[i] - 1];
1023 /* Duplicate last row to fill out MCU */
1024 for (j = ph[i] - crow[i]; j < th[i]; j++)
1025 memcpy(tmpbuf[i][j], tmpbuf[i][ph[i] - crow[i] - 1], iw[i]);
1026 yuvptr[i] = tmpbuf[i];
1028 yuvptr[i] = &inbuf[i][crow[i]];
1030 jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor * DCTSIZE);
1032 jpeg_finish_compress(cinfo);
1035 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1036 for (i = 0; i < MAX_COMPONENTS; i++) {
1037 if (tmpbuf[i]) free(tmpbuf[i]);
1038 if (inbuf[i]) free(inbuf[i]);
1040 if (_tmpbuf) free(_tmpbuf);
1041 if (this->jerr.warning) retval = -1;
1042 this->jerr.stopOnWarning = FALSE;
1046 DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
1047 int width, int pad, int height, int subsamp,
1048 unsigned char **jpegBuf,
1049 unsigned long *jpegSize, int jpegQual,
1052 const unsigned char *srcPlanes[3];
1053 int pw0, ph0, strides[3], retval = -1;
1054 tjinstance *this = (tjinstance *)handle;
1056 if (!this) _throwg("tjCompressFromYUV(): Invalid handle");
1057 this->isInstanceError = FALSE;
1059 if (srcBuf == NULL || width <= 0 || pad < 1 || height <= 0 || subsamp < 0 ||
1060 subsamp >= NUMSUBOPT)
1061 _throw("tjCompressFromYUV(): Invalid argument");
1063 pw0 = tjPlaneWidth(0, width, subsamp);
1064 ph0 = tjPlaneHeight(0, height, subsamp);
1065 srcPlanes[0] = srcBuf;
1066 strides[0] = PAD(pw0, pad);
1067 if (subsamp == TJSAMP_GRAY) {
1068 strides[1] = strides[2] = 0;
1069 srcPlanes[1] = srcPlanes[2] = NULL;
1071 int pw1 = tjPlaneWidth(1, width, subsamp);
1072 int ph1 = tjPlaneHeight(1, height, subsamp);
1074 strides[1] = strides[2] = PAD(pw1, pad);
1075 srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1076 srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1079 return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1080 subsamp, jpegBuf, jpegSize, jpegQual, flags);
1089 static tjhandle _tjInitDecompress(tjinstance *this)
1091 static unsigned char buffer[1];
1093 /* This is also straight out of example.txt */
1094 this->dinfo.err = jpeg_std_error(&this->jerr.pub);
1095 this->jerr.pub.error_exit = my_error_exit;
1096 this->jerr.pub.output_message = my_output_message;
1097 this->jerr.emit_message = this->jerr.pub.emit_message;
1098 this->jerr.pub.emit_message = my_emit_message;
1099 this->jerr.pub.addon_message_table = turbojpeg_message_table;
1100 this->jerr.pub.first_addon_message = JMSG_FIRSTADDONCODE;
1101 this->jerr.pub.last_addon_message = JMSG_LASTADDONCODE;
1103 if (setjmp(this->jerr.setjmp_buffer)) {
1104 /* If we get here, the JPEG code has signaled an error. */
1105 if (this) free(this);
1109 jpeg_create_decompress(&this->dinfo);
1110 /* Make an initial call so it will create the source manager */
1111 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1113 this->init |= DECOMPRESS;
1114 return (tjhandle)this;
1117 DLLEXPORT tjhandle tjInitDecompress(void)
1121 if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
1122 snprintf(errStr, JMSG_LENGTH_MAX,
1123 "tjInitDecompress(): Memory allocation failure");
1126 MEMZERO(this, sizeof(tjinstance));
1127 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
1128 return _tjInitDecompress(this);
1132 DLLEXPORT int tjDecompressHeader3(tjhandle handle,
1133 const unsigned char *jpegBuf,
1134 unsigned long jpegSize, int *width,
1135 int *height, int *jpegSubsamp,
1136 int *jpegColorspace)
1140 getdinstance(handle);
1141 if ((this->init & DECOMPRESS) == 0)
1142 _throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
1144 if (jpegBuf == NULL || jpegSize <= 0 || width == NULL || height == NULL ||
1145 jpegSubsamp == NULL || jpegColorspace == NULL)
1146 _throw("tjDecompressHeader3(): Invalid argument");
1148 if (setjmp(this->jerr.setjmp_buffer)) {
1149 /* If we get here, the JPEG code has signaled an error. */
1153 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1154 jpeg_read_header(dinfo, TRUE);
1156 *width = dinfo->image_width;
1157 *height = dinfo->image_height;
1158 *jpegSubsamp = getSubsamp(dinfo);
1159 switch (dinfo->jpeg_color_space) {
1160 case JCS_GRAYSCALE: *jpegColorspace = TJCS_GRAY; break;
1161 case JCS_RGB: *jpegColorspace = TJCS_RGB; break;
1162 case JCS_YCbCr: *jpegColorspace = TJCS_YCbCr; break;
1163 case JCS_CMYK: *jpegColorspace = TJCS_CMYK; break;
1164 case JCS_YCCK: *jpegColorspace = TJCS_YCCK; break;
1165 default: *jpegColorspace = -1; break;
1168 jpeg_abort_decompress(dinfo);
1170 if (*jpegSubsamp < 0)
1171 _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1172 if (*jpegColorspace < 0)
1173 _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1174 if (*width < 1 || *height < 1)
1175 _throw("tjDecompressHeader3(): Invalid data returned in header");
1178 if (this->jerr.warning) retval = -1;
1182 DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
1183 unsigned long jpegSize, int *width,
1184 int *height, int *jpegSubsamp)
1188 return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1189 jpegSubsamp, &jpegColorspace);
1192 DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
1193 unsigned long jpegSize, int *width,
1198 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1203 DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numscalingfactors)
1205 if (numscalingfactors == NULL) {
1206 snprintf(errStr, JMSG_LENGTH_MAX,
1207 "tjGetScalingFactors(): Invalid argument");
1211 *numscalingfactors = NUMSF;
1212 return (tjscalingfactor *)sf;
1216 DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
1217 unsigned long jpegSize, unsigned char *dstBuf,
1218 int width, int pitch, int height, int pixelFormat,
1221 JSAMPROW *row_pointer = NULL;
1222 int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
1224 getdinstance(handle);
1225 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1226 if ((this->init & DECOMPRESS) == 0)
1227 _throw("tjDecompress2(): Instance has not been initialized for decompression");
1229 if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1230 pitch < 0 || height < 0 || pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1231 _throw("tjDecompress2(): Invalid argument");
1234 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1235 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1236 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1239 if (setjmp(this->jerr.setjmp_buffer)) {
1240 /* If we get here, the JPEG code has signaled an error. */
1241 retval = -1; goto bailout;
1244 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1245 jpeg_read_header(dinfo, TRUE);
1246 this->dinfo.out_color_space = pf2cs[pixelFormat];
1247 if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1248 if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1250 jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
1251 if (width == 0) width = jpegwidth;
1252 if (height == 0) height = jpegheight;
1253 for (i = 0; i < NUMSF; i++) {
1254 scaledw = TJSCALED(jpegwidth, sf[i]);
1255 scaledh = TJSCALED(jpegheight, sf[i]);
1256 if (scaledw <= width && scaledh <= height)
1260 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
1261 width = scaledw; height = scaledh;
1262 dinfo->scale_num = sf[i].num;
1263 dinfo->scale_denom = sf[i].denom;
1265 jpeg_start_decompress(dinfo);
1266 if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1269 (JSAMPROW *)malloc(sizeof(JSAMPROW) * dinfo->output_height)) == NULL)
1270 _throw("tjDecompress2(): Memory allocation failure");
1271 if (setjmp(this->jerr.setjmp_buffer)) {
1272 /* If we get here, the JPEG code has signaled an error. */
1273 retval = -1; goto bailout;
1275 for (i = 0; i < (int)dinfo->output_height; i++) {
1276 if (flags & TJFLAG_BOTTOMUP)
1277 row_pointer[i] = &dstBuf[(dinfo->output_height - i - 1) * pitch];
1279 row_pointer[i] = &dstBuf[i * pitch];
1281 while (dinfo->output_scanline < dinfo->output_height)
1282 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1283 dinfo->output_height - dinfo->output_scanline);
1284 jpeg_finish_decompress(dinfo);
1287 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1288 if (row_pointer) free(row_pointer);
1289 if (this->jerr.warning) retval = -1;
1290 this->jerr.stopOnWarning = FALSE;
1294 DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1295 unsigned long jpegSize, unsigned char *dstBuf,
1296 int width, int pitch, int height, int pixelSize,
1300 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1302 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1303 height, getPixelFormat(pixelSize, flags), flags);
1307 static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1308 int pixelFormat, int subsamp, int flags)
1312 dinfo->scale_num = dinfo->scale_denom = 1;
1314 if (subsamp == TJSAMP_GRAY) {
1315 dinfo->num_components = dinfo->comps_in_scan = 1;
1316 dinfo->jpeg_color_space = JCS_GRAYSCALE;
1318 dinfo->num_components = dinfo->comps_in_scan = 3;
1319 dinfo->jpeg_color_space = JCS_YCbCr;
1322 dinfo->comp_info = (jpeg_component_info *)
1323 (*dinfo->mem->alloc_small) ((j_common_ptr)dinfo, JPOOL_IMAGE,
1324 dinfo->num_components *
1325 sizeof(jpeg_component_info));
1327 for (i = 0; i < dinfo->num_components; i++) {
1328 jpeg_component_info *compptr = &dinfo->comp_info[i];
1330 compptr->h_samp_factor = (i == 0) ? tjMCUWidth[subsamp] / 8 : 1;
1331 compptr->v_samp_factor = (i == 0) ? tjMCUHeight[subsamp] / 8 : 1;
1332 compptr->component_index = i;
1333 compptr->component_id = i + 1;
1334 compptr->quant_tbl_no = compptr->dc_tbl_no =
1335 compptr->ac_tbl_no = (i == 0) ? 0 : 1;
1336 dinfo->cur_comp_info[i] = compptr;
1338 dinfo->data_precision = 8;
1339 for (i = 0; i < 2; i++) {
1340 if (dinfo->quant_tbl_ptrs[i] == NULL)
1341 dinfo->quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)dinfo);
1348 int my_read_markers(j_decompress_ptr dinfo)
1350 return JPEG_REACHED_SOS;
1353 void my_reset_marker_reader(j_decompress_ptr dinfo)
1357 DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
1358 const unsigned char **srcPlanes,
1359 const int *strides, int subsamp,
1360 unsigned char *dstBuf, int width, int pitch,
1361 int height, int pixelFormat, int flags)
1363 JSAMPROW *row_pointer = NULL;
1364 JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1365 JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
1366 int i, retval = 0, row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1368 jpeg_component_info *compptr;
1369 int (*old_read_markers) (j_decompress_ptr);
1370 void (*old_reset_marker_reader) (j_decompress_ptr);
1372 getdinstance(handle);
1373 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1375 for (i = 0; i < MAX_COMPONENTS; i++) {
1376 tmpbuf[i] = NULL; _tmpbuf[i] = NULL; inbuf[i] = NULL;
1379 if ((this->init & DECOMPRESS) == 0)
1380 _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
1382 if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT ||
1383 dstBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
1384 pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
1385 _throw("tjDecodeYUVPlanes(): Invalid argument");
1386 if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1387 _throw("tjDecodeYUVPlanes(): Invalid argument");
1389 if (setjmp(this->jerr.setjmp_buffer)) {
1390 /* If we get here, the JPEG code has signaled an error. */
1391 retval = -1; goto bailout;
1394 if (pixelFormat == TJPF_CMYK)
1395 _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
1397 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
1398 dinfo->image_width = width;
1399 dinfo->image_height = height;
1402 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1403 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1404 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1407 if (setDecodeDefaults(dinfo, pixelFormat, subsamp, flags) == -1) {
1408 retval = -1; goto bailout;
1410 old_read_markers = dinfo->marker->read_markers;
1411 dinfo->marker->read_markers = my_read_markers;
1412 old_reset_marker_reader = dinfo->marker->reset_marker_reader;
1413 dinfo->marker->reset_marker_reader = my_reset_marker_reader;
1414 jpeg_read_header(dinfo, TRUE);
1415 dinfo->marker->read_markers = old_read_markers;
1416 dinfo->marker->reset_marker_reader = old_reset_marker_reader;
1418 this->dinfo.out_color_space = pf2cs[pixelFormat];
1419 if (flags & TJFLAG_FASTDCT) this->dinfo.dct_method = JDCT_FASTEST;
1420 dinfo->do_fancy_upsampling = FALSE;
1421 dinfo->Se = DCTSIZE2 - 1;
1422 jinit_master_decompress(dinfo);
1423 (*dinfo->upsample->start_pass) (dinfo);
1425 pw0 = PAD(width, dinfo->max_h_samp_factor);
1426 ph0 = PAD(height, dinfo->max_v_samp_factor);
1428 if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
1430 if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
1431 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1432 for (i = 0; i < height; i++) {
1433 if (flags & TJFLAG_BOTTOMUP)
1434 row_pointer[i] = &dstBuf[(height - i - 1) * pitch];
1436 row_pointer[i] = &dstBuf[i * pitch];
1439 for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1];
1441 for (i = 0; i < dinfo->num_components; i++) {
1442 compptr = &dinfo->comp_info[i];
1444 (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
1445 compptr->v_samp_factor + 32);
1447 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1448 tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
1450 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1451 for (row = 0; row < compptr->v_samp_factor; row++) {
1452 unsigned char *_tmpbuf_aligned =
1453 (unsigned char *)PAD((size_t)_tmpbuf[i], 32);
1456 &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row];
1458 pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor;
1459 ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1460 inbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]);
1462 _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1463 ptr = (JSAMPLE *)srcPlanes[i];
1464 for (row = 0; row < ph[i]; row++) {
1465 inbuf[i][row] = ptr;
1466 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1470 if (setjmp(this->jerr.setjmp_buffer)) {
1471 /* If we get here, the JPEG code has signaled an error. */
1472 retval = -1; goto bailout;
1475 for (row = 0; row < ph0; row += dinfo->max_v_samp_factor) {
1476 JDIMENSION inrow = 0, outrow = 0;
1478 for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components;
1480 jcopy_sample_rows(inbuf[i],
1481 row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0,
1482 compptr->v_samp_factor, pw[i]);
1483 (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow,
1484 dinfo->max_v_samp_factor, &row_pointer[row],
1485 &outrow, dinfo->max_v_samp_factor);
1487 jpeg_abort_decompress(dinfo);
1490 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1491 if (row_pointer) free(row_pointer);
1492 for (i = 0; i < MAX_COMPONENTS; i++) {
1493 if (tmpbuf[i] != NULL) free(tmpbuf[i]);
1494 if (_tmpbuf[i] != NULL) free(_tmpbuf[i]);
1495 if (inbuf[i] != NULL) free(inbuf[i]);
1497 if (this->jerr.warning) retval = -1;
1498 this->jerr.stopOnWarning = FALSE;
1502 DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
1503 int pad, int subsamp, unsigned char *dstBuf,
1504 int width, int pitch, int height, int pixelFormat,
1507 const unsigned char *srcPlanes[3];
1508 int pw0, ph0, strides[3], retval = -1;
1509 tjinstance *this = (tjinstance *)handle;
1511 if (!this) _throwg("tjDecodeYUV(): Invalid handle");
1512 this->isInstanceError = FALSE;
1514 if (srcBuf == NULL || pad < 0 || !isPow2(pad) || subsamp < 0 ||
1515 subsamp >= NUMSUBOPT || width <= 0 || height <= 0)
1516 _throw("tjDecodeYUV(): Invalid argument");
1518 pw0 = tjPlaneWidth(0, width, subsamp);
1519 ph0 = tjPlaneHeight(0, height, subsamp);
1520 srcPlanes[0] = srcBuf;
1521 strides[0] = PAD(pw0, pad);
1522 if (subsamp == TJSAMP_GRAY) {
1523 strides[1] = strides[2] = 0;
1524 srcPlanes[1] = srcPlanes[2] = NULL;
1526 int pw1 = tjPlaneWidth(1, width, subsamp);
1527 int ph1 = tjPlaneHeight(1, height, subsamp);
1529 strides[1] = strides[2] = PAD(pw1, pad);
1530 srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
1531 srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
1534 return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1535 pitch, height, pixelFormat, flags);
1541 DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
1542 const unsigned char *jpegBuf,
1543 unsigned long jpegSize,
1544 unsigned char **dstPlanes, int width,
1545 int *strides, int height, int flags)
1547 int i, sfi, row, retval = 0;
1548 int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
1549 int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1550 tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS];
1551 JSAMPLE *_tmpbuf = NULL, *ptr;
1552 JSAMPROW *outbuf[MAX_COMPONENTS], *tmpbuf[MAX_COMPONENTS];
1555 getdinstance(handle);
1556 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1558 for (i = 0; i < MAX_COMPONENTS; i++) {
1559 tmpbuf[i] = NULL; outbuf[i] = NULL;
1562 if ((this->init & DECOMPRESS) == 0)
1563 _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
1565 if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0] ||
1566 width < 0 || height < 0)
1567 _throw("tjDecompressToYUVPlanes(): Invalid argument");
1570 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1571 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1572 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1575 if (setjmp(this->jerr.setjmp_buffer)) {
1576 /* If we get here, the JPEG code has signaled an error. */
1577 retval = -1; goto bailout;
1580 if (!this->headerRead) {
1581 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1582 jpeg_read_header(dinfo, TRUE);
1584 this->headerRead = 0;
1585 jpegSubsamp = getSubsamp(dinfo);
1586 if (jpegSubsamp < 0)
1587 _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1589 if (jpegSubsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1590 _throw("tjDecompressToYUVPlanes(): Invalid argument");
1592 jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
1593 if (width == 0) width = jpegwidth;
1594 if (height == 0) height = jpegheight;
1595 for (i = 0; i < NUMSF; i++) {
1596 scaledw = TJSCALED(jpegwidth, sf[i]);
1597 scaledh = TJSCALED(jpegheight, sf[i]);
1598 if (scaledw <= width && scaledh <= height)
1602 _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
1603 if (dinfo->num_components > 3)
1604 _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
1606 width = scaledw; height = scaledh;
1607 dinfo->scale_num = sf[i].num;
1608 dinfo->scale_denom = sf[i].denom;
1610 jpeg_calc_output_dimensions(dinfo);
1612 dctsize = DCTSIZE * sf[sfi].num / sf[sfi].denom;
1614 for (i = 0; i < dinfo->num_components; i++) {
1615 jpeg_component_info *compptr = &dinfo->comp_info[i];
1618 iw[i] = compptr->width_in_blocks * dctsize;
1619 ih = compptr->height_in_blocks * dctsize;
1620 pw[i] = PAD(dinfo->output_width, dinfo->max_h_samp_factor) *
1621 compptr->h_samp_factor / dinfo->max_h_samp_factor;
1622 ph[i] = PAD(dinfo->output_height, dinfo->max_v_samp_factor) *
1623 compptr->v_samp_factor / dinfo->max_v_samp_factor;
1624 if (iw[i] != pw[i] || ih != ph[i]) usetmpbuf = 1;
1625 th[i] = compptr->v_samp_factor * dctsize;
1626 tmpbufsize += iw[i] * th[i];
1627 if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL)
1628 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1630 for (row = 0; row < ph[i]; row++) {
1631 outbuf[i][row] = ptr;
1632 ptr += (strides && strides[i] != 0) ? strides[i] : pw[i];
1636 if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
1637 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1639 for (i = 0; i < dinfo->num_components; i++) {
1640 if ((tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * th[i])) == NULL)
1641 _throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1642 for (row = 0; row < th[i]; row++) {
1643 tmpbuf[i][row] = ptr;
1649 if (setjmp(this->jerr.setjmp_buffer)) {
1650 /* If we get here, the JPEG code has signaled an error. */
1651 retval = -1; goto bailout;
1654 if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
1655 if (flags & TJFLAG_FASTDCT) dinfo->dct_method = JDCT_FASTEST;
1656 dinfo->raw_data_out = TRUE;
1658 jpeg_start_decompress(dinfo);
1659 for (row = 0; row < (int)dinfo->output_height;
1660 row += dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size) {
1661 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1662 int crow[MAX_COMPONENTS];
1664 for (i = 0; i < dinfo->num_components; i++) {
1665 jpeg_component_info *compptr = &dinfo->comp_info[i];
1667 if (jpegSubsamp == TJ_420) {
1668 /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1669 to be clever and use the IDCT to perform upsampling on the U and V
1670 planes. For instance, if the output image is to be scaled by 1/2
1671 relative to the JPEG image, then the scaling factor and upsampling
1672 effectively cancel each other, so a normal 8x8 IDCT can be used.
1673 However, this is not desirable when using the decompress-to-YUV
1674 functionality in TurboJPEG, since we want to output the U and V
1675 planes in their subsampled form. Thus, we have to override some
1676 internal libjpeg parameters to force it to use the "scaled" IDCT
1677 functions on the U and V planes. */
1678 compptr->_DCT_scaled_size = dctsize;
1679 compptr->MCU_sample_width = tjMCUWidth[jpegSubsamp] *
1680 sf[sfi].num / sf[sfi].denom *
1681 compptr->v_samp_factor / dinfo->max_v_samp_factor;
1682 dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1684 crow[i] = row * compptr->v_samp_factor / dinfo->max_v_samp_factor;
1685 if (usetmpbuf) yuvptr[i] = tmpbuf[i];
1686 else yuvptr[i] = &outbuf[i][crow[i]];
1688 jpeg_read_raw_data(dinfo, yuvptr,
1689 dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size);
1693 for (i = 0; i < dinfo->num_components; i++) {
1694 for (j = 0; j < MIN(th[i], ph[i] - crow[i]); j++) {
1695 memcpy(outbuf[i][crow[i] + j], tmpbuf[i][j], pw[i]);
1700 jpeg_finish_decompress(dinfo);
1703 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1704 for (i = 0; i < MAX_COMPONENTS; i++) {
1705 if (tmpbuf[i]) free(tmpbuf[i]);
1706 if (outbuf[i]) free(outbuf[i]);
1708 if (_tmpbuf) free(_tmpbuf);
1709 if (this->jerr.warning) retval = -1;
1710 this->jerr.stopOnWarning = FALSE;
1714 DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
1715 unsigned long jpegSize, unsigned char *dstBuf,
1716 int width, int pad, int height, int flags)
1718 unsigned char *dstPlanes[3];
1719 int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1;
1720 int i, jpegwidth, jpegheight, scaledw, scaledh;
1722 getdinstance(handle);
1723 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1725 if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
1726 pad < 1 || !isPow2(pad) || height < 0)
1727 _throw("tjDecompressToYUV2(): Invalid argument");
1729 if (setjmp(this->jerr.setjmp_buffer)) {
1730 /* If we get here, the JPEG code has signaled an error. */
1734 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1735 jpeg_read_header(dinfo, TRUE);
1736 jpegSubsamp = getSubsamp(dinfo);
1737 if (jpegSubsamp < 0)
1738 _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1740 jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
1741 if (width == 0) width = jpegwidth;
1742 if (height == 0) height = jpegheight;
1744 for (i = 0; i < NUMSF; i++) {
1745 scaledw = TJSCALED(jpegwidth, sf[i]);
1746 scaledh = TJSCALED(jpegheight, sf[i]);
1747 if (scaledw <= width && scaledh <= height)
1751 _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1753 pw0 = tjPlaneWidth(0, width, jpegSubsamp);
1754 ph0 = tjPlaneHeight(0, height, jpegSubsamp);
1755 dstPlanes[0] = dstBuf;
1756 strides[0] = PAD(pw0, pad);
1757 if (jpegSubsamp == TJSAMP_GRAY) {
1758 strides[1] = strides[2] = 0;
1759 dstPlanes[1] = dstPlanes[2] = NULL;
1761 int pw1 = tjPlaneWidth(1, width, jpegSubsamp);
1762 int ph1 = tjPlaneHeight(1, height, jpegSubsamp);
1764 strides[1] = strides[2] = PAD(pw1, pad);
1765 dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
1766 dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
1769 this->headerRead = 1;
1770 return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1771 strides, height, flags);
1774 this->jerr.stopOnWarning = FALSE;
1778 DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
1779 unsigned long jpegSize, unsigned char *dstBuf,
1782 return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1788 DLLEXPORT tjhandle tjInitTransform(void)
1790 tjinstance *this = NULL;
1791 tjhandle handle = NULL;
1793 if ((this = (tjinstance *)malloc(sizeof(tjinstance))) == NULL) {
1794 snprintf(errStr, JMSG_LENGTH_MAX,
1795 "tjInitTransform(): Memory allocation failure");
1798 MEMZERO(this, sizeof(tjinstance));
1799 snprintf(this->errStr, JMSG_LENGTH_MAX, "No error");
1800 handle = _tjInitCompress(this);
1801 if (!handle) return NULL;
1802 handle = _tjInitDecompress(this);
1807 DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
1808 unsigned long jpegSize, int n,
1809 unsigned char **dstBufs, unsigned long *dstSizes,
1810 tjtransform *t, int flags)
1812 jpeg_transform_info *xinfo = NULL;
1813 jvirt_barray_ptr *srccoefs, *dstcoefs;
1814 int retval = 0, i, jpegSubsamp, saveMarkers = 0;
1816 getinstance(handle);
1817 this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
1818 if ((this->init & COMPRESS) == 0 || (this->init & DECOMPRESS) == 0)
1819 _throw("tjTransform(): Instance has not been initialized for transformation");
1821 if (jpegBuf == NULL || jpegSize <= 0 || n < 1 || dstBufs == NULL ||
1822 dstSizes == NULL || t == NULL || flags < 0)
1823 _throw("tjTransform(): Invalid argument");
1826 if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1827 else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1828 else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1832 (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
1833 _throw("tjTransform(): Memory allocation failure");
1834 MEMZERO(xinfo, sizeof(jpeg_transform_info) * n);
1836 if (setjmp(this->jerr.setjmp_buffer)) {
1837 /* If we get here, the JPEG code has signaled an error. */
1838 retval = -1; goto bailout;
1841 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1843 for (i = 0; i < n; i++) {
1844 xinfo[i].transform = xformtypes[t[i].op];
1845 xinfo[i].perfect = (t[i].options & TJXOPT_PERFECT) ? 1 : 0;
1846 xinfo[i].trim = (t[i].options & TJXOPT_TRIM) ? 1 : 0;
1847 xinfo[i].force_grayscale = (t[i].options & TJXOPT_GRAY) ? 1 : 0;
1848 xinfo[i].crop = (t[i].options & TJXOPT_CROP) ? 1 : 0;
1849 if (n != 1 && t[i].op == TJXOP_HFLIP) xinfo[i].slow_hflip = 1;
1850 else xinfo[i].slow_hflip = 0;
1852 if (xinfo[i].crop) {
1853 xinfo[i].crop_xoffset = t[i].r.x; xinfo[i].crop_xoffset_set = JCROP_POS;
1854 xinfo[i].crop_yoffset = t[i].r.y; xinfo[i].crop_yoffset_set = JCROP_POS;
1855 if (t[i].r.w != 0) {
1856 xinfo[i].crop_width = t[i].r.w; xinfo[i].crop_width_set = JCROP_POS;
1858 xinfo[i].crop_width = JCROP_UNSET;
1859 if (t[i].r.h != 0) {
1860 xinfo[i].crop_height = t[i].r.h; xinfo[i].crop_height_set = JCROP_POS;
1862 xinfo[i].crop_height = JCROP_UNSET;
1864 if (!(t[i].options & TJXOPT_COPYNONE)) saveMarkers = 1;
1867 jcopy_markers_setup(dinfo, saveMarkers ? JCOPYOPT_ALL : JCOPYOPT_NONE);
1868 jpeg_read_header(dinfo, TRUE);
1869 jpegSubsamp = getSubsamp(dinfo);
1870 if (jpegSubsamp < 0)
1871 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
1873 for (i = 0; i < n; i++) {
1874 if (!jtransform_request_workspace(dinfo, &xinfo[i]))
1875 _throw("tjTransform(): Transform is not perfect");
1877 if (xinfo[i].crop) {
1878 if ((t[i].r.x % xinfo[i].iMCU_sample_width) != 0 ||
1879 (t[i].r.y % xinfo[i].iMCU_sample_height) != 0) {
1880 snprintf(errStr, JMSG_LENGTH_MAX,
1881 "To crop this JPEG image, x must be a multiple of %d\n"
1882 "and y must be a multiple of %d.\n",
1883 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1884 retval = -1; goto bailout;
1889 srccoefs = jpeg_read_coefficients(dinfo);
1891 for (i = 0; i < n; i++) {
1892 int w, h, alloc = 1;
1894 if (!xinfo[i].crop) {
1895 w = dinfo->image_width; h = dinfo->image_height;
1897 w = xinfo[i].crop_width; h = xinfo[i].crop_height;
1899 if (flags & TJFLAG_NOREALLOC) {
1900 alloc = 0; dstSizes[i] = tjBufSize(w, h, jpegSubsamp);
1902 if (!(t[i].options & TJXOPT_NOOUTPUT))
1903 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
1904 jpeg_copy_critical_parameters(dinfo, cinfo);
1905 dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
1906 if (flags & TJFLAG_PROGRESSIVE || t[i].options & TJXOPT_PROGRESSIVE)
1907 jpeg_simple_progression(cinfo);
1908 if (!(t[i].options & TJXOPT_NOOUTPUT)) {
1909 jpeg_write_coefficients(cinfo, dstcoefs);
1910 jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
1911 JCOPYOPT_NONE : JCOPYOPT_ALL);
1913 jinit_c_master_control(cinfo, TRUE);
1914 jtransform_execute_transformation(dinfo, cinfo, srccoefs, &xinfo[i]);
1915 if (t[i].customFilter) {
1919 for (ci = 0; ci < cinfo->num_components; ci++) {
1920 jpeg_component_info *compptr = &cinfo->comp_info[ci];
1921 tjregion arrayRegion = {
1922 0, 0, compptr->width_in_blocks * DCTSIZE, DCTSIZE
1924 tjregion planeRegion = {
1925 0, 0, compptr->width_in_blocks * DCTSIZE,
1926 compptr->height_in_blocks * DCTSIZE
1929 for (by = 0; by < compptr->height_in_blocks;
1930 by += compptr->v_samp_factor) {
1931 JBLOCKARRAY barray = (dinfo->mem->access_virt_barray)
1932 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1935 for (y = 0; y < compptr->v_samp_factor; y++) {
1936 if (t[i].customFilter(barray[y][0], arrayRegion, planeRegion, ci,
1938 _throw("tjTransform(): Error in custom filter");
1939 arrayRegion.y += DCTSIZE;
1944 if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
1947 jpeg_finish_decompress(dinfo);
1950 if (cinfo->global_state > CSTATE_START) jpeg_abort_compress(cinfo);
1951 if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
1952 if (xinfo) free(xinfo);
1953 if (this->jerr.warning) retval = -1;
1954 this->jerr.stopOnWarning = FALSE;
1959 DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
1960 int align, int *height, int *pixelFormat,
1963 int retval = 0, tempc, pitch;
1964 tjhandle handle = NULL;
1966 j_compress_ptr cinfo = NULL;
1967 cjpeg_source_ptr src;
1968 unsigned char *dstBuf = NULL;
1972 if (!filename || !width || align < 1 || !height || !pixelFormat ||
1973 *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF)
1974 _throwg("tjLoadImage(): Invalid argument");
1975 if ((align & (align - 1)) != 0)
1976 _throwg("tjLoadImage(): Alignment must be a power of 2");
1978 if ((handle = tjInitCompress()) == NULL) return NULL;
1979 this = (tjinstance *)handle;
1980 cinfo = &this->cinfo;
1982 if ((file = fopen(filename, "rb")) == NULL)
1983 _throwunix("tjLoadImage(): Cannot open input file");
1985 if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF)
1986 _throwunix("tjLoadImage(): Could not read input file")
1987 else if (tempc == EOF)
1988 _throwg("tjLoadImage(): Input file contains no data");
1990 if (setjmp(this->jerr.setjmp_buffer)) {
1991 /* If we get here, the JPEG code has signaled an error. */
1992 retval = -1; goto bailout;
1995 if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN;
1996 else cinfo->in_color_space = pf2cs[*pixelFormat];
1998 if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL)
1999 _throwg("tjLoadImage(): Could not initialize bitmap loader");
2000 invert = (flags & TJFLAG_BOTTOMUP) == 0;
2001 } else if (tempc == 'P') {
2002 if ((src = jinit_read_ppm(cinfo)) == NULL)
2003 _throwg("tjLoadImage(): Could not initialize bitmap loader");
2004 invert = (flags & TJFLAG_BOTTOMUP) != 0;
2006 _throwg("tjLoadImage(): Unsupported file type");
2008 src->input_file = file;
2009 (*src->start_input) (cinfo, src);
2010 (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
2012 *width = cinfo->image_width; *height = cinfo->image_height;
2013 *pixelFormat = cs2pf[cinfo->in_color_space];
2015 pitch = PAD((*width) * tjPixelSize[*pixelFormat], align);
2016 if ((dstBuf = (unsigned char *)malloc(pitch * (*height))) == NULL)
2017 _throwg("tjLoadImage(): Memory allocation failure");
2019 if (setjmp(this->jerr.setjmp_buffer)) {
2020 /* If we get here, the JPEG code has signaled an error. */
2021 retval = -1; goto bailout;
2024 while (cinfo->next_scanline < cinfo->image_height) {
2025 int i, nlines = (*src->get_pixel_rows) (cinfo, src);
2027 for (i = 0; i < nlines; i++) {
2028 unsigned char *dstptr;
2031 row = cinfo->next_scanline + i;
2032 if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch];
2033 else dstptr = &dstBuf[row * pitch];
2034 memcpy(dstptr, src->buffer[i], (*width) * tjPixelSize[*pixelFormat]);
2036 cinfo->next_scanline += nlines;
2039 (*src->finish_input) (cinfo, src);
2042 if (handle) tjDestroy(handle);
2043 if (file) fclose(file);
2044 if (retval < 0 && dstBuf) { free(dstBuf); dstBuf = NULL; }
2049 DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
2050 int width, int pitch, int height, int pixelFormat,
2054 tjhandle handle = NULL;
2056 j_decompress_ptr dinfo = NULL;
2062 if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 ||
2063 pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
2064 _throwg("tjSaveImage(): Invalid argument");
2066 if ((handle = tjInitDecompress()) == NULL)
2068 this = (tjinstance *)handle;
2069 dinfo = &this->dinfo;
2071 if ((file = fopen(filename, "wb")) == NULL)
2072 _throwunix("tjSaveImage(): Cannot open output file");
2074 if (setjmp(this->jerr.setjmp_buffer)) {
2075 /* If we get here, the JPEG code has signaled an error. */
2076 retval = -1; goto bailout;
2079 this->dinfo.out_color_space = pf2cs[pixelFormat];
2080 dinfo->image_width = width; dinfo->image_height = height;
2081 dinfo->global_state = DSTATE_READY;
2082 dinfo->scale_num = dinfo->scale_denom = 1;
2084 ptr = strrchr(filename, '.');
2085 if (ptr && !strcasecmp(ptr, ".bmp")) {
2086 if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL)
2087 _throwg("tjSaveImage(): Could not initialize bitmap writer");
2088 invert = (flags & TJFLAG_BOTTOMUP) == 0;
2090 if ((dst = jinit_write_ppm(dinfo)) == NULL)
2091 _throwg("tjSaveImage(): Could not initialize PPM writer");
2092 invert = (flags & TJFLAG_BOTTOMUP) != 0;
2095 dst->output_file = file;
2096 (*dst->start_output) (dinfo, dst);
2097 (*dinfo->mem->realize_virt_arrays) ((j_common_ptr)dinfo);
2099 if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
2101 while (dinfo->output_scanline < dinfo->output_height) {
2102 unsigned char *rowptr;
2105 rowptr = &buffer[(height - dinfo->output_scanline - 1) * pitch];
2107 rowptr = &buffer[dinfo->output_scanline * pitch];
2108 memcpy(dst->buffer[0], rowptr, width * tjPixelSize[pixelFormat]);
2109 (*dst->put_pixel_rows) (dinfo, dst, 1);
2110 dinfo->output_scanline++;
2113 (*dst->finish_output) (dinfo, dst);
2116 if (handle) tjDestroy(handle);
2117 if (file) fclose(file);