Home | History | Annotate | Download | only in libjpeg_turbo
      1 /* Copyright (C)2004 Landmark Graphics Corporation
      2  * Copyright (C)2005 Sun Microsystems, Inc.
      3  * Copyright (C)2009 D. R. Commander
      4  *
      5  * This library is free software and may be redistributed and/or modified under
      6  * the terms of the wxWindows Library License, Version 3.1 or (at your option)
      7  * any later version.  The full license is in the LICENSE.txt file included
      8  * with this distribution.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * wxWindows Library License for more details.
     14  */
     15 
     16 // This implements a JPEG compressor/decompressor using the libjpeg API
     17 
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 #include <jpeglib.h>
     22 #include <jerror.h>
     23 #include <setjmp.h>
     24 #include "./turbojpeg.h"
     25 
     26 
     27 // Error handling
     28 
     29 static char lasterror[JMSG_LENGTH_MAX]="No error";
     30 
     31 typedef struct _error_mgr
     32 {
     33 	struct jpeg_error_mgr pub;
     34 	jmp_buf jb;
     35 } error_mgr;
     36 
     37 static void my_error_exit(j_common_ptr cinfo)
     38 {
     39 	error_mgr *myerr = (error_mgr *)cinfo->err;
     40 	(*cinfo->err->output_message)(cinfo);
     41 	longjmp(myerr->jb, 1);
     42 }
     43 
     44 static void my_output_message(j_common_ptr cinfo)
     45 {
     46 	(*cinfo->err->format_message)(cinfo, lasterror);
     47 }
     48 
     49 
     50 // Global structures, macros, etc.
     51 
     52 typedef struct _jpgstruct
     53 {
     54 	struct jpeg_compress_struct cinfo;
     55 	struct jpeg_decompress_struct dinfo;
     56 	struct jpeg_destination_mgr jdms;
     57 	struct jpeg_source_mgr jsms;
     58 	error_mgr jerr;
     59 	int initc, initd;
     60 } jpgstruct;
     61 
     62 static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1};
     63 static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1};
     64 
     65 #define _throw(c) {sprintf(lasterror, "%s", c);  return -1;}
     66 #define _catch(f) {if((f)==-1) return -1;}
     67 #define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
     68 	if(!j) _throw("Invalid handle");
     69 
     70 
     71 // CO
     72 
     73 static boolean empty_output_buffer(struct jpeg_compress_struct *cinfo)
     74 {
     75 	ERREXIT(cinfo, JERR_BUFFER_SIZE);
     76 	return TRUE;
     77 }
     78 
     79 static void destination_noop(struct jpeg_compress_struct *cinfo)
     80 {
     81 }
     82 
     83 DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
     84 {
     85 	jpgstruct *j=NULL;
     86 	if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
     87 		{sprintf(lasterror, "Memory allocation failure");  return NULL;}
     88 	memset(j, 0, sizeof(jpgstruct));
     89 	j->cinfo.err=jpeg_std_error(&j->jerr.pub);
     90 	j->jerr.pub.error_exit=my_error_exit;
     91 	j->jerr.pub.output_message=my_output_message;
     92 
     93 	if(setjmp(j->jerr.jb))
     94 	{ // this will execute if LIBJPEG has an error
     95 		if(j) free(j);  return NULL;
     96   }
     97 
     98 	jpeg_create_compress(&j->cinfo);
     99 	j->cinfo.dest=&j->jdms;
    100 	j->jdms.init_destination=destination_noop;
    101 	j->jdms.empty_output_buffer=empty_output_buffer;
    102 	j->jdms.term_destination=destination_noop;
    103 
    104 	j->initc=1;
    105 	return (tjhandle)j;
    106 }
    107 
    108 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
    109 {
    110 	// This allows enough room in case the image doesn't compress
    111 	return ((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
    112 }
    113 
    114 DLLEXPORT int DLLCALL tjCompress(tjhandle h,
    115 	unsigned char *srcbuf, int width, int pitch, int height, int ps,
    116 	unsigned char *dstbuf, unsigned long *size,
    117 	int jpegsub, int qual, int flags)
    118 {
    119 	int i;  JSAMPROW *row_pointer=NULL;
    120 
    121 	checkhandle(h);
    122 
    123 	if(srcbuf==NULL || width<=0 || pitch<0 || height<=0
    124 		|| dstbuf==NULL || size==NULL
    125 		|| jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100)
    126 		_throw("Invalid argument in tjCompress()");
    127 	if(ps!=3 && ps!=4) _throw("This compressor can only take 24-bit or 32-bit RGB input");
    128 	if(!j->initc) _throw("Instance has not been initialized for compression");
    129 
    130 	if(pitch==0) pitch=width*ps;
    131 
    132 	j->cinfo.image_width = width;
    133 	j->cinfo.image_height = height;
    134 	j->cinfo.input_components = ps;
    135 
    136 	#if JCS_EXTENSIONS==1
    137 	j->cinfo.in_color_space = JCS_EXT_RGB;
    138 	if(ps==3 && (flags&TJ_BGR))
    139 		j->cinfo.in_color_space = JCS_EXT_BGR;
    140 	else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
    141 		j->cinfo.in_color_space = JCS_EXT_RGBX;
    142 	else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
    143 		j->cinfo.in_color_space = JCS_EXT_BGRX;
    144 	else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
    145 		j->cinfo.in_color_space = JCS_EXT_XBGR;
    146 	else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
    147 		j->cinfo.in_color_space = JCS_EXT_XRGB;
    148 	#else
    149 	#error "TurboJPEG requires JPEG colorspace extensions"
    150 	#endif
    151 
    152 	if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    153 	else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
    154 	else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    155 
    156 	if(setjmp(j->jerr.jb))
    157 	{  // this will execute if LIBJPEG has an error
    158 		if(row_pointer) free(row_pointer);
    159 		return -1;
    160   }
    161 
    162 	jpeg_set_defaults(&j->cinfo);
    163 
    164 	jpeg_set_quality(&j->cinfo, qual, TRUE);
    165 	if(jpegsub==TJ_GRAYSCALE)
    166 		jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE);
    167 	else
    168 		jpeg_set_colorspace(&j->cinfo, JCS_YCbCr);
    169 	j->cinfo.dct_method = JDCT_FASTEST;
    170 
    171 	j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub];
    172 	j->cinfo.comp_info[1].h_samp_factor=1;
    173 	j->cinfo.comp_info[2].h_samp_factor=1;
    174 	j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub];
    175 	j->cinfo.comp_info[1].v_samp_factor=1;
    176 	j->cinfo.comp_info[2].v_samp_factor=1;
    177 
    178 	j->jdms.next_output_byte = dstbuf;
    179 	j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height);
    180 
    181 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
    182 		_throw("Memory allocation failed in tjInitCompress()");
    183 	for(i=0; i<height; i++)
    184 	{
    185 		if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
    186 		else row_pointer[i]= &srcbuf[i*pitch];
    187 	}
    188 	jpeg_start_compress(&j->cinfo, TRUE);
    189 	while(j->cinfo.next_scanline<j->cinfo.image_height)
    190 	{
    191 		jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
    192 			j->cinfo.image_height-j->cinfo.next_scanline);
    193 	}
    194 	jpeg_finish_compress(&j->cinfo);
    195 	*size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)
    196 		-(unsigned long)(j->jdms.free_in_buffer);
    197 
    198 	if(row_pointer) free(row_pointer);
    199 	return 0;
    200 }
    201 
    202 
    203 // DEC
    204 
    205 static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo)
    206 {
    207 	ERREXIT(dinfo, JERR_BUFFER_SIZE);
    208 	return TRUE;
    209 }
    210 
    211 static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes)
    212 {
    213 	dinfo->src->next_input_byte += (size_t) num_bytes;
    214 	dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
    215 }
    216 
    217 static void source_noop (struct jpeg_decompress_struct *dinfo)
    218 {
    219 }
    220 
    221 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
    222 {
    223 	jpgstruct *j;
    224 	if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
    225 		{sprintf(lasterror, "Memory allocation failure");  return NULL;}
    226 	memset(j, 0, sizeof(jpgstruct));
    227 	j->dinfo.err=jpeg_std_error(&j->jerr.pub);
    228 	j->jerr.pub.error_exit=my_error_exit;
    229 	j->jerr.pub.output_message=my_output_message;
    230 
    231 	if(setjmp(j->jerr.jb))
    232 	{ // this will execute if LIBJPEG has an error
    233 		free(j);  return NULL;
    234   }
    235 
    236 	jpeg_create_decompress(&j->dinfo);
    237 	j->dinfo.src=&j->jsms;
    238 	j->jsms.init_source=source_noop;
    239 	j->jsms.fill_input_buffer = fill_input_buffer;
    240 	j->jsms.skip_input_data = skip_input_data;
    241 	j->jsms.resync_to_restart = jpeg_resync_to_restart;
    242 	j->jsms.term_source = source_noop;
    243 
    244 	j->initd=1;
    245 	return (tjhandle)j;
    246 }
    247 
    248 
    249 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
    250 	unsigned char *srcbuf, unsigned long size,
    251 	int *width, int *height)
    252 {
    253 	checkhandle(h);
    254 
    255 	if(srcbuf==NULL || size<=0 || width==NULL || height==NULL)
    256 		_throw("Invalid argument in tjDecompressHeader()");
    257 	if(!j->initd) _throw("Instance has not been initialized for decompression");
    258 
    259 	if(setjmp(j->jerr.jb))
    260 	{  // this will execute if LIBJPEG has an error
    261 		return -1;
    262 	}
    263 
    264 	j->jsms.bytes_in_buffer = size;
    265 	j->jsms.next_input_byte = srcbuf;
    266 
    267 	jpeg_read_header(&j->dinfo, TRUE);
    268 
    269 	*width=j->dinfo.image_width;  *height=j->dinfo.image_height;
    270 
    271 	jpeg_abort_decompress(&j->dinfo);
    272 
    273 	if(*width<1 || *height<1) _throw("Invalid data returned in header");
    274 	return 0;
    275 }
    276 
    277 
    278 DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
    279 	unsigned char *srcbuf, unsigned long size,
    280 	unsigned char *dstbuf, int width, int pitch, int height, int ps,
    281 	int flags)
    282 {
    283 	int i;  JSAMPROW *row_pointer=NULL;
    284 
    285 	checkhandle(h);
    286 
    287 	if(srcbuf==NULL || size<=0
    288 		|| dstbuf==NULL || width<=0 || pitch<0 || height<=0)
    289 		_throw("Invalid argument in tjDecompress()");
    290 	if(ps!=3 && ps!=4) _throw("This compressor can only take 24-bit or 32-bit RGB input");
    291 	if(!j->initd) _throw("Instance has not been initialized for decompression");
    292 
    293 	if(pitch==0) pitch=width*ps;
    294 
    295 	if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    296 	else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
    297 	else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    298 
    299 	if(setjmp(j->jerr.jb))
    300 	{  // this will execute if LIBJPEG has an error
    301 		if(row_pointer) free(row_pointer);
    302 		return -1;
    303   }
    304 
    305 	j->jsms.bytes_in_buffer = size;
    306 	j->jsms.next_input_byte = srcbuf;
    307 
    308 	jpeg_read_header(&j->dinfo, TRUE);
    309 
    310 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
    311 		_throw("Memory allocation failed in tjInitDecompress()");
    312 	for(i=0; i<height; i++)
    313 	{
    314 		if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
    315 		else row_pointer[i]= &dstbuf[i*pitch];
    316 	}
    317 
    318 	#if JCS_EXTENSIONS==1
    319 	j->dinfo.out_color_space = JCS_EXT_RGB;
    320 	if(ps==3 && (flags&TJ_BGR))
    321 		j->dinfo.out_color_space = JCS_EXT_BGR;
    322 	else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
    323 		j->dinfo.out_color_space = JCS_EXT_RGBX;
    324 	else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
    325 		j->dinfo.out_color_space = JCS_EXT_BGRX;
    326 	else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
    327 		j->dinfo.out_color_space = JCS_EXT_XBGR;
    328 	else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
    329 		j->dinfo.out_color_space = JCS_EXT_XRGB;
    330 	#else
    331 	#error "TurboJPEG requires JPEG colorspace extensions"
    332 	#endif
    333 	if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
    334 
    335 	jpeg_start_decompress(&j->dinfo);
    336 	while(j->dinfo.output_scanline<j->dinfo.output_height)
    337 	{
    338 		jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
    339 			j->dinfo.output_height-j->dinfo.output_scanline);
    340 	}
    341 	jpeg_finish_decompress(&j->dinfo);
    342 
    343 	if(row_pointer) free(row_pointer);
    344 	return 0;
    345 }
    346 
    347 
    348 // General
    349 
    350 DLLEXPORT char* DLLCALL tjGetErrorStr(void)
    351 {
    352 	return lasterror;
    353 }
    354 
    355 DLLEXPORT int DLLCALL tjDestroy(tjhandle h)
    356 {
    357 	checkhandle(h);
    358 	if(setjmp(j->jerr.jb)) return -1;
    359 	if(j->initc) jpeg_destroy_compress(&j->cinfo);
    360 	if(j->initd) jpeg_destroy_decompress(&j->dinfo);
    361 	free(j);
    362 	return 0;
    363 }
    364