2 * Copyright (C)2009-2012, 2014 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
35 #define JPEG_INTERNALS
39 #include "./turbojpeg.h"
43 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
44 unsigned long *, boolean);
45 extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
47 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
50 /* Error handling (based on example in example.c) */
52 static char errStr[JMSG_LENGTH_MAX]="No error";
56 struct jpeg_error_mgr pub;
57 jmp_buf setjmp_buffer;
59 typedef struct my_error_mgr *my_error_ptr;
61 static void my_error_exit(j_common_ptr cinfo)
63 my_error_ptr myerr=(my_error_ptr)cinfo->err;
64 (*cinfo->err->output_message)(cinfo);
65 longjmp(myerr->setjmp_buffer, 1);
68 /* Based on output_message() in jerror.c */
70 static void my_output_message(j_common_ptr cinfo)
72 (*cinfo->err->format_message)(cinfo, errStr);
76 /* Global structures, macros, etc. */
78 enum {COMPRESS=1, DECOMPRESS=2};
80 typedef struct _tjinstance
82 struct jpeg_compress_struct cinfo;
83 struct jpeg_decompress_struct dinfo;
84 struct my_error_mgr jerr;
88 static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
90 static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
92 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
93 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
97 static const tjscalingfactor sf[NUMSF]={
116 #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
117 retval=-1; goto bailout;}
118 #define getinstance(handle) tjinstance *this=(tjinstance *)handle; \
119 j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \
120 if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
122 cinfo=&this->cinfo; dinfo=&this->dinfo;
124 static int getPixelFormat(int pixelSize, int flags)
126 if(pixelSize==1) return TJPF_GRAY;
129 if(flags&TJ_BGR) return TJPF_BGR;
130 else return TJPF_RGB;
134 if(flags&TJ_ALPHAFIRST)
136 if(flags&TJ_BGR) return TJPF_XBGR;
137 else return TJPF_XRGB;
141 if(flags&TJ_BGR) return TJPF_BGRX;
142 else return TJPF_RGBX;
148 static int setCompDefaults(struct jpeg_compress_struct *cinfo,
149 int pixelFormat, int subsamp, int jpegQual, int flags)
156 cinfo->in_color_space=JCS_GRAYSCALE; break;
157 #if JCS_EXTENSIONS==1
159 cinfo->in_color_space=JCS_EXT_RGB; break;
161 cinfo->in_color_space=JCS_EXT_BGR; break;
164 cinfo->in_color_space=JCS_EXT_RGBX; break;
167 cinfo->in_color_space=JCS_EXT_BGRX; break;
170 cinfo->in_color_space=JCS_EXT_XRGB; break;
173 cinfo->in_color_space=JCS_EXT_XBGR; break;
185 cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB;
190 cinfo->input_components=tjPixelSize[pixelFormat];
191 jpeg_set_defaults(cinfo);
194 jpeg_set_quality(cinfo, jpegQual, TRUE);
195 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
196 else cinfo->dct_method=JDCT_FASTEST;
198 if(subsamp==TJSAMP_GRAY)
199 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
201 jpeg_set_colorspace(cinfo, JCS_YCbCr);
203 cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
204 cinfo->comp_info[1].h_samp_factor=1;
205 cinfo->comp_info[2].h_samp_factor=1;
206 cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
207 cinfo->comp_info[1].v_samp_factor=1;
208 cinfo->comp_info[2].v_samp_factor=1;
213 static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
214 int pixelFormat, int flags)
221 dinfo->out_color_space=JCS_GRAYSCALE; break;
222 #if JCS_EXTENSIONS==1
224 dinfo->out_color_space=JCS_EXT_RGB; break;
226 dinfo->out_color_space=JCS_EXT_BGR; break;
228 dinfo->out_color_space=JCS_EXT_RGBX; break;
230 dinfo->out_color_space=JCS_EXT_BGRX; break;
232 dinfo->out_color_space=JCS_EXT_XRGB; break;
234 dinfo->out_color_space=JCS_EXT_XBGR; break;
235 #if JCS_ALPHA_EXTENSIONS==1
237 dinfo->out_color_space=JCS_EXT_RGBA; break;
239 dinfo->out_color_space=JCS_EXT_BGRA; break;
241 dinfo->out_color_space=JCS_EXT_ARGB; break;
243 dinfo->out_color_space=JCS_EXT_ABGR; break;
256 dinfo->out_color_space=JCS_RGB; break;
259 _throw("Unsupported pixel format");
262 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
269 static int getSubsamp(j_decompress_ptr dinfo)
272 for(i=0; i<NUMSUBOPT; i++)
274 if(dinfo->num_components==pixelsize[i])
276 if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
277 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
280 for(k=1; k<dinfo->num_components; k++)
282 if(dinfo->comp_info[k].h_samp_factor==1
283 && dinfo->comp_info[k].v_samp_factor==1)
286 if(match==dinfo->num_components-1)
297 #ifndef JCS_EXTENSIONS
299 /* Conversion functions to emulate the colorspace extensions. This allows the
300 TurboJPEG wrapper to be used with libjpeg */
302 #define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \
303 int rowPad=pitch-width*PS; \
306 unsigned char *endOfRow=src+width*PS; \
307 while(src<endOfRow) \
309 dst[RGB_RED]=src[ROFFSET]; \
310 dst[RGB_GREEN]=src[GOFFSET]; \
311 dst[RGB_BLUE]=src[BOFFSET]; \
312 dst+=RGB_PIXELSIZE; src+=PS; \
318 static unsigned char *toRGB(unsigned char *src, int width, int pitch,
319 int height, int pixelFormat, unsigned char *dst)
321 unsigned char *retval=src;
325 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
326 retval=dst; TORGB(3, 0, 1, 2);
330 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
331 retval=dst; TORGB(3, 2, 1, 0);
336 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
337 retval=dst; TORGB(4, 0, 1, 2);
342 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
343 retval=dst; TORGB(4, 2, 1, 0);
348 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
349 retval=dst; TORGB(4, 1, 2, 3);
354 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
355 retval=dst; TORGB(4, 3, 2, 1);
362 #define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \
363 int rowPad=pitch-width*PS; \
366 unsigned char *endOfRow=dst+width*PS; \
367 while(dst<endOfRow) \
369 dst[ROFFSET]=src[RGB_RED]; \
370 dst[GOFFSET]=src[RGB_GREEN]; \
371 dst[BOFFSET]=src[RGB_BLUE]; \
373 dst+=PS; src+=RGB_PIXELSIZE; \
379 static void fromRGB(unsigned char *src, unsigned char *dst, int width,
380 int pitch, int height, int pixelFormat)
385 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
386 FROMRGB(3, 0, 1, 2,);
390 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
391 FROMRGB(3, 2, 1, 0,);
395 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
396 FROMRGB(4, 0, 1, 2,);
400 #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
401 FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
405 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
406 FROMRGB(4, 2, 1, 0,);
410 #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
411 FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return;
415 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
416 FROMRGB(4, 1, 2, 3,); return;
420 #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
421 FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return;
425 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
426 FROMRGB(4, 3, 2, 1,); return;
430 #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
431 FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return;
440 /* General API functions */
442 DLLEXPORT char* DLLCALL tjGetErrorStr(void)
448 DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
451 if(setjmp(this->jerr.setjmp_buffer)) return -1;
452 if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
453 if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
459 /* These are exposed mainly because Windows can't malloc() and free() across
460 DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
461 with turbojpeg.dll for compatibility reasons. However, these functions
462 can potentially be used for other purposes by different implementations. */
464 DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
470 DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
472 return (unsigned char *)malloc(bytes);
478 static tjhandle _tjInitCompress(tjinstance *this)
480 unsigned char buffer[1], *buf=buffer; unsigned long size=1;
482 /* This is also straight out of example.c */
483 this->cinfo.err=jpeg_std_error(&this->jerr.pub);
484 this->jerr.pub.error_exit=my_error_exit;
485 this->jerr.pub.output_message=my_output_message;
487 if(setjmp(this->jerr.setjmp_buffer))
489 /* If we get here, the JPEG code has signaled an error. */
490 if(this) free(this); return NULL;
493 jpeg_create_compress(&this->cinfo);
494 /* Make an initial call so it will create the destination manager */
495 jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
497 this->init|=COMPRESS;
498 return (tjhandle)this;
501 DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
503 tjinstance *this=NULL;
504 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
506 snprintf(errStr, JMSG_LENGTH_MAX,
507 "tjInitCompress(): Memory allocation failure");
510 MEMZERO(this, sizeof(tjinstance));
511 return _tjInitCompress(this);
515 DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
518 unsigned long retval=0; int mcuw, mcuh, chromasf;
519 if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
520 _throw("tjBufSize(): Invalid argument");
522 /* This allows for rare corner cases in which a JPEG image can actually be
523 larger than the uncompressed input (we wouldn't mention it if it hadn't
525 mcuw=tjMCUWidth[jpegSubsamp];
526 mcuh=tjMCUHeight[jpegSubsamp];
527 chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
528 retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
534 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
536 unsigned long retval=0;
537 if(width<1 || height<1)
538 _throw("TJBUFSIZE(): Invalid argument");
540 /* This allows for rare corner cases in which a JPEG image can actually be
541 larger than the uncompressed input (we wouldn't mention it if it hadn't
543 retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
550 DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
553 unsigned long retval=0;
555 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
556 _throw("tjBufSizeYUV(): Invalid argument");
557 pw=PAD(width, tjMCUWidth[subsamp]/8);
558 ph=PAD(height, tjMCUHeight[subsamp]/8);
559 cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp];
560 retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2);
567 DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
570 return tjBufSizeYUV(width, height, subsamp);
574 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
575 int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
576 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
578 int i, retval=0, alloc=1; JSAMPROW *row_pointer=NULL;
579 #ifndef JCS_EXTENSIONS
580 unsigned char *rgbBuf=NULL;
584 if((this->init&COMPRESS)==0)
585 _throw("tjCompress2(): Instance has not been initialized for compression");
587 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
588 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
589 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
590 _throw("tjCompress2(): Invalid argument");
592 if(setjmp(this->jerr.setjmp_buffer))
594 /* If we get here, the JPEG code has signaled an error. */
599 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
601 #ifndef JCS_EXTENSIONS
602 if(pixelFormat!=TJPF_GRAY)
604 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
605 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
606 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
607 pitch=width*RGB_PIXELSIZE;
611 cinfo->image_width=width;
612 cinfo->image_height=height;
614 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
615 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
616 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
618 if(flags&TJFLAG_NOREALLOC)
620 alloc=0; *jpegSize=tjBufSize(width, height, jpegSubsamp);
622 jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
623 if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
626 jpeg_start_compress(cinfo, TRUE);
627 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
628 _throw("tjCompress2(): Memory allocation failure");
629 for(i=0; i<height; i++)
631 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
632 else row_pointer[i]=&srcBuf[i*pitch];
634 while(cinfo->next_scanline<cinfo->image_height)
636 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
637 cinfo->image_height-cinfo->next_scanline);
639 jpeg_finish_compress(cinfo);
642 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
643 #ifndef JCS_EXTENSIONS
644 if(rgbBuf) free(rgbBuf);
646 if(row_pointer) free(row_pointer);
650 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
651 int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
652 unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
654 int retval=0; unsigned long size;
657 size=tjBufSizeYUV(width, height, jpegSubsamp);
658 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
659 getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
663 retval=tjCompress2(handle, srcBuf, width, pitch, height,
664 getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
665 flags|TJFLAG_NOREALLOC);
672 DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
673 int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
674 int subsamp, int flags)
676 int i, retval=0; JSAMPROW *row_pointer=NULL;
677 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
678 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
679 JSAMPROW *outbuf[MAX_COMPONENTS];
680 int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
682 unsigned long yuvsize=0;
683 jpeg_component_info *compptr;
684 #ifndef JCS_EXTENSIONS
685 unsigned char *rgbBuf=NULL;
690 for(i=0; i<MAX_COMPONENTS; i++)
692 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
693 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
696 if((this->init&COMPRESS)==0)
697 _throw("tjEncodeYUV2(): Instance has not been initialized for compression");
699 if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
700 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
701 || subsamp>=NUMSUBOPT)
702 _throw("tjEncodeYUV2(): Invalid argument");
704 if(setjmp(this->jerr.setjmp_buffer))
706 /* If we get here, the JPEG code has signaled an error. */
711 if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
713 #ifndef JCS_EXTENSIONS
714 if(pixelFormat!=TJPF_GRAY)
716 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
717 if(!rgbBuf) _throw("tjEncodeYUV2(): Memory allocation failure");
718 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
719 pitch=width*RGB_PIXELSIZE;
723 cinfo->image_width=width;
724 cinfo->image_height=height;
726 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
727 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
728 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
730 yuvsize=tjBufSizeYUV(width, height, subsamp);
731 if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
733 /* Execute only the parts of jpeg_start_compress() that we need. If we
734 were to call the whole jpeg_start_compress() function, then it would try
735 to write the file headers, which could overflow the output buffer if the
736 YUV image were very small. */
737 if(cinfo->global_state!=CSTATE_START)
738 _throw("tjEncodeYUV3(): libjpeg API is in the wrong state");
739 (*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
740 jinit_c_master_control(cinfo, FALSE);
741 jinit_color_converter(cinfo);
742 jinit_downsampler(cinfo);
743 (*cinfo->cconvert->start_pass)(cinfo);
745 pw=PAD(width, cinfo->max_h_samp_factor);
746 ph=PAD(height, cinfo->max_v_samp_factor);
748 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
749 _throw("tjEncodeYUV2(): Memory allocation failure");
750 for(i=0; i<height; i++)
752 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
753 else row_pointer[i]=&srcBuf[i*pitch];
756 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
758 for(i=0; i<cinfo->num_components; i++)
760 compptr=&cinfo->comp_info[i];
761 _tmpbuf[i]=(JSAMPLE *)malloc(
762 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
763 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
764 if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
765 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
766 if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
767 for(row=0; row<cinfo->max_v_samp_factor; row++)
769 unsigned char *_tmpbuf_aligned=
770 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
771 tmpbuf[i][row]=&_tmpbuf_aligned[
772 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
773 /compptr->h_samp_factor, 16) * row];
775 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
776 * compptr->v_samp_factor + 16);
777 if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
778 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
779 if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
780 for(row=0; row<compptr->v_samp_factor; row++)
782 unsigned char *_tmpbuf2_aligned=
783 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
784 tmpbuf2[i][row]=&_tmpbuf2_aligned[
785 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
787 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
788 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
789 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
790 if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
791 for(row=0; row<ch[i]; row++)
797 if(yuvsize!=(unsigned long)(ptr-dstBuf))
798 _throw("tjEncodeYUV2(): Generated image is not the correct size");
800 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
802 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
803 cinfo->max_v_samp_factor);
804 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
805 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
806 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
807 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
808 compptr->v_samp_factor, cw[i]);
810 cinfo->next_scanline+=height;
811 jpeg_abort_compress(cinfo);
814 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
815 #ifndef JCS_EXTENSIONS
816 if(rgbBuf) free(rgbBuf);
818 if(row_pointer) free(row_pointer);
819 for(i=0; i<MAX_COMPONENTS; i++)
821 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
822 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
823 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
824 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
825 if(outbuf[i]!=NULL) free(outbuf[i]);
830 DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
831 int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
832 int subsamp, int flags)
834 return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
835 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
841 static tjhandle _tjInitDecompress(tjinstance *this)
843 unsigned char buffer[1];
845 /* This is also straight out of example.c */
846 this->dinfo.err=jpeg_std_error(&this->jerr.pub);
847 this->jerr.pub.error_exit=my_error_exit;
848 this->jerr.pub.output_message=my_output_message;
850 if(setjmp(this->jerr.setjmp_buffer))
852 /* If we get here, the JPEG code has signaled an error. */
853 if(this) free(this); return NULL;
856 jpeg_create_decompress(&this->dinfo);
857 /* Make an initial call so it will create the source manager */
858 jpeg_mem_src_tj(&this->dinfo, buffer, 1);
860 this->init|=DECOMPRESS;
861 return (tjhandle)this;
864 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
867 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
869 snprintf(errStr, JMSG_LENGTH_MAX,
870 "tjInitDecompress(): Memory allocation failure");
873 MEMZERO(this, sizeof(tjinstance));
874 return _tjInitDecompress(this);
878 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
879 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
885 if((this->init&DECOMPRESS)==0)
886 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
888 if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
889 || jpegSubsamp==NULL)
890 _throw("tjDecompressHeader2(): Invalid argument");
892 if(setjmp(this->jerr.setjmp_buffer))
894 /* If we get here, the JPEG code has signaled an error. */
898 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
899 jpeg_read_header(dinfo, TRUE);
901 *width=dinfo->image_width;
902 *height=dinfo->image_height;
903 *jpegSubsamp=getSubsamp(dinfo);
905 jpeg_abort_decompress(dinfo);
908 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
909 if(*width<1 || *height<1)
910 _throw("tjDecompressHeader2(): Invalid data returned in header");
916 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
917 unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
920 return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
925 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
927 if(numscalingfactors==NULL)
929 snprintf(errStr, JMSG_LENGTH_MAX,
930 "tjGetScalingFactors(): Invalid argument");
934 *numscalingfactors=NUMSF;
935 return (tjscalingfactor *)sf;
939 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
940 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
941 int height, int pixelFormat, int flags)
943 int i, retval=0; JSAMPROW *row_pointer=NULL;
944 int jpegwidth, jpegheight, scaledw, scaledh;
945 #ifndef JCS_EXTENSIONS
946 unsigned char *rgbBuf=NULL;
947 unsigned char *_dstBuf=NULL; int _pitch=0;
951 if((this->init&DECOMPRESS)==0)
952 _throw("tjDecompress2(): Instance has not been initialized for decompression");
954 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
955 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
956 _throw("tjDecompress2(): Invalid argument");
958 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
959 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
960 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
962 if(setjmp(this->jerr.setjmp_buffer))
964 /* If we get here, the JPEG code has signaled an error. */
969 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
970 jpeg_read_header(dinfo, TRUE);
971 if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
973 retval=-1; goto bailout;
976 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
978 jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
979 if(width==0) width=jpegwidth;
980 if(height==0) height=jpegheight;
981 for(i=0; i<NUMSF; i++)
983 scaledw=TJSCALED(jpegwidth, sf[i]);
984 scaledh=TJSCALED(jpegheight, sf[i]);
985 if(scaledw<=width && scaledh<=height)
988 if(scaledw>width || scaledh>height)
989 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
990 width=scaledw; height=scaledh;
991 dinfo->scale_num=sf[i].num;
992 dinfo->scale_denom=sf[i].denom;
994 jpeg_start_decompress(dinfo);
995 if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
997 #ifndef JCS_EXTENSIONS
998 if(pixelFormat!=TJPF_GRAY &&
999 (RGB_RED!=tjRedOffset[pixelFormat] ||
1000 RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1001 RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1002 RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1004 rgbBuf=(unsigned char *)malloc(width*height*3);
1005 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1006 _pitch=pitch; pitch=width*3;
1007 _dstBuf=dstBuf; dstBuf=rgbBuf;
1011 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1012 *dinfo->output_height))==NULL)
1013 _throw("tjDecompress2(): Memory allocation failure");
1014 for(i=0; i<(int)dinfo->output_height; i++)
1016 if(flags&TJFLAG_BOTTOMUP)
1017 row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1018 else row_pointer[i]=&dstBuf[i*pitch];
1020 while(dinfo->output_scanline<dinfo->output_height)
1022 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1023 dinfo->output_height-dinfo->output_scanline);
1025 jpeg_finish_decompress(dinfo);
1027 #ifndef JCS_EXTENSIONS
1028 fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1032 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1033 #ifndef JCS_EXTENSIONS
1034 if(rgbBuf) free(rgbBuf);
1036 if(row_pointer) free(row_pointer);
1040 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1041 unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1042 int height, int pixelSize, int flags)
1045 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1047 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1048 height, getPixelFormat(pixelSize, flags), flags);
1052 DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1053 unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1056 int i, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS];
1057 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1058 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1059 JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
1061 getinstance(handle);
1063 for(i=0; i<MAX_COMPONENTS; i++)
1065 tmpbuf[i]=NULL; outbuf[i]=NULL;
1068 if((this->init&DECOMPRESS)==0)
1069 _throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
1071 if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
1072 _throw("tjDecompressToYUV(): Invalid argument");
1074 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1075 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1076 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1078 if(setjmp(this->jerr.setjmp_buffer))
1080 /* If we get here, the JPEG code has signaled an error. */
1085 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1086 jpeg_read_header(dinfo, TRUE);
1088 for(i=0; i<dinfo->num_components; i++)
1090 jpeg_component_info *compptr=&dinfo->comp_info[i];
1092 iw[i]=compptr->width_in_blocks*DCTSIZE;
1093 ih=compptr->height_in_blocks*DCTSIZE;
1094 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
1095 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
1096 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
1097 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
1098 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
1099 th[i]=compptr->v_samp_factor*DCTSIZE;
1100 tmpbufsize+=iw[i]*th[i];
1101 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
1102 _throw("tjDecompressToYUV(): Memory allocation failure");
1103 for(row=0; row<ch[i]; row++)
1111 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1112 _throw("tjDecompressToYUV(): Memory allocation failure");
1114 for(i=0; i<dinfo->num_components; i++)
1116 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1117 _throw("tjDecompressToYUV(): Memory allocation failure");
1118 for(row=0; row<th[i]; row++)
1126 if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1127 if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
1128 dinfo->raw_data_out=TRUE;
1130 jpeg_start_decompress(dinfo);
1131 for(row=0; row<(int)dinfo->output_height;
1132 row+=dinfo->max_v_samp_factor*DCTSIZE)
1134 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1135 int crow[MAX_COMPONENTS];
1136 for(i=0; i<dinfo->num_components; i++)
1138 jpeg_component_info *compptr=&dinfo->comp_info[i];
1139 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1140 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1141 else yuvptr[i]=&outbuf[i][crow[i]];
1143 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
1147 for(i=0; i<dinfo->num_components; i++)
1149 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
1151 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
1156 jpeg_finish_decompress(dinfo);
1159 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1160 for(i=0; i<MAX_COMPONENTS; i++)
1162 if(tmpbuf[i]) free(tmpbuf[i]);
1163 if(outbuf[i]) free(outbuf[i]);
1165 if(_tmpbuf) free(_tmpbuf);
1172 DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1174 tjinstance *this=NULL; tjhandle handle=NULL;
1175 if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1177 snprintf(errStr, JMSG_LENGTH_MAX,
1178 "tjInitTransform(): Memory allocation failure");
1181 MEMZERO(this, sizeof(tjinstance));
1182 handle=_tjInitCompress(this);
1183 if(!handle) return NULL;
1184 handle=_tjInitDecompress(this);
1189 DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1190 unsigned long jpegSize, int n, unsigned char **dstBufs,
1191 unsigned long *dstSizes, tjtransform *t, int flags)
1193 jpeg_transform_info *xinfo=NULL;
1194 jvirt_barray_ptr *srccoefs, *dstcoefs;
1195 int retval=0, i, jpegSubsamp;
1197 getinstance(handle);
1198 if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
1199 _throw("tjTransform(): Instance has not been initialized for transformation");
1201 if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1202 || t==NULL || flags<0)
1203 _throw("tjTransform(): Invalid argument");
1205 if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1206 else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1207 else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1209 if(setjmp(this->jerr.setjmp_buffer))
1211 /* If we get here, the JPEG code has signaled an error. */
1216 jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1218 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1220 _throw("tjTransform(): Memory allocation failure");
1221 MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
1225 xinfo[i].transform=xformtypes[t[i].op];
1226 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1227 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1228 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1229 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1230 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
1231 else xinfo[i].slow_hflip=0;
1235 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
1236 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
1239 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
1241 else xinfo[i].crop_width=JCROP_UNSET;
1244 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
1246 else xinfo[i].crop_height=JCROP_UNSET;
1250 jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1251 jpeg_read_header(dinfo, TRUE);
1252 jpegSubsamp=getSubsamp(dinfo);
1254 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
1258 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
1259 _throw("tjTransform(): Transform is not perfect");
1263 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1264 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1266 snprintf(errStr, JMSG_LENGTH_MAX,
1267 "To crop this JPEG image, x must be a multiple of %d\n"
1268 "and y must be a multiple of %d.\n",
1269 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1270 retval=-1; goto bailout;
1275 srccoefs=jpeg_read_coefficients(dinfo);
1282 w=dinfo->image_width; h=dinfo->image_height;
1286 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
1288 if(flags&TJFLAG_NOREALLOC)
1290 alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
1292 if(!(t[i].options&TJXOPT_NOOUTPUT))
1293 jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
1294 jpeg_copy_critical_parameters(dinfo, cinfo);
1295 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
1297 if(!(t[i].options&TJXOPT_NOOUTPUT))
1299 jpeg_write_coefficients(cinfo, dstcoefs);
1300 jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1302 else jinit_c_master_control(cinfo, TRUE);
1303 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
1305 if(t[i].customFilter)
1307 int ci, y; JDIMENSION by;
1308 for(ci=0; ci<cinfo->num_components; ci++)
1310 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1311 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1313 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1314 compptr->height_in_blocks*DCTSIZE};
1315 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1317 JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1318 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1320 for(y=0; y<compptr->v_samp_factor; y++)
1322 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
1324 _throw("tjTransform(): Error in custom filter");
1325 arrayRegion.y+=DCTSIZE;
1330 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
1333 jpeg_finish_decompress(dinfo);
1336 if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1337 if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1338 if(xinfo) free(xinfo);