diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/turbojpeg.c | 944 | ||||
-rw-r--r-- | common/turbojpeg.h | 680 |
2 files changed, 1162 insertions, 462 deletions
diff --git a/common/turbojpeg.c b/common/turbojpeg.c index 497ec59..c145338 100644 --- a/common/turbojpeg.c +++ b/common/turbojpeg.c @@ -1,112 +1,517 @@ -/* Copyright (C)2004 Landmark Graphics Corporation - * Copyright (C)2005 Sun Microsystems, Inc. - * Copyright (C)2009-2011 D. R. Commander +/* + * Copyright (C)2009-2012 D. R. Commander. All Rights Reserved. * - * This library is free software and may be redistributed and/or modified under - * the terms of the wxWindows Library License, Version 3.1 or (at your option) - * any later version. The full license is in the LICENSE.txt file included - * with this distribution. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * wxWindows Library License for more details. + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the libjpeg-turbo Project nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ -// This implements a JPEG compressor/decompressor using the libjpeg API +/* TurboJPEG/OSS: this implements the TurboJPEG API using libjpeg-turbo */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <jpeglib.h> #include <jerror.h> +#ifndef JCS_EXTENSIONS +#define JPEG_INTERNALS +#include <jmorecfg.h> +#endif #include <setjmp.h> #include "./turbojpeg.h" +#define PAD(v, p) ((v+(p)-1)&(~((p)-1))) #define CSTATE_START 100 #define DSTATE_START 200 +#define MEMZERO(ptr, size) memset(ptr, 0, size) + +#ifndef min + #define min(a,b) ((a)<(b)?(a):(b)) +#endif + +#ifndef max + #define max(a,b) ((a)>(b)?(a):(b)) +#endif -// Error handling +/* Error handling (based on example in example.c) */ -static char lasterror[JMSG_LENGTH_MAX]="No error"; +static char errStr[JMSG_LENGTH_MAX]="No error"; -typedef struct _error_mgr +struct my_error_mgr { struct jpeg_error_mgr pub; - jmp_buf jb; -} error_mgr; + jmp_buf setjmp_buffer; +}; +typedef struct my_error_mgr *my_error_ptr; static void my_error_exit(j_common_ptr cinfo) { - error_mgr *myerr = (error_mgr *)cinfo->err; + my_error_ptr myerr=(my_error_ptr)cinfo->err; (*cinfo->err->output_message)(cinfo); - longjmp(myerr->jb, 1); + longjmp(myerr->setjmp_buffer, 1); } +/* Based on output_message() in jerror.c */ + static void my_output_message(j_common_ptr cinfo) { - (*cinfo->err->format_message)(cinfo, lasterror); + (*cinfo->err->format_message)(cinfo, errStr); } -// Global structures, macros, etc. +/* Global structures, macros, etc. */ + +enum {COMPRESS=1, DECOMPRESS=2}; -typedef struct _jpgstruct +typedef struct _tjinstance { struct jpeg_compress_struct cinfo; struct jpeg_decompress_struct dinfo; - struct jpeg_destination_mgr jdms; - struct jpeg_source_mgr jsms; - error_mgr jerr; - int initc, initd; -} jpgstruct; + struct jpeg_destination_mgr jdst; + struct jpeg_source_mgr jsrc; + struct my_error_mgr jerr; + int init; +} tjinstance; + +static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3}; + +#define NUMSF 4 +static const tjscalingfactor sf[NUMSF]={ + {1, 1}, + {1, 2}, + {1, 4}, + {1, 8} +}; + +#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \ + retval=-1; goto bailout;} +#define getinstance(handle) tjinstance *this=(tjinstance *)handle; \ + j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \ + if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \ + return -1;} \ + cinfo=&this->cinfo; dinfo=&this->dinfo; + +static int getPixelFormat(int pixelSize, int flags) +{ + if(pixelSize==1) return TJPF_GRAY; + if(pixelSize==3) + { + if(flags&TJ_BGR) return TJPF_BGR; + else return TJPF_RGB; + } + if(pixelSize==4) + { + if(flags&TJ_ALPHAFIRST) + { + if(flags&TJ_BGR) return TJPF_XBGR; + else return TJPF_XRGB; + } + else + { + if(flags&TJ_BGR) return TJPF_BGRX; + else return TJPF_RGBX; + } + } + return -1; +} + +static int setCompDefaults(struct jpeg_compress_struct *cinfo, + int pixelFormat, int subsamp, int jpegQual) +{ + int retval=0; + + switch(pixelFormat) + { + case TJPF_GRAY: + cinfo->in_color_space=JCS_GRAYSCALE; break; + #if JCS_EXTENSIONS==1 + case TJPF_RGB: + cinfo->in_color_space=JCS_EXT_RGB; break; + case TJPF_BGR: + cinfo->in_color_space=JCS_EXT_BGR; break; + case TJPF_RGBX: + case TJPF_RGBA: + cinfo->in_color_space=JCS_EXT_RGBX; break; + case TJPF_BGRX: + case TJPF_BGRA: + cinfo->in_color_space=JCS_EXT_BGRX; break; + case TJPF_XRGB: + case TJPF_ARGB: + cinfo->in_color_space=JCS_EXT_XRGB; break; + case TJPF_XBGR: + case TJPF_ABGR: + cinfo->in_color_space=JCS_EXT_XBGR; break; + #else + case TJPF_RGB: + case TJPF_BGR: + case TJPF_RGBX: + case TJPF_BGRX: + case TJPF_XRGB: + case TJPF_XBGR: + case TJPF_RGBA: + case TJPF_BGRA: + case TJPF_ARGB: + case TJPF_ABGR: + cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB; + break; + #endif + } + + cinfo->input_components=tjPixelSize[pixelFormat]; + jpeg_set_defaults(cinfo); + if(jpegQual>=0) + { + jpeg_set_quality(cinfo, jpegQual, TRUE); + if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW; + else cinfo->dct_method=JDCT_FASTEST; + } + if(subsamp==TJSAMP_GRAY) + jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); + else + jpeg_set_colorspace(cinfo, JCS_YCbCr); + + cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8; + cinfo->comp_info[1].h_samp_factor=1; + cinfo->comp_info[2].h_samp_factor=1; + cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8; + cinfo->comp_info[1].v_samp_factor=1; + cinfo->comp_info[2].v_samp_factor=1; + + return retval; +} + +static int setDecompDefaults(struct jpeg_decompress_struct *dinfo, + int pixelFormat) +{ + int retval=0; + + switch(pixelFormat) + { + case TJPF_GRAY: + dinfo->out_color_space=JCS_GRAYSCALE; break; + #if JCS_EXTENSIONS==1 + case TJPF_RGB: + dinfo->out_color_space=JCS_EXT_RGB; break; + case TJPF_BGR: + dinfo->out_color_space=JCS_EXT_BGR; break; + case TJPF_RGBX: + dinfo->out_color_space=JCS_EXT_RGBX; break; + case TJPF_BGRX: + dinfo->out_color_space=JCS_EXT_BGRX; break; + case TJPF_XRGB: + dinfo->out_color_space=JCS_EXT_XRGB; break; + case TJPF_XBGR: + dinfo->out_color_space=JCS_EXT_XBGR; break; + #if JCS_ALPHA_EXTENSIONS==1 + case TJPF_RGBA: + dinfo->out_color_space=JCS_EXT_RGBA; break; + case TJPF_BGRA: + dinfo->out_color_space=JCS_EXT_BGRA; break; + case TJPF_ARGB: + dinfo->out_color_space=JCS_EXT_ARGB; break; + case TJPF_ABGR: + dinfo->out_color_space=JCS_EXT_ABGR; break; + #endif + #else + case TJPF_RGB: + case TJPF_BGR: + case TJPF_RGBX: + case TJPF_BGRX: + case TJPF_XRGB: + case TJPF_XBGR: + case TJPF_RGBA: + case TJPF_BGRA: + case TJPF_ARGB: + case TJPF_ABGR: + dinfo->out_color_space=JCS_RGB; break; + #endif + default: + _throw("Unsupported pixel format"); + } + + bailout: + return retval; +} + + +static int getSubsamp(j_decompress_ptr dinfo) +{ + int retval=-1, i, k; + for(i=0; i<NUMSUBOPT; i++) + { + if(dinfo->num_components==pixelsize[i]) + { + if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8 + && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8) + { + int match=0; + for(k=1; k<dinfo->num_components; k++) + { + if(dinfo->comp_info[k].h_samp_factor==1 + && dinfo->comp_info[k].v_samp_factor==1) + match++; + } + if(match==dinfo->num_components-1) + { + retval=i; break; + } + } + } + } + return retval; +} + + +#ifndef JCS_EXTENSIONS + +/* Conversion functions to emulate the colorspace extensions. This allows the + TurboJPEG wrapper to be used with libjpeg */ + +#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) { \ + int rowPad=pitch-width*PS; \ + while(height--) \ + { \ + unsigned char *endOfRow=src+width*PS; \ + while(src<endOfRow) \ + { \ + dst[RGB_RED]=src[ROFFSET]; \ + dst[RGB_GREEN]=src[GOFFSET]; \ + dst[RGB_BLUE]=src[BOFFSET]; \ + dst+=RGB_PIXELSIZE; src+=PS; \ + } \ + src+=rowPad; \ + } \ +} + +static unsigned char *toRGB(unsigned char *src, int width, int pitch, + int height, int pixelFormat, unsigned char *dst) +{ + unsigned char *retval=src; + switch(pixelFormat) + { + case TJPF_RGB: + #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3 + retval=dst; TORGB(3, 0, 1, 2); + #endif + break; + case TJPF_BGR: + #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3 + retval=dst; TORGB(3, 2, 1, 0); + #endif + break; + case TJPF_RGBX: + case TJPF_RGBA: + #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4 + retval=dst; TORGB(4, 0, 1, 2); + #endif + break; + case TJPF_BGRX: + case TJPF_BGRA: + #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4 + retval=dst; TORGB(4, 2, 1, 0); + #endif + break; + case TJPF_XRGB: + case TJPF_ARGB: + #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4 + retval=dst; TORGB(4, 1, 2, 3); + #endif + break; + case TJPF_XBGR: + case TJPF_ABGR: + #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4 + retval=dst; TORGB(4, 3, 2, 1); + #endif + break; + } + return retval; +} -static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1}; -static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1}; -static const int pixelsize[NUMSUBOPT]={3, 3, 3, 1}; +#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) { \ + int rowPad=pitch-width*PS; \ + while(height--) \ + { \ + unsigned char *endOfRow=dst+width*PS; \ + while(dst<endOfRow) \ + { \ + dst[ROFFSET]=src[RGB_RED]; \ + dst[GOFFSET]=src[RGB_GREEN]; \ + dst[BOFFSET]=src[RGB_BLUE]; \ + SETALPHA \ + dst+=PS; src+=RGB_PIXELSIZE; \ + } \ + dst+=rowPad; \ + } \ +} -#define _throw(c) {sprintf(lasterror, "%s", c); retval=-1; goto bailout;} -#define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \ - if(!j) {sprintf(lasterror, "Invalid handle"); return -1;} +static void fromRGB(unsigned char *src, unsigned char *dst, int width, + int pitch, int height, int pixelFormat) +{ + switch(pixelFormat) + { + case TJPF_RGB: + #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3 + FROMRGB(3, 0, 1, 2,); + #endif + break; + case TJPF_BGR: + #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3 + FROMRGB(3, 2, 1, 0,); + #endif + break; + case TJPF_RGBX: + #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4 + FROMRGB(4, 0, 1, 2,); + #endif + break; + case TJPF_RGBA: + #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4 + FROMRGB(4, 0, 1, 2, dst[3]=0xFF;); + #endif + break; + case TJPF_BGRX: + #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4 + FROMRGB(4, 2, 1, 0,); + #endif + break; + case TJPF_BGRA: + #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4 + FROMRGB(4, 2, 1, 0, dst[3]=0xFF;); return; + #endif + break; + case TJPF_XRGB: + #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4 + FROMRGB(4, 1, 2, 3,); return; + #endif + break; + case TJPF_ARGB: + #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4 + FROMRGB(4, 1, 2, 3, dst[0]=0xFF;); return; + #endif + break; + case TJPF_XBGR: + #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4 + FROMRGB(4, 3, 2, 1,); return; + #endif + break; + case TJPF_ABGR: + #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4 + FROMRGB(4, 3, 2, 1, dst[0]=0xFF;); return; + #endif + break; + } +} +#endif -// CO -static boolean empty_output_buffer(struct jpeg_compress_struct *cinfo) +/* General API functions */ + +DLLEXPORT char* DLLCALL tjGetErrorStr(void) +{ + return errStr; +} + + +DLLEXPORT int DLLCALL tjDestroy(tjhandle handle) +{ + getinstance(handle); + if(setjmp(this->jerr.setjmp_buffer)) return -1; + if(this->init&COMPRESS) jpeg_destroy_compress(cinfo); + if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo); + free(this); + return 0; +} + + +/* Compressor */ + +static boolean empty_output_buffer(j_compress_ptr cinfo) { ERREXIT(cinfo, JERR_BUFFER_SIZE); return TRUE; } -static void destination_noop(struct jpeg_compress_struct *cinfo) +static void dst_noop(j_compress_ptr cinfo) { } +static tjhandle _tjInitCompress(tjinstance *this) +{ + /* This is also straight out of example.c */ + this->cinfo.err=jpeg_std_error(&this->jerr.pub); + this->jerr.pub.error_exit=my_error_exit; + this->jerr.pub.output_message=my_output_message; + + if(setjmp(this->jerr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. */ + if(this) free(this); return NULL; + } + + jpeg_create_compress(&this->cinfo); + this->cinfo.dest=&this->jdst; + this->jdst.init_destination=dst_noop; + this->jdst.empty_output_buffer=empty_output_buffer; + this->jdst.term_destination=dst_noop; + + this->init|=COMPRESS; + return (tjhandle)this; +} + DLLEXPORT tjhandle DLLCALL tjInitCompress(void) { - jpgstruct *j=NULL; - if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL) - {sprintf(lasterror, "Memory allocation failure"); return NULL;} - memset(j, 0, sizeof(jpgstruct)); - j->cinfo.err=jpeg_std_error(&j->jerr.pub); - j->jerr.pub.error_exit=my_error_exit; - j->jerr.pub.output_message=my_output_message; - - if(setjmp(j->jerr.jb)) - { // this will execute if LIBJPEG has an error - if(j) free(j); return NULL; + tjinstance *this=NULL; + if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL) + { + snprintf(errStr, JMSG_LENGTH_MAX, + "tjInitCompress(): Memory allocation failure"); + return NULL; } + MEMZERO(this, sizeof(tjinstance)); + return _tjInitCompress(this); +} + - jpeg_create_compress(&j->cinfo); - j->cinfo.dest=&j->jdms; - j->jdms.init_destination=destination_noop; - j->jdms.empty_output_buffer=empty_output_buffer; - j->jdms.term_destination=destination_noop; +DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height, + int jpegSubsamp) +{ + unsigned long retval=0; int mcuw, mcuh, chromasf; + if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT) + _throw("tjBufSize(): Invalid argument"); - j->initc=1; - return (tjhandle)j; + // This allows for rare corner cases in which a JPEG image can actually be + // larger than the uncompressed input (we wouldn't mention it if it hadn't + // happened before.) + mcuw=tjMCUWidth[jpegSubsamp]; + mcuh=tjMCUHeight[jpegSubsamp]; + chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh); + retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048; + + bailout: + return retval; } @@ -114,311 +519,332 @@ DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height) { unsigned long retval=0; if(width<1 || height<1) - _throw("Invalid argument in TJBUFSIZE()"); + _throw("TJBUFSIZE(): Invalid argument"); // This allows for rare corner cases in which a JPEG image can actually be // larger than the uncompressed input (we wouldn't mention it if it hadn't // happened before.) - retval=((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048; + retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048; bailout: return retval; } -DLLEXPORT int DLLCALL tjCompress(tjhandle h, - unsigned char *srcbuf, int width, int pitch, int height, int ps, - unsigned char *dstbuf, unsigned long *size, - int jpegsub, int qual, int flags) +DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, + int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, + unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) { int i, retval=0; JSAMPROW *row_pointer=NULL; - - checkhandle(h); - - if(srcbuf==NULL || width<=0 || pitch<0 || height<=0 - || dstbuf==NULL || size==NULL - || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100) - _throw("Invalid argument in tjCompress()"); - if(ps!=3 && ps!=4 && ps!=1) - _throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input"); - if(!j->initc) _throw("Instance has not been initialized for compression"); - - if(pitch==0) pitch=width*ps; - - j->cinfo.image_width = width; - j->cinfo.image_height = height; - j->cinfo.input_components = ps; - - if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE; - #if JCS_EXTENSIONS==1 - else j->cinfo.in_color_space = JCS_EXT_RGB; - if(ps==3 && (flags&TJ_BGR)) - j->cinfo.in_color_space = JCS_EXT_BGR; - else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) - j->cinfo.in_color_space = JCS_EXT_RGBX; - else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) - j->cinfo.in_color_space = JCS_EXT_BGRX; - else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) - j->cinfo.in_color_space = JCS_EXT_XBGR; - else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) - j->cinfo.in_color_space = JCS_EXT_XRGB; - #else - #error "TurboJPEG requires JPEG colorspace extensions" + #ifndef JCS_EXTENSIONS + unsigned char *rgbBuf=NULL; #endif - if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); - else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1"); - else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); + getinstance(handle) + if((this->init&COMPRESS)==0) + _throw("tjCompress2(): Instance has not been initialized for compression"); - if(setjmp(j->jerr.jb)) - { // this will execute if LIBJPEG has an error + if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0 + || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL + || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100) + _throw("tjCompress2(): Invalid argument"); + + if(setjmp(this->jerr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. */ retval=-1; goto bailout; } - jpeg_set_defaults(&j->cinfo); + if(pitch==0) pitch=width*tjPixelSize[pixelFormat]; - jpeg_set_quality(&j->cinfo, qual, TRUE); - if(jpegsub==TJ_GRAYSCALE) - jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE); - else - jpeg_set_colorspace(&j->cinfo, JCS_YCbCr); - if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW; - else j->cinfo.dct_method=JDCT_FASTEST; + #ifndef JCS_EXTENSIONS + if(pixelFormat!=TJPF_GRAY) + { + rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE); + if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure"); + srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf); + pitch=width*RGB_PIXELSIZE; + } + #endif + + cinfo->image_width=width; + cinfo->image_height=height; + + if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); + else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); + else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); - j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub]; - j->cinfo.comp_info[1].h_samp_factor=1; - j->cinfo.comp_info[2].h_samp_factor=1; - j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub]; - j->cinfo.comp_info[1].v_samp_factor=1; - j->cinfo.comp_info[2].v_samp_factor=1; + if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1) + return -1; - j->jdms.next_output_byte = dstbuf; - j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height); + this->jdst.next_output_byte=*jpegBuf; + this->jdst.free_in_buffer=tjBufSize(width, height, jpegSubsamp); - jpeg_start_compress(&j->cinfo, TRUE); + jpeg_start_compress(cinfo, TRUE); if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL) - _throw("Memory allocation failed in tjCompress()"); + _throw("tjCompress2(): Memory allocation failure"); for(i=0; i<height; i++) { - if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch]; - else row_pointer[i]= &srcbuf[i*pitch]; + if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch]; + else row_pointer[i]=&srcBuf[i*pitch]; } - while(j->cinfo.next_scanline<j->cinfo.image_height) + while(cinfo->next_scanline<cinfo->image_height) { - jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline], - j->cinfo.image_height-j->cinfo.next_scanline); + jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline], + cinfo->image_height-cinfo->next_scanline); } - jpeg_finish_compress(&j->cinfo); - *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height) - -(unsigned long)(j->jdms.free_in_buffer); + jpeg_finish_compress(cinfo); + *jpegSize=tjBufSize(width, height, jpegSubsamp) + -(unsigned long)(this->jdst.free_in_buffer); bailout: - if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo); + if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo); + #ifndef JCS_EXTENSIONS + if(rgbBuf && rgbBuf!=srcBuf) free(rgbBuf); + #endif if(row_pointer) free(row_pointer); return retval; } +DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf, + int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf, + unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) +{ + int retval=0; unsigned long size; + retval=tjCompress2(handle, srcBuf, width, pitch, height, + getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual, + flags); + *jpegSize=size; + return retval; +} + -// DEC +/* Decompressor */ -static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo) +static boolean fill_input_buffer(j_decompress_ptr dinfo) { ERREXIT(dinfo, JERR_BUFFER_SIZE); return TRUE; } -static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes) +static void skip_input_data(j_decompress_ptr dinfo, long num_bytes) { dinfo->src->next_input_byte += (size_t) num_bytes; dinfo->src->bytes_in_buffer -= (size_t) num_bytes; } -static void source_noop (struct jpeg_decompress_struct *dinfo) +static void src_noop(j_decompress_ptr dinfo) { } -DLLEXPORT tjhandle DLLCALL tjInitDecompress(void) +static tjhandle _tjInitDecompress(tjinstance *this) { - jpgstruct *j; - if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL) - {sprintf(lasterror, "Memory allocation failure"); return NULL;} - memset(j, 0, sizeof(jpgstruct)); - j->dinfo.err=jpeg_std_error(&j->jerr.pub); - j->jerr.pub.error_exit=my_error_exit; - j->jerr.pub.output_message=my_output_message; - - if(setjmp(j->jerr.jb)) - { // this will execute if LIBJPEG has an error - free(j); return NULL; + /* This is also straight out of example.c */ + this->dinfo.err=jpeg_std_error(&this->jerr.pub); + this->jerr.pub.error_exit=my_error_exit; + this->jerr.pub.output_message=my_output_message; + + if(setjmp(this->jerr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. */ + if(this) free(this); return NULL; } - jpeg_create_decompress(&j->dinfo); - j->dinfo.src=&j->jsms; - j->jsms.init_source=source_noop; - j->jsms.fill_input_buffer = fill_input_buffer; - j->jsms.skip_input_data = skip_input_data; - j->jsms.resync_to_restart = jpeg_resync_to_restart; - j->jsms.term_source = source_noop; + jpeg_create_decompress(&this->dinfo); + this->dinfo.src=&this->jsrc; + this->jsrc.init_source=src_noop; + this->jsrc.fill_input_buffer=fill_input_buffer; + this->jsrc.skip_input_data=skip_input_data; + this->jsrc.resync_to_restart=jpeg_resync_to_restart; + this->jsrc.term_source=src_noop; + + this->init|=DECOMPRESS; + return (tjhandle)this; +} - j->initd=1; - return (tjhandle)j; +DLLEXPORT tjhandle DLLCALL tjInitDecompress(void) +{ + tjinstance *this; + if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL) + { + snprintf(errStr, JMSG_LENGTH_MAX, + "tjInitDecompress(): Memory allocation failure"); + return NULL; + } + MEMZERO(this, sizeof(tjinstance)); + return _tjInitDecompress(this); } -DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle h, - unsigned char *srcbuf, unsigned long size, - int *width, int *height, int *jpegsub) +DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, + int *jpegSubsamp) { - int i, k, retval=0; + int retval=0; - checkhandle(h); + getinstance(handle); + if((this->init&DECOMPRESS)==0) + _throw("tjDecompressHeader2(): Instance has not been initialized for decompression"); - if(srcbuf==NULL || size<=0 || width==NULL || height==NULL || jpegsub==NULL) - _throw("Invalid argument in tjDecompressHeader2()"); - if(!j->initd) _throw("Instance has not been initialized for decompression"); + if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL + || jpegSubsamp==NULL) + _throw("tjDecompressHeader2(): Invalid argument"); - if(setjmp(j->jerr.jb)) - { // this will execute if LIBJPEG has an error + if(setjmp(this->jerr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. */ return -1; } - j->jsms.bytes_in_buffer = size; - j->jsms.next_input_byte = srcbuf; + this->jsrc.bytes_in_buffer=jpegSize; + this->jsrc.next_input_byte=jpegBuf; + jpeg_read_header(dinfo, TRUE); - jpeg_read_header(&j->dinfo, TRUE); + *width=dinfo->image_width; + *height=dinfo->image_height; + *jpegSubsamp=getSubsamp(dinfo); - *width=j->dinfo.image_width; *height=j->dinfo.image_height; - *jpegsub=-1; - for(i=0; i<NUMSUBOPT; i++) - { - if(j->dinfo.num_components==pixelsize[i]) - { - if(j->dinfo.comp_info[0].h_samp_factor==hsampfactor[i] - && j->dinfo.comp_info[0].v_samp_factor==vsampfactor[i]) - { - int match=0; - for(k=1; k<j->dinfo.num_components; k++) - { - if(j->dinfo.comp_info[k].h_samp_factor==1 - && j->dinfo.comp_info[k].v_samp_factor==1) - match++; - } - if(match==j->dinfo.num_components-1) - { - *jpegsub=i; break; - } - } - } - } + jpeg_abort_decompress(dinfo); - jpeg_abort_decompress(&j->dinfo); - - if(*jpegsub<0) _throw("Could not determine subsampling type for JPEG image"); - if(*width<1 || *height<1) _throw("Invalid data returned in header"); + if(*jpegSubsamp<0) + _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image"); + if(*width<1 || *height<1) + _throw("tjDecompressHeader2(): Invalid data returned in header"); bailout: return retval; } +DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height) +{ + int jpegSubsamp; + return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height, + &jpegSubsamp); +} -DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h, - unsigned char *srcbuf, unsigned long size, - int *width, int *height) + +DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors) { - int jpegsub; - return tjDecompressHeader2(h, srcbuf, size, width, height, &jpegsub); + if(numscalingfactors==NULL) + { + snprintf(errStr, JMSG_LENGTH_MAX, + "tjGetScalingFactors(): Invalid argument"); + return NULL; + } + + *numscalingfactors=NUMSF; + return (tjscalingfactor *)sf; } -DLLEXPORT int DLLCALL tjDecompress(tjhandle h, - unsigned char *srcbuf, unsigned long size, - unsigned char *dstbuf, int width, int pitch, int height, int ps, - int flags) +DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf, + unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, + int height, int pixelFormat, int flags) { int i, retval=0; JSAMPROW *row_pointer=NULL; + int jpegwidth, jpegheight, scaledw, scaledh; + #ifndef JCS_EXTENSIONS + unsigned char *rgbBuf=NULL; + unsigned char *_dstBuf=NULL; int _pitch=0; + #endif - checkhandle(h); - - if(srcbuf==NULL || size<=0 - || dstbuf==NULL || width<=0 || pitch<0 || height<=0) - _throw("Invalid argument in tjDecompress()"); - if(ps!=3 && ps!=4 && ps!=1) - _throw("This decompressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale output"); - if(!j->initd) _throw("Instance has not been initialized for decompression"); + getinstance(handle); + if((this->init&DECOMPRESS)==0) + _throw("tjDecompress2(): Instance has not been initialized for decompression"); - if(pitch==0) pitch=width*ps; + if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0 + || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF) + _throw("tjDecompress2(): Invalid argument"); - if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); - else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1"); - else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); + if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); + else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); + else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); - if(setjmp(j->jerr.jb)) - { // this will execute if LIBJPEG has an error + if(setjmp(this->jerr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. */ retval=-1; goto bailout; } - j->jsms.bytes_in_buffer = size; - j->jsms.next_input_byte = srcbuf; + this->jsrc.bytes_in_buffer=jpegSize; + this->jsrc.next_input_byte=jpegBuf; + jpeg_read_header(dinfo, TRUE); + if(setDecompDefaults(dinfo, pixelFormat)==-1) + { + retval=-1; goto bailout; + } - jpeg_read_header(&j->dinfo, TRUE); + if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE; - if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL) - _throw("Memory allocation failed in tjDecompress()"); - for(i=0; i<height; i++) + jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height; + if(width==0) width=jpegwidth; + if(height==0) height=jpegheight; + for(i=0; i<NUMSF; i++) { - if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch]; - else row_pointer[i]= &dstbuf[i*pitch]; + scaledw=TJSCALED(jpegwidth, sf[i]); + scaledh=TJSCALED(jpegheight, sf[i]); + if(scaledw<=width && scaledh<=height) + break; + } + if(scaledw>width || scaledh>height) + _throw("tjDecompress2(): Could not scale down to desired image dimensions"); + width=scaledw; height=scaledh; + dinfo->scale_num=sf[i].num; + dinfo->scale_denom=sf[i].denom; + + jpeg_start_decompress(dinfo); + if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat]; + + #ifndef JCS_EXTENSIONS + if(pixelFormat!=TJPF_GRAY && + (RGB_RED!=tjRedOffset[pixelFormat] || + RGB_GREEN!=tjGreenOffset[pixelFormat] || + RGB_BLUE!=tjBlueOffset[pixelFormat] || + RGB_PIXELSIZE!=tjPixelSize[pixelFormat])) + { + rgbBuf=(unsigned char *)malloc(width*height*3); + if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure"); + _pitch=pitch; pitch=width*3; + _dstBuf=dstBuf; dstBuf=rgbBuf; } - - if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE; - #if JCS_EXTENSIONS==1 - else j->dinfo.out_color_space = JCS_EXT_RGB; - if(ps==3 && (flags&TJ_BGR)) - j->dinfo.out_color_space = JCS_EXT_BGR; - else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) - j->dinfo.out_color_space = JCS_EXT_RGBX; - else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST)) - j->dinfo.out_color_space = JCS_EXT_BGRX; - else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) - j->dinfo.out_color_space = JCS_EXT_XBGR; - else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST)) - j->dinfo.out_color_space = JCS_EXT_XRGB; - #else - #error "TurboJPEG requires JPEG colorspace extensions" #endif - if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE; - - jpeg_start_decompress(&j->dinfo); - while(j->dinfo.output_scanline<j->dinfo.output_height) + if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW) + *dinfo->output_height))==NULL) + _throw("tjDecompress2(): Memory allocation failure"); + for(i=0; i<(int)dinfo->output_height; i++) + { + if(flags&TJFLAG_BOTTOMUP) + row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch]; + else row_pointer[i]=&dstBuf[i*pitch]; + } + while(dinfo->output_scanline<dinfo->output_height) { - jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline], - j->dinfo.output_height-j->dinfo.output_scanline); + jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline], + dinfo->output_height-dinfo->output_scanline); } - jpeg_finish_decompress(&j->dinfo); + jpeg_finish_decompress(dinfo); + + #ifndef JCS_EXTENSIONS + fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat); + #endif bailout: - if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo); + if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo); + #ifndef JCS_EXTENSIONS + if(rgbBuf && rgbBuf!=dstBuf) free(rgbBuf); + #endif if(row_pointer) free(row_pointer); return retval; } - -// General - -DLLEXPORT char* DLLCALL tjGetErrorStr(void) -{ - return lasterror; -} - -DLLEXPORT int DLLCALL tjDestroy(tjhandle h) +DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf, + unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, + int height, int pixelSize, int flags) { - checkhandle(h); - if(setjmp(j->jerr.jb)) return -1; - if(j->initc) jpeg_destroy_compress(&j->cinfo); - if(j->initd) jpeg_destroy_decompress(&j->dinfo); - free(j); - return 0; + return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch, + height, getPixelFormat(pixelSize, flags), flags); } diff --git a/common/turbojpeg.h b/common/turbojpeg.h index 6e3e259..ab8adda 100644 --- a/common/turbojpeg.h +++ b/common/turbojpeg.h @@ -1,255 +1,529 @@ -/* Copyright (C)2004 Landmark Graphics Corporation - * Copyright (C)2005, 2006 Sun Microsystems, Inc. - * Copyright (C)2009-2011 D. R. Commander +/* + * Copyright (C)2009-2012 D. R. Commander. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * This library is free software and may be redistributed and/or modified under - * the terms of the wxWindows Library License, Version 3.1 or (at your option) - * any later version. The full license is in the LICENSE.txt file included - * with this distribution. + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the libjpeg-turbo Project nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * wxWindows Library License for more details. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ -#if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) \ - && defined(_WIN32) && defined(DLLDEFINE) +#ifndef __TURBOJPEG_H__ +#define __TURBOJPEG_H__ + +#if defined(_WIN32) && defined(DLLDEFINE) #define DLLEXPORT __declspec(dllexport) #else #define DLLEXPORT #endif - #define DLLCALL -/* Subsampling */ -#define NUMSUBOPT 4 - -enum {TJ_444=0, TJ_422, TJ_420, TJ_GRAYSCALE}; -#define TJ_411 TJ_420 /* for backward compatibility with VirtualGL <= 2.1.x, - TurboVNC <= 0.6, and TurboJPEG/IPP */ - - -/* Flags */ -#define TJ_BGR 1 - /* The components of each pixel in the source/destination bitmap are stored - in B,G,R order, not R,G,B */ -#define TJ_BOTTOMUP 2 - /* The source/destination bitmap is stored in bottom-up (Windows, OpenGL) - order, not top-down (X11) order */ -#define TJ_FORCEMMX 8 - /* Turn off CPU auto-detection and force TurboJPEG to use MMX code - (IPP and 32-bit libjpeg-turbo versions only) */ -#define TJ_FORCESSE 16 - /* Turn off CPU auto-detection and force TurboJPEG to use SSE code - (32-bit IPP and 32-bit libjpeg-turbo versions only) */ -#define TJ_FORCESSE2 32 - /* Turn off CPU auto-detection and force TurboJPEG to use SSE2 code - (32-bit IPP and 32-bit libjpeg-turbo versions only) */ -#define TJ_ALPHAFIRST 64 - /* If the source/destination bitmap is 32 bpp, assume that each pixel is - ARGB/XRGB (or ABGR/XBGR if TJ_BGR is also specified) */ -#define TJ_FORCESSE3 128 - /* Turn off CPU auto-detection and force TurboJPEG to use SSE3 code - (64-bit IPP version only) */ -#define TJ_FASTUPSAMPLE 256 - /* Use fast, inaccurate 4:2:2 and 4:2:0 YUV upsampling routines - (libjpeg and libjpeg-turbo versions only) */ +/** + * @addtogroup TurboJPEG Lite + * TurboJPEG API. This API provides an interface for generating and decoding + * JPEG images in memory. + * + * @{ + */ + + +/** + * The number of chrominance subsampling options + */ +#define TJ_NUMSAMP 5 + +/** + * Chrominance subsampling options. + * When an image is converted from the RGB to the YCbCr colorspace as part of + * the JPEG compression process, some of the Cb and Cr (chrominance) components + * can be discarded or averaged together to produce a smaller image with little + * perceptible loss of image clarity (the human eye is more sensitive to small + * changes in brightness than small changes in color.) This is called + * "chrominance subsampling". + */ +enum TJSAMP +{ + /** + * 4:4:4 chrominance subsampling (no chrominance subsampling). The JPEG or + * YUV image will contain one chrominance component for every pixel in the + * source image. + */ + TJSAMP_444=0, + /** + * 4:2:2 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 2x1 block of pixels in the source image. + */ + TJSAMP_422, + /** + * 4:2:0 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 2x2 block of pixels in the source image. + */ + TJSAMP_420, + /** + * Grayscale. The JPEG or YUV image will contain no chrominance components. + */ + TJSAMP_GRAY, + /** + * 4:4:0 chrominance subsampling. The JPEG or YUV image will contain one + * chrominance component for every 1x2 block of pixels in the source image. + */ + TJSAMP_440 +}; + +/** + * MCU block width (in pixels) for a given level of chrominance subsampling. + * MCU block sizes: + * - 8x8 for no subsampling or grayscale + * - 16x8 for 4:2:2 + * - 8x16 for 4:4:0 + * - 16x16 for 4:2:0 + */ +static const int tjMCUWidth[TJ_NUMSAMP] = {8, 16, 16, 8, 8}; + +/** + * MCU block height (in pixels) for a given level of chrominance subsampling. + * MCU block sizes: + * - 8x8 for no subsampling or grayscale + * - 16x8 for 4:2:2 + * - 8x16 for 4:4:0 + * - 16x16 for 4:2:0 + */ +static const int tjMCUHeight[TJ_NUMSAMP] = {8, 8, 16, 8, 16}; + + +/** + * The number of pixel formats + */ +#define TJ_NUMPF 11 + +/** + * Pixel formats + */ +enum TJPF +{ + /** + * RGB pixel format. The red, green, and blue components in the image are + * stored in 3-byte pixels in the order R, G, B from lowest to highest byte + * address within each pixel. + */ + TJPF_RGB=0, + /** + * BGR pixel format. The red, green, and blue components in the image are + * stored in 3-byte pixels in the order B, G, R from lowest to highest byte + * address within each pixel. + */ + TJPF_BGR, + /** + * RGBX pixel format. The red, green, and blue components in the image are + * stored in 4-byte pixels in the order R, G, B from lowest to highest byte + * address within each pixel. The X component is ignored when compressing + * and undefined when decompressing. + */ + TJPF_RGBX, + /** + * BGRX pixel format. The red, green, and blue components in the image are + * stored in 4-byte pixels in the order B, G, R from lowest to highest byte + * address within each pixel. The X component is ignored when compressing + * and undefined when decompressing. + */ + TJPF_BGRX, + /** + * XBGR pixel format. The red, green, and blue components in the image are + * stored in 4-byte pixels in the order R, G, B from highest to lowest byte + * address within each pixel. The X component is ignored when compressing + * and undefined when decompressing. + */ + TJPF_XBGR, + /** + * XRGB pixel format. The red, green, and blue components in the image are + * stored in 4-byte pixels in the order B, G, R from highest to lowest byte + * address within each pixel. The X component is ignored when compressing + * and undefined when decompressing. + */ + TJPF_XRGB, + /** + * Grayscale pixel format. Each 1-byte pixel represents a luminance + * (brightness) level from 0 to 255. + */ + TJPF_GRAY, + /** + * RGBA pixel format. This is the same as @ref TJPF_RGBX, except that when + * decompressing, the X component is guaranteed to be 0xFF, which can be + * interpreted as an opaque alpha channel. + */ + TJPF_RGBA, + /** + * BGRA pixel format. This is the same as @ref TJPF_BGRX, except that when + * decompressing, the X component is guaranteed to be 0xFF, which can be + * interpreted as an opaque alpha channel. + */ + TJPF_BGRA, + /** + * ABGR pixel format. This is the same as @ref TJPF_XBGR, except that when + * decompressing, the X component is guaranteed to be 0xFF, which can be + * interpreted as an opaque alpha channel. + */ + TJPF_ABGR, + /** + * ARGB pixel format. This is the same as @ref TJPF_XRGB, except that when + * decompressing, the X component is guaranteed to be 0xFF, which can be + * interpreted as an opaque alpha channel. + */ + TJPF_ARGB +}; + +/** + * Red offset (in bytes) for a given pixel format. This specifies the number + * of bytes that the red component is offset from the start of the pixel. For + * instance, if a pixel of format TJ_BGRX is stored in <tt>char pixel[]</tt>, + * then the red component will be <tt>pixel[tjRedOffset[TJ_BGRX]]</tt>. + */ +static const int tjRedOffset[TJ_NUMPF] = {0, 2, 0, 2, 3, 1, 0, 0, 2, 3, 1}; +/** + * Green offset (in bytes) for a given pixel format. This specifies the number + * of bytes that the green component is offset from the start of the pixel. + * For instance, if a pixel of format TJ_BGRX is stored in + * <tt>char pixel[]</tt>, then the green component will be + * <tt>pixel[tjGreenOffset[TJ_BGRX]]</tt>. + */ +static const int tjGreenOffset[TJ_NUMPF] = {1, 1, 1, 1, 2, 2, 0, 1, 1, 2, 2}; +/** + * Blue offset (in bytes) for a given pixel format. This specifies the number + * of bytes that the Blue component is offset from the start of the pixel. For + * instance, if a pixel of format TJ_BGRX is stored in <tt>char pixel[]</tt>, + * then the blue component will be <tt>pixel[tjBlueOffset[TJ_BGRX]]</tt>. + */ +static const int tjBlueOffset[TJ_NUMPF] = {2, 0, 2, 0, 1, 3, 0, 2, 0, 1, 3}; + +/** + * Pixel size (in bytes) for a given pixel format. + */ +static const int tjPixelSize[TJ_NUMPF] = {3, 3, 4, 4, 4, 4, 1, 4, 4, 4, 4}; +/** + * The uncompressed source/destination image is stored in bottom-up (Windows, + * OpenGL) order, not top-down (X11) order. + */ +#define TJFLAG_BOTTOMUP 2 +/** + * Turn off CPU auto-detection and force TurboJPEG to use MMX code (IPP and + * 32-bit libjpeg-turbo versions only.) + */ +#define TJFLAG_FORCEMMX 8 +/** + * Turn off CPU auto-detection and force TurboJPEG to use SSE code (32-bit IPP + * and 32-bit libjpeg-turbo versions only) + */ +#define TJFLAG_FORCESSE 16 +/** + * Turn off CPU auto-detection and force TurboJPEG to use SSE2 code (32-bit IPP + * and 32-bit libjpeg-turbo versions only) + */ +#define TJFLAG_FORCESSE2 32 +/** + * Turn off CPU auto-detection and force TurboJPEG to use SSE3 code (64-bit IPP + * version only) + */ +#define TJFLAG_FORCESSE3 128 +/** + * Use fast, inaccurate chrominance upsampling routines in the JPEG + * decompressor (libjpeg and libjpeg-turbo versions only) + */ +#define TJFLAG_FASTUPSAMPLE 256 + + +/** + * Scaling factor + */ +typedef struct +{ + /** + * Numerator + */ + int num; + /** + * Denominator + */ + int denom; +} tjscalingfactor; + + +/** + * TurboJPEG instance handle + */ typedef void* tjhandle; -#define TJPAD(p) (((p)+3)&(~3)) -#ifndef max - #define max(a,b) ((a)>(b)?(a):(b)) -#endif + +/** + * Pad the given width to the nearest 32-bit boundary + */ +#define TJPAD(width) (((width)+3)&(~3)) + +/** + * Compute the scaled value of <tt>dimension</tt> using the given scaling + * factor. This macro performs the integer equivalent of <tt>ceil(dimension * + * scalingFactor)</tt>. + */ +#define TJSCALED(dimension, scalingFactor) ((dimension * scalingFactor.num \ + + scalingFactor.denom - 1) / scalingFactor.denom) #ifdef __cplusplus extern "C" { #endif -/* API follows */ - -/* - tjhandle tjInitCompress(void) +/** + * Create a TurboJPEG compressor instance. + * + * @return a handle to the newly-created instance, or NULL if an error + * occurred (see #tjGetErrorStr().) + */ +DLLEXPORT tjhandle DLLCALL tjInitCompress(void); - Creates a new JPEG compressor instance, allocates memory for the structures, - and returns a handle to the instance. Most applications will only - need to call this once at the beginning of the program or once for each - concurrent thread. Don't try to create a new instance every time you - compress an image, because this may cause performance to suffer in some - TurboJPEG implementations. - RETURNS: NULL on error +/** + * Compress an RGB or grayscale image into a JPEG image. + * + * @param handle a handle to a TurboJPEG compressor or transformer instance + * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels + * to be compressed + * @param width width (in pixels) of the source image + * @param pitch bytes per line of the source image. Normally, this should be + * <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded, + * or <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of + * the image is padded to the nearest 32-bit boundary, as is the case + * for Windows bitmaps. You can also be clever and use this parameter + * to skip lines, etc. Setting this parameter to 0 is the equivalent of + * setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>. + * @param height height (in pixels) of the source image + * @param pixelFormat pixel format of the source image (see @ref TJPF + * "Pixel formats".) + * @param jpegBuf address of a pointer to an image buffer that will receive the + * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer + * to accommodate the size of the JPEG image. Thus, you can choose to: + * -# pre-allocate the JPEG buffer with an arbitrary size using + * #tjAlloc() and let TurboJPEG grow the buffer as needed, + * -# set <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the + * buffer for you, or + * -# pre-allocate the buffer to a "worst case" size determined by + * calling #tjBufSize(). This should ensure that the buffer never has + * to be re-allocated (setting #TJFLAG_NOREALLOC guarantees this.) + * . + * If you choose option 1, <tt>*jpegSize</tt> should be set to the + * size of your pre-allocated buffer. In any case, unless you have + * set #TJFLAG_NOREALLOC, you should always check <tt>*jpegBuf</tt> upon + * return from this function, as it may have changed. + * @param jpegSize pointer to an unsigned long variable that holds the size of + * the JPEG image buffer. If <tt>*jpegBuf</tt> points to a + * pre-allocated buffer, then <tt>*jpegSize</tt> should be set to the + * size of the buffer. Upon return, <tt>*jpegSize</tt> will contain the + * size of the JPEG image (in bytes.) + * @param jpegSubsamp the level of chrominance subsampling to be used when + * generating the JPEG image (see @ref TJSAMP + * "Chrominance subsampling options".) + * @param jpegQual the image quality of the generated JPEG image (1 = worst, + 100 = best) + * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP + * "flags". + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) */ -DLLEXPORT tjhandle DLLCALL tjInitCompress(void); +DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, + int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, + unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags); + + +/** + * The maximum size of the buffer (in bytes) required to hold a JPEG image with + * the given parameters. The number of bytes returned by this function is + * larger than the size of the uncompressed source image. The reason for this + * is that the JPEG format uses 16-bit coefficients, and it is thus possible + * for a very high-quality JPEG image with very high frequency content to + * expand rather than compress when converted to the JPEG format. Such images + * represent a very rare corner case, but since there is no way to predict the + * size of a JPEG image prior to compression, the corner case has to be + * handled. + * + * @param width width of the image (in pixels) + * @param height height of the image (in pixels) + * @param jpegSubsamp the level of chrominance subsampling to be used when + * generating the JPEG image (see @ref TJSAMP + * "Chrominance subsampling options".) + * + * @return the maximum size of the buffer (in bytes) required to hold the + * image, or -1 if the arguments are out of bounds. + */ +DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height, + int jpegSubsamp); -/* - int tjCompress(tjhandle j, - unsigned char *srcbuf, int width, int pitch, int height, int pixelsize, - unsigned char *dstbuf, unsigned long *size, - int jpegsubsamp, int jpegqual, int flags) - - [INPUT] j = instance handle previously returned from a call to - tjInitCompress() - [INPUT] srcbuf = pointer to user-allocated image buffer containing RGB or - grayscale pixels to be compressed - [INPUT] width = width (in pixels) of the source image - [INPUT] pitch = bytes per line of the source image (width*pixelsize if the - bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap - is padded to the nearest 32-bit boundary, such as is the case for Windows - bitmaps. You can also be clever and use this parameter to skip lines, - etc. Setting this parameter to 0 is the equivalent of setting it to - width*pixelsize. - [INPUT] height = height (in pixels) of the source image - [INPUT] pixelsize = size (in bytes) of each pixel in the source image - RGBX/BGRX/XRGB/XBGR: 4, RGB/BGR: 3, Grayscale: 1 - [INPUT] dstbuf = pointer to user-allocated image buffer that will receive - the JPEG image. Use the TJBUFSIZE(width, height) function to determine - the appropriate size for this buffer based on the image width and height. - [OUTPUT] size = pointer to unsigned long that receives the size (in bytes) - of the compressed image - [INPUT] jpegsubsamp = Specifies either 4:2:0, 4:2:2, 4:4:4, or grayscale - subsampling. When the image is converted from the RGB to YCbCr colorspace - as part of the JPEG compression process, every other Cb and Cr - (chrominance) pixel can be discarded to produce a smaller image with - little perceptible loss of image clarity (the human eye is more sensitive - to small changes in brightness than small changes in color.) - - TJ_420: 4:2:0 subsampling. Discards every other Cb, Cr pixel in both - horizontal and vertical directions - TJ_422: 4:2:2 subsampling. Discards every other Cb, Cr pixel only in - the horizontal direction - TJ_444: no subsampling - TJ_GRAYSCALE: Generate grayscale JPEG image - - [INPUT] jpegqual = JPEG quality (an integer between 0 and 100 inclusive) - [INPUT] flags = the bitwise OR of one or more of the flags described in the - "Flags" section above - - RETURNS: 0 on success, -1 on error +/** + * Create a TurboJPEG decompressor instance. + * + * @return a handle to the newly-created instance, or NULL if an error + * occurred (see #tjGetErrorStr().) */ -DLLEXPORT int DLLCALL tjCompress(tjhandle j, - unsigned char *srcbuf, int width, int pitch, int height, int pixelsize, - unsigned char *dstbuf, unsigned long *size, - int jpegsubsamp, int jpegqual, int flags); +DLLEXPORT tjhandle DLLCALL tjInitDecompress(void); -/* - unsigned long TJBUFSIZE(int width, int height) +/** + * Retrieve information about a JPEG image without decompressing it. + * + * @param handle a handle to a TurboJPEG decompressor or transformer instance + * @param jpegBuf pointer to a buffer containing a JPEG image + * @param jpegSize size of the JPEG image (in bytes) + * @param width pointer to an integer variable that will receive the width (in + * pixels) of the JPEG image + * @param height pointer to an integer variable that will receive the height + * (in pixels) of the JPEG image + * @param jpegSubsamp pointer to an integer variable that will receive the + * level of chrominance subsampling used when compressing the JPEG image + * (see @ref TJSAMP "Chrominance subsampling options".) + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) +*/ +DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, + int *jpegSubsamp); - Convenience function that returns the maximum size of the buffer required to - hold a JPEG image with the given width and height - RETURNS: -1 if arguments are out of bounds +/** + * Returns a list of fractional scaling factors that the JPEG decompressor in + * this implementation of TurboJPEG supports. + * + * @param numscalingfactors pointer to an integer variable that will receive + * the number of elements in the list + * + * @return a pointer to a list of fractional scaling factors, or NULL if an + * error is encountered (see #tjGetErrorStr().) */ -DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height); - +DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors); -/* - tjhandle tjInitDecompress(void) - Creates a new JPEG decompressor instance, allocates memory for the - structures, and returns a handle to the instance. Most applications will - only need to call this once at the beginning of the program or once for each - concurrent thread. Don't try to create a new instance every time you - decompress an image, because this may cause performance to suffer in some - TurboJPEG implementations. +/** + * Decompress a JPEG image to an RGB or grayscale image. + * + * @param handle a handle to a TurboJPEG decompressor or transformer instance + * @param jpegBuf pointer to a buffer containing the JPEG image to decompress + * @param jpegSize size of the JPEG image (in bytes) + * @param dstBuf pointer to an image buffer that will receive the decompressed + * image. This buffer should normally be <tt>pitch * scaledHeight</tt> + * bytes in size, where <tt>scaledHeight</tt> can be determined by + * calling #TJSCALED() with the JPEG image height and one of the scaling + * factors returned by #tjGetScalingFactors(). The dstBuf pointer may + * also be used to decompress into a specific region of a larger buffer. + * @param width desired width (in pixels) of the destination image. If this is + * smaller than the width of the JPEG image being decompressed, then + * TurboJPEG will use scaling in the JPEG decompressor to generate the + * largest possible image that will fit within the desired width. If + * width is set to 0, then only the height will be considered when + * determining the scaled image size. + * @param pitch bytes per line of the destination image. Normally, this is + * <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt> if the decompressed + * image is unpadded, else <tt>#TJPAD(scaledWidth * + * #tjPixelSize[pixelFormat])</tt> if each line of the decompressed + * image is padded to the nearest 32-bit boundary, as is the case for + * Windows bitmaps. (NOTE: <tt>scaledWidth</tt> can be determined by + * calling #TJSCALED() with the JPEG image width and one of the scaling + * factors returned by #tjGetScalingFactors().) You can also be clever + * and use the pitch parameter to skip lines, etc. Setting this + * parameter to 0 is the equivalent of setting it to <tt>scaledWidth + * * #tjPixelSize[pixelFormat]</tt>. + * @param height desired height (in pixels) of the destination image. If this + * is smaller than the height of the JPEG image being decompressed, then + * TurboJPEG will use scaling in the JPEG decompressor to generate the + * largest possible image that will fit within the desired height. If + * height is set to 0, then only the width will be considered when + * determining the scaled image size. + * @param pixelFormat pixel format of the destination image (see @ref + * TJPF "Pixel formats".) + * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP + * "flags". + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) + */ +DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, + int width, int pitch, int height, int pixelFormat, int flags); - RETURNS: NULL on error -*/ -DLLEXPORT tjhandle DLLCALL tjInitDecompress(void); +/** + * Destroy a TurboJPEG compressor, decompressor, or transformer instance. + * + * @param handle a handle to a TurboJPEG compressor, decompressor or + * transformer instance + * + * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().) + */ +DLLEXPORT int DLLCALL tjDestroy(tjhandle handle); -/* - int tjDecompressHeader2(tjhandle j, - unsigned char *srcbuf, unsigned long size, - int *width, int *height, int *jpegsubsamp) - - [INPUT] j = instance handle previously returned from a call to - tjInitDecompress() - [INPUT] srcbuf = pointer to a user-allocated buffer containing a JPEG image - [INPUT] size = size of the JPEG image buffer (in bytes) - [OUTPUT] width = width (in pixels) of the JPEG image - [OUTPUT] height = height (in pixels) of the JPEG image - [OUTPUT] jpegsubsamp = type of chrominance subsampling used when compressing - the JPEG image - - RETURNS: 0 on success, -1 on error -*/ -DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle j, - unsigned char *srcbuf, unsigned long size, - int *width, int *height, int *jpegsubsamp); -/* - Legacy version of the above function -*/ -DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j, - unsigned char *srcbuf, unsigned long size, - int *width, int *height); +/** + * Returns a descriptive error message explaining why the last command failed. + * + * @return a descriptive error message explaining why the last command failed. + */ +DLLEXPORT char* DLLCALL tjGetErrorStr(void); -/* - int tjDecompress(tjhandle j, - unsigned char *srcbuf, unsigned long size, - unsigned char *dstbuf, int width, int pitch, int height, int pixelsize, - int flags) - - [INPUT] j = instance handle previously returned from a call to - tjInitDecompress() - [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image - to decompress - [INPUT] size = size of the JPEG image buffer (in bytes) - [INPUT] dstbuf = pointer to user-allocated image buffer that will receive - the bitmap image. This buffer should normally be pitch*height - bytes in size, although this pointer may also be used to decompress into - a specific region of a larger buffer. - [INPUT] width = width (in pixels) of the destination image - [INPUT] pitch = bytes per line of the destination image (width*pixelsize if - the bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the - bitmap is padded to the nearest 32-bit boundary, such as is the case for - Windows bitmaps. You can also be clever and use this parameter to skip - lines, etc. Setting this parameter to 0 is the equivalent of setting it - to width*pixelsize. - [INPUT] height = height (in pixels) of the destination image - [INPUT] pixelsize = size (in bytes) of each pixel in the destination image - RGBX/BGRX/XRGB/XBGR: 4, RGB/BGR: 3, Grayscale: 1 - [INPUT] flags = the bitwise OR of one or more of the flags described in the - "Flags" section above. - - RETURNS: 0 on success, -1 on error -*/ -DLLEXPORT int DLLCALL tjDecompress(tjhandle j, - unsigned char *srcbuf, unsigned long size, - unsigned char *dstbuf, int width, int pitch, int height, int pixelsize, - int flags); +/* Backward compatibility functions and macros (nothing to see here) */ +#define NUMSUBOPT TJ_NUMSAMP +#define TJ_444 TJSAMP_444 +#define TJ_422 TJSAMP_422 +#define TJ_420 TJSAMP_420 +#define TJ_411 TJSAMP_420 +#define TJ_GRAYSCALE TJSAMP_GRAY +#define TJ_BGR 1 +#define TJ_BOTTOMUP TJFLAG_BOTTOMUP +#define TJ_FORCEMMX TJFLAG_FORCEMMX +#define TJ_FORCESSE TJFLAG_FORCESSE +#define TJ_FORCESSE2 TJFLAG_FORCESSE2 +#define TJ_ALPHAFIRST 64 +#define TJ_FORCESSE3 TJFLAG_FORCESSE3 +#define TJ_FASTUPSAMPLE TJFLAG_FASTUPSAMPLE -/* - int tjDestroy(tjhandle h) +DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height); - Frees structures associated with a compression or decompression instance - - [INPUT] h = instance handle (returned from a previous call to - tjInitCompress() or tjInitDecompress() +DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf, + int width, int pitch, int height, int pixelSize, unsigned char *dstBuf, + unsigned long *compressedSize, int jpegSubsamp, int jpegQual, int flags); - RETURNS: 0 on success, -1 on error -*/ -DLLEXPORT int DLLCALL tjDestroy(tjhandle h); +DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height); +DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, + unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, + int width, int pitch, int height, int pixelSize, int flags); -/* - char *tjGetErrorStr(void) - - Returns a descriptive error message explaining why the last command failed -*/ -DLLEXPORT char* DLLCALL tjGetErrorStr(void); +/** + * @} + */ #ifdef __cplusplus } #endif + +#endif |