Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright (C)2009-2012 D. R. Commander.  All Rights Reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are met:
      6  *
      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.
     15  *
     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.
     27  */
     28 
     29 /* TurboJPEG/OSS:  this implements the TurboJPEG API using libjpeg-turbo */
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #ifndef JCS_EXTENSIONS
     35 #define JPEG_INTERNAL_OPTIONS
     36 #endif
     37 #include <jpeglib.h>
     38 #include <jerror.h>
     39 #include <setjmp.h>
     40 #include "./turbojpeg.h"
     41 
     42 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
     43 
     44 #define CSTATE_START 100
     45 #define DSTATE_START 200
     46 #define MEMZERO(ptr, size) memset(ptr, 0, size)
     47 
     48 #ifndef min
     49  #define min(a,b) ((a)<(b)?(a):(b))
     50 #endif
     51 
     52 #ifndef max
     53  #define max(a,b) ((a)>(b)?(a):(b))
     54 #endif
     55 
     56 
     57 /* Error handling (based on example in example.c) */
     58 
     59 static char errStr[JMSG_LENGTH_MAX]="No error";
     60 
     61 struct my_error_mgr
     62 {
     63 	struct jpeg_error_mgr pub;
     64 	jmp_buf setjmp_buffer;
     65 };
     66 typedef struct my_error_mgr *my_error_ptr;
     67 
     68 static void my_error_exit(j_common_ptr cinfo)
     69 {
     70 	my_error_ptr myerr=(my_error_ptr)cinfo->err;
     71 	(*cinfo->err->output_message)(cinfo);
     72 	longjmp(myerr->setjmp_buffer, 1);
     73 }
     74 
     75 /* Based on output_message() in jerror.c */
     76 
     77 static void my_output_message(j_common_ptr cinfo)
     78 {
     79 	(*cinfo->err->format_message)(cinfo, errStr);
     80 }
     81 
     82 
     83 /* Global structures, macros, etc. */
     84 
     85 enum {COMPRESS=1, DECOMPRESS=2};
     86 
     87 typedef struct _tjinstance
     88 {
     89 	struct jpeg_compress_struct cinfo;
     90 	struct jpeg_decompress_struct dinfo;
     91 	struct jpeg_destination_mgr jdst;
     92 	struct jpeg_source_mgr jsrc;
     93 	struct my_error_mgr jerr;
     94 	int init;
     95 } tjinstance;
     96 
     97 static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
     98 
     99 #define NUMSF 4
    100 static const tjscalingfactor sf[NUMSF]={
    101 	{1, 1},
    102 	{1, 2},
    103 	{1, 4},
    104 	{1, 8}
    105 };
    106 
    107 #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
    108 	retval=-1;  goto bailout;}
    109 #define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
    110 	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
    111 	(void) cinfo; (void) dinfo; /* silence warnings */ \
    112 	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
    113 		return -1;}  \
    114 	cinfo=&this->cinfo;  dinfo=&this->dinfo;
    115 
    116 static int getPixelFormat(int pixelSize, int flags)
    117 {
    118 	if(pixelSize==1) return TJPF_GRAY;
    119 	if(pixelSize==3)
    120 	{
    121 		if(flags&TJ_BGR) return TJPF_BGR;
    122 		else return TJPF_RGB;
    123 	}
    124 	if(pixelSize==4)
    125 	{
    126 		if(flags&TJ_ALPHAFIRST)
    127 		{
    128 			if(flags&TJ_BGR) return TJPF_XBGR;
    129 			else return TJPF_XRGB;
    130 		}
    131 		else
    132 		{
    133 			if(flags&TJ_BGR) return TJPF_BGRX;
    134 			else return TJPF_RGBX;
    135 		}
    136 	}
    137 	return -1;
    138 }
    139 
    140 static int setCompDefaults(struct jpeg_compress_struct *cinfo,
    141 	int pixelFormat, int subsamp, int jpegQual)
    142 {
    143 	int retval=0;
    144 
    145 	switch(pixelFormat)
    146 	{
    147 		case TJPF_GRAY:
    148 			cinfo->in_color_space=JCS_GRAYSCALE;  break;
    149 		#if JCS_EXTENSIONS==1
    150 		case TJPF_RGB:
    151 			cinfo->in_color_space=JCS_EXT_RGB;  break;
    152 		case TJPF_BGR:
    153 			cinfo->in_color_space=JCS_EXT_BGR;  break;
    154 		case TJPF_RGBX:
    155 		case TJPF_RGBA:
    156 			cinfo->in_color_space=JCS_EXT_RGBX;  break;
    157 		case TJPF_BGRX:
    158 		case TJPF_BGRA:
    159 			cinfo->in_color_space=JCS_EXT_BGRX;  break;
    160 		case TJPF_XRGB:
    161 		case TJPF_ARGB:
    162 			cinfo->in_color_space=JCS_EXT_XRGB;  break;
    163 		case TJPF_XBGR:
    164 		case TJPF_ABGR:
    165 			cinfo->in_color_space=JCS_EXT_XBGR;  break;
    166 		#else
    167 		case TJPF_RGB:
    168 		case TJPF_BGR:
    169 		case TJPF_RGBX:
    170 		case TJPF_BGRX:
    171 		case TJPF_XRGB:
    172 		case TJPF_XBGR:
    173 		case TJPF_RGBA:
    174 		case TJPF_BGRA:
    175 		case TJPF_ARGB:
    176 		case TJPF_ABGR:
    177 			cinfo->in_color_space=JCS_RGB;  pixelFormat=TJPF_RGB;
    178 			break;
    179 		#endif
    180 	}
    181 
    182 	cinfo->input_components=tjPixelSize[pixelFormat];
    183 	jpeg_set_defaults(cinfo);
    184 	if(jpegQual>=0)
    185 	{
    186 		jpeg_set_quality(cinfo, jpegQual, TRUE);
    187 		if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW;
    188 		else cinfo->dct_method=JDCT_FASTEST;
    189 	}
    190 	if(subsamp==TJSAMP_GRAY)
    191 		jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
    192 	else
    193 		jpeg_set_colorspace(cinfo, JCS_YCbCr);
    194 
    195 	cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
    196 	cinfo->comp_info[1].h_samp_factor=1;
    197 	cinfo->comp_info[2].h_samp_factor=1;
    198 	cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
    199 	cinfo->comp_info[1].v_samp_factor=1;
    200 	cinfo->comp_info[2].v_samp_factor=1;
    201 
    202 	return retval;
    203 }
    204 
    205 static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
    206 	int pixelFormat)
    207 {
    208 	int retval=0;
    209 
    210 	switch(pixelFormat)
    211 	{
    212 		case TJPF_GRAY:
    213 			dinfo->out_color_space=JCS_GRAYSCALE;  break;
    214 		#if JCS_EXTENSIONS==1
    215 		case TJPF_RGB:
    216 			dinfo->out_color_space=JCS_EXT_RGB;  break;
    217 		case TJPF_BGR:
    218 			dinfo->out_color_space=JCS_EXT_BGR;  break;
    219 		case TJPF_RGBX:
    220 			dinfo->out_color_space=JCS_EXT_RGBX;  break;
    221 		case TJPF_BGRX:
    222 			dinfo->out_color_space=JCS_EXT_BGRX;  break;
    223 		case TJPF_XRGB:
    224 			dinfo->out_color_space=JCS_EXT_XRGB;  break;
    225 		case TJPF_XBGR:
    226 			dinfo->out_color_space=JCS_EXT_XBGR;  break;
    227 		#if JCS_ALPHA_EXTENSIONS==1
    228 		case TJPF_RGBA:
    229 			dinfo->out_color_space=JCS_EXT_RGBA;  break;
    230 		case TJPF_BGRA:
    231 			dinfo->out_color_space=JCS_EXT_BGRA;  break;
    232 		case TJPF_ARGB:
    233 			dinfo->out_color_space=JCS_EXT_ARGB;  break;
    234 		case TJPF_ABGR:
    235 			dinfo->out_color_space=JCS_EXT_ABGR;  break;
    236 		#endif
    237 		#else
    238 		case TJPF_RGB:
    239 		case TJPF_BGR:
    240 		case TJPF_RGBX:
    241 		case TJPF_BGRX:
    242 		case TJPF_XRGB:
    243 		case TJPF_XBGR:
    244 		case TJPF_RGBA:
    245 		case TJPF_BGRA:
    246 		case TJPF_ARGB:
    247 		case TJPF_ABGR:
    248 			dinfo->out_color_space=JCS_RGB;  break;
    249 		#endif
    250 		default:
    251 			_throw("Unsupported pixel format");
    252 	}
    253 
    254 	bailout:
    255 	return retval;
    256 }
    257 
    258 
    259 static int getSubsamp(j_decompress_ptr dinfo)
    260 {
    261 	int retval=-1, i, k;
    262 	for(i=0; i<NUMSUBOPT; i++)
    263 	{
    264 		if(dinfo->num_components==pixelsize[i])
    265 		{
    266 			if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
    267 				&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
    268 			{
    269 				int match=0;
    270 				for(k=1; k<dinfo->num_components; k++)
    271 				{
    272 					if(dinfo->comp_info[k].h_samp_factor==1
    273 						&& dinfo->comp_info[k].v_samp_factor==1)
    274 						match++;
    275 				}
    276 				if(match==dinfo->num_components-1)
    277 				{
    278 					retval=i;  break;
    279 				}
    280 			}
    281 		}
    282 	}
    283 	return retval;
    284 }
    285 
    286 
    287 #ifndef JCS_EXTENSIONS
    288 
    289 /* Conversion functions to emulate the colorspace extensions.  This allows the
    290    TurboJPEG wrapper to be used with libjpeg */
    291 
    292 #define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
    293 	int rowPad=pitch-width*PS;  \
    294 	while(height--)  \
    295 	{  \
    296 		unsigned char *endOfRow=src+width*PS;  \
    297 		while(src<endOfRow)  \
    298 		{  \
    299 			dst[RGB_RED]=src[ROFFSET];  \
    300 			dst[RGB_GREEN]=src[GOFFSET];  \
    301 			dst[RGB_BLUE]=src[BOFFSET];  \
    302 			dst+=RGB_PIXELSIZE;  src+=PS;  \
    303 		}  \
    304 		src+=rowPad;  \
    305 	}  \
    306 }
    307 
    308 static unsigned char *toRGB(unsigned char *src, int width, int pitch,
    309 	int height, int pixelFormat, unsigned char *dst)
    310 {
    311 	unsigned char *retval=src;
    312 	switch(pixelFormat)
    313 	{
    314 		case TJPF_RGB:
    315 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
    316 			retval=dst;  TORGB(3, 0, 1, 2);
    317 			#endif
    318 			break;
    319 		case TJPF_BGR:
    320 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
    321 			retval=dst;  TORGB(3, 2, 1, 0);
    322 			#endif
    323 			break;
    324 		case TJPF_RGBX:
    325 		case TJPF_RGBA:
    326 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
    327 			retval=dst;  TORGB(4, 0, 1, 2);
    328 			#endif
    329 			break;
    330 		case TJPF_BGRX:
    331 		case TJPF_BGRA:
    332 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
    333 			retval=dst;  TORGB(4, 2, 1, 0);
    334 			#endif
    335 			break;
    336 		case TJPF_XRGB:
    337 		case TJPF_ARGB:
    338 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
    339 			retval=dst;  TORGB(4, 1, 2, 3);
    340 			#endif
    341 			break;
    342 		case TJPF_XBGR:
    343 		case TJPF_ABGR:
    344 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
    345 			retval=dst;  TORGB(4, 3, 2, 1);
    346 			#endif
    347 			break;
    348 	}
    349 	return retval;
    350 }
    351 
    352 #define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) {  \
    353 	int rowPad=pitch-width*PS;  \
    354 	while(height--)  \
    355 	{  \
    356 		unsigned char *endOfRow=dst+width*PS;  \
    357 		while(dst<endOfRow)  \
    358 		{  \
    359 			dst[ROFFSET]=src[RGB_RED];  \
    360 			dst[GOFFSET]=src[RGB_GREEN];  \
    361 			dst[BOFFSET]=src[RGB_BLUE];  \
    362 			SETALPHA  \
    363 			dst+=PS;  src+=RGB_PIXELSIZE;  \
    364 		}  \
    365 		dst+=rowPad;  \
    366 	}  \
    367 }
    368 
    369 static void fromRGB(unsigned char *src, unsigned char *dst, int width,
    370 	int pitch, int height, int pixelFormat)
    371 {
    372 	switch(pixelFormat)
    373 	{
    374 		case TJPF_RGB:
    375 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
    376 			FROMRGB(3, 0, 1, 2,);
    377 			#endif
    378 			break;
    379 		case TJPF_BGR:
    380 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
    381 			FROMRGB(3, 2, 1, 0,);
    382 			#endif
    383 			break;
    384 		case TJPF_RGBX:
    385 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
    386 			FROMRGB(4, 0, 1, 2,);
    387 			#endif
    388 			break;
    389 		case TJPF_RGBA:
    390 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
    391 			FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
    392 			#endif
    393 			break;
    394 		case TJPF_BGRX:
    395 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
    396 			FROMRGB(4, 2, 1, 0,);
    397 			#endif
    398 			break;
    399 		case TJPF_BGRA:
    400 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
    401 			FROMRGB(4, 2, 1, 0, dst[3]=0xFF;);  return;
    402 			#endif
    403 			break;
    404 		case TJPF_XRGB:
    405 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
    406 			FROMRGB(4, 1, 2, 3,);  return;
    407 			#endif
    408 			break;
    409 		case TJPF_ARGB:
    410 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
    411 			FROMRGB(4, 1, 2, 3, dst[0]=0xFF;);  return;
    412 			#endif
    413 			break;
    414 		case TJPF_XBGR:
    415 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
    416 			FROMRGB(4, 3, 2, 1,);  return;
    417 			#endif
    418 			break;
    419 		case TJPF_ABGR:
    420 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
    421 			FROMRGB(4, 3, 2, 1, dst[0]=0xFF;);  return;
    422 			#endif
    423 			break;
    424 	}
    425 }
    426 
    427 #endif
    428 
    429 
    430 /* General API functions */
    431 
    432 DLLEXPORT char* DLLCALL tjGetErrorStr(void)
    433 {
    434 	return errStr;
    435 }
    436 
    437 
    438 DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
    439 {
    440 	getinstance(handle);
    441 	if(setjmp(this->jerr.setjmp_buffer)) return -1;
    442 	if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
    443 	if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
    444 	free(this);
    445 	return 0;
    446 }
    447 
    448 
    449 /* Compressor  */
    450 
    451 static boolean empty_output_buffer(j_compress_ptr cinfo)
    452 {
    453 	ERREXIT(cinfo, JERR_BUFFER_SIZE);
    454 	return TRUE;
    455 }
    456 
    457 static void dst_noop(j_compress_ptr cinfo)
    458 {
    459 }
    460 
    461 static tjhandle _tjInitCompress(tjinstance *this)
    462 {
    463 	/* This is also straight out of example.c */
    464 	this->cinfo.err=jpeg_std_error(&this->jerr.pub);
    465 	this->jerr.pub.error_exit=my_error_exit;
    466 	this->jerr.pub.output_message=my_output_message;
    467 
    468 	if(setjmp(this->jerr.setjmp_buffer))
    469 	{
    470 		/* If we get here, the JPEG code has signaled an error. */
    471 		if(this) free(this);  return NULL;
    472 	}
    473 
    474 	jpeg_create_compress(&this->cinfo);
    475 	this->cinfo.dest=&this->jdst;
    476 	this->jdst.init_destination=dst_noop;
    477 	this->jdst.empty_output_buffer=empty_output_buffer;
    478 	this->jdst.term_destination=dst_noop;
    479 
    480 	this->init|=COMPRESS;
    481 	return (tjhandle)this;
    482 }
    483 
    484 DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
    485 {
    486 	tjinstance *this=NULL;
    487 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
    488 	{
    489 		snprintf(errStr, JMSG_LENGTH_MAX,
    490 			"tjInitCompress(): Memory allocation failure");
    491 		return NULL;
    492 	}
    493 	MEMZERO(this, sizeof(tjinstance));
    494 	return _tjInitCompress(this);
    495 }
    496 
    497 
    498 DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
    499 	int jpegSubsamp)
    500 {
    501 	unsigned long retval=0;  int mcuw, mcuh, chromasf;
    502 	if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
    503 		_throw("tjBufSize(): Invalid argument");
    504 
    505 	// This allows for rare corner cases in which a JPEG image can actually be
    506 	// larger than the uncompressed input (we wouldn't mention it if it hadn't
    507 	// happened before.)
    508 	mcuw=tjMCUWidth[jpegSubsamp];
    509 	mcuh=tjMCUHeight[jpegSubsamp];
    510 	chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
    511 	retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
    512 
    513 	bailout:
    514 	return retval;
    515 }
    516 
    517 
    518 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
    519 {
    520 	unsigned long retval=0;
    521 	if(width<1 || height<1)
    522 		_throw("TJBUFSIZE(): Invalid argument");
    523 
    524 	// This allows for rare corner cases in which a JPEG image can actually be
    525 	// larger than the uncompressed input (we wouldn't mention it if it hadn't
    526 	// happened before.)
    527 	retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
    528 
    529 	bailout:
    530 	return retval;
    531 }
    532 
    533 
    534 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
    535 	int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
    536 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
    537 {
    538 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
    539 	#ifndef JCS_EXTENSIONS
    540 	unsigned char *rgbBuf=NULL;
    541 	#endif
    542 
    543 	getinstance(handle)
    544 	if((this->init&COMPRESS)==0)
    545 		_throw("tjCompress2(): Instance has not been initialized for compression");
    546 
    547 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
    548 		|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
    549 		|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
    550 		_throw("tjCompress2(): Invalid argument");
    551 
    552 	if(setjmp(this->jerr.setjmp_buffer))
    553 	{
    554 		/* If we get here, the JPEG code has signaled an error. */
    555 		retval=-1;
    556 		goto bailout;
    557 	}
    558 
    559 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
    560 
    561 	#ifndef JCS_EXTENSIONS
    562 	if(pixelFormat!=TJPF_GRAY)
    563 	{
    564 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
    565 		if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
    566 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
    567 		pitch=width*RGB_PIXELSIZE;
    568 	}
    569 	#endif
    570 
    571 	cinfo->image_width=width;
    572 	cinfo->image_height=height;
    573 
    574 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    575 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
    576 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    577 
    578 	if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1)
    579 		return -1;
    580 
    581 	this->jdst.next_output_byte=*jpegBuf;
    582 	this->jdst.free_in_buffer=tjBufSize(width, height, jpegSubsamp);
    583 
    584 	jpeg_start_compress(cinfo, TRUE);
    585 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
    586 		_throw("tjCompress2(): Memory allocation failure");
    587 	for(i=0; i<height; i++)
    588 	{
    589 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
    590 		else row_pointer[i]=&srcBuf[i*pitch];
    591 	}
    592 	while(cinfo->next_scanline<cinfo->image_height)
    593 	{
    594 		jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
    595 			cinfo->image_height-cinfo->next_scanline);
    596 	}
    597 	jpeg_finish_compress(cinfo);
    598  	*jpegSize=tjBufSize(width, height, jpegSubsamp)
    599 		-(unsigned long)(this->jdst.free_in_buffer);
    600 
    601 	bailout:
    602 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
    603 	#ifndef JCS_EXTENSIONS
    604 	if(rgbBuf) free(rgbBuf);
    605 	#endif
    606 	if(row_pointer) free(row_pointer);
    607 	return retval;
    608 }
    609 
    610 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
    611 	int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
    612 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
    613 {
    614 	int retval=0;  unsigned long size;
    615 	retval=tjCompress2(handle, srcBuf, width, pitch, height,
    616 		getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
    617 		flags);
    618 	*jpegSize=size;
    619 	return retval;
    620 }
    621 
    622 
    623 /* Decompressor */
    624 
    625 static boolean fill_input_buffer(j_decompress_ptr dinfo)
    626 {
    627 	ERREXIT(dinfo, JERR_BUFFER_SIZE);
    628 	return TRUE;
    629 }
    630 
    631 static void skip_input_data(j_decompress_ptr dinfo, long num_bytes)
    632 {
    633 	dinfo->src->next_input_byte += (size_t) num_bytes;
    634 	dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
    635 }
    636 
    637 static void src_noop(j_decompress_ptr dinfo)
    638 {
    639 }
    640 
    641 static tjhandle _tjInitDecompress(tjinstance *this)
    642 {
    643 	/* This is also straight out of example.c */
    644 	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
    645 	this->jerr.pub.error_exit=my_error_exit;
    646 	this->jerr.pub.output_message=my_output_message;
    647 
    648 	if(setjmp(this->jerr.setjmp_buffer))
    649 	{
    650 		/* If we get here, the JPEG code has signaled an error. */
    651 		if(this) free(this);  return NULL;
    652 	}
    653 
    654 	jpeg_create_decompress(&this->dinfo);
    655 	this->dinfo.src=&this->jsrc;
    656 	this->jsrc.init_source=src_noop;
    657 	this->jsrc.fill_input_buffer=fill_input_buffer;
    658 	this->jsrc.skip_input_data=skip_input_data;
    659 	this->jsrc.resync_to_restart=jpeg_resync_to_restart;
    660 	this->jsrc.term_source=src_noop;
    661 
    662 	this->init|=DECOMPRESS;
    663 	return (tjhandle)this;
    664 }
    665 
    666 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
    667 {
    668 	tjinstance *this;
    669 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
    670 	{
    671 		snprintf(errStr, JMSG_LENGTH_MAX,
    672 			"tjInitDecompress(): Memory allocation failure");
    673 		return NULL;
    674 	}
    675 	MEMZERO(this, sizeof(tjinstance));
    676 	return _tjInitDecompress(this);
    677 }
    678 
    679 
    680 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
    681 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
    682 	int *jpegSubsamp)
    683 {
    684 	int retval=0;
    685 
    686 	getinstance(handle);
    687 	if((this->init&DECOMPRESS)==0)
    688 		_throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
    689 
    690 	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
    691 		|| jpegSubsamp==NULL)
    692 		_throw("tjDecompressHeader2(): Invalid argument");
    693 
    694 	if(setjmp(this->jerr.setjmp_buffer))
    695 	{
    696 		/* If we get here, the JPEG code has signaled an error. */
    697 		return -1;
    698 	}
    699 
    700 	this->jsrc.bytes_in_buffer=jpegSize;
    701 	this->jsrc.next_input_byte=jpegBuf;
    702 	jpeg_read_header(dinfo, TRUE);
    703 
    704 	*width=dinfo->image_width;
    705 	*height=dinfo->image_height;
    706 	*jpegSubsamp=getSubsamp(dinfo);
    707 
    708 	jpeg_abort_decompress(dinfo);
    709 
    710 	if(*jpegSubsamp<0)
    711 		_throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
    712 	if(*width<1 || *height<1)
    713 		_throw("tjDecompressHeader2(): Invalid data returned in header");
    714 
    715 	bailout:
    716 	return retval;
    717 }
    718 
    719 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
    720 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
    721 {
    722 	int jpegSubsamp;
    723 	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
    724 		&jpegSubsamp);
    725 }
    726 
    727 
    728 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
    729 {
    730 	if(numscalingfactors==NULL)
    731 	{
    732 		snprintf(errStr, JMSG_LENGTH_MAX,
    733 			"tjGetScalingFactors(): Invalid argument");
    734 		return NULL;
    735 	}
    736 
    737 	*numscalingfactors=NUMSF;
    738 	return (tjscalingfactor *)sf;
    739 }
    740 
    741 
    742 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
    743 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
    744 	int height, int pixelFormat, int flags)
    745 {
    746 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
    747 	int jpegwidth, jpegheight, scaledw, scaledh;
    748 	#ifndef JCS_EXTENSIONS
    749 	unsigned char *rgbBuf=NULL;
    750 	unsigned char *_dstBuf=NULL;  int _pitch=0;
    751 	#endif
    752 
    753 	getinstance(handle);
    754 	if((this->init&DECOMPRESS)==0)
    755 		_throw("tjDecompress2(): Instance has not been initialized for decompression");
    756 
    757 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
    758 		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
    759 		_throw("tjDecompress2(): Invalid argument");
    760 
    761 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    762 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
    763 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    764 
    765 	if(setjmp(this->jerr.setjmp_buffer))
    766 	{
    767 		/* If we get here, the JPEG code has signaled an error. */
    768 		retval=-1;
    769 		goto bailout;
    770 	}
    771 
    772 	this->jsrc.bytes_in_buffer=jpegSize;
    773 	this->jsrc.next_input_byte=jpegBuf;
    774 	jpeg_read_header(dinfo, TRUE);
    775 	if(setDecompDefaults(dinfo, pixelFormat)==-1)
    776 	{
    777 		retval=-1;  goto bailout;
    778 	}
    779 
    780 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
    781 
    782 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
    783 	if(width==0) width=jpegwidth;
    784 	if(height==0) height=jpegheight;
    785 	for(i=0; i<NUMSF; i++)
    786 	{
    787 		scaledw=TJSCALED(jpegwidth, sf[i]);
    788 		scaledh=TJSCALED(jpegheight, sf[i]);
    789 		if(scaledw<=width && scaledh<=height)
    790 				break;
    791 	}
    792 	if(scaledw>width || scaledh>height)
    793 		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
    794 	width=scaledw;  height=scaledh;
    795 	dinfo->scale_num=sf[i].num;
    796 	dinfo->scale_denom=sf[i].denom;
    797 
    798 	jpeg_start_decompress(dinfo);
    799 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
    800 
    801 	#ifndef JCS_EXTENSIONS
    802 	if(pixelFormat!=TJPF_GRAY &&
    803 		(RGB_RED!=tjRedOffset[pixelFormat] ||
    804 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
    805 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
    806 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
    807 	{
    808 		rgbBuf=(unsigned char *)malloc(width*height*3);
    809 		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
    810 		_pitch=pitch;  pitch=width*3;
    811 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
    812 	}
    813 	#endif
    814 
    815 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
    816 		*dinfo->output_height))==NULL)
    817 		_throw("tjDecompress2(): Memory allocation failure");
    818 	for(i=0; i<(int)dinfo->output_height; i++)
    819 	{
    820 		if(flags&TJFLAG_BOTTOMUP)
    821 			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
    822 		else row_pointer[i]=&dstBuf[i*pitch];
    823 	}
    824 	while(dinfo->output_scanline<dinfo->output_height)
    825 	{
    826 		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
    827 			dinfo->output_height-dinfo->output_scanline);
    828 	}
    829 	jpeg_finish_decompress(dinfo);
    830 
    831 	#ifndef JCS_EXTENSIONS
    832 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
    833 	#endif
    834 
    835 	bailout:
    836 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
    837 	#ifndef JCS_EXTENSIONS
    838 	if(rgbBuf) free(rgbBuf);
    839 	#endif
    840 	if(row_pointer) free(row_pointer);
    841 	return retval;
    842 }
    843 
    844 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
    845 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
    846 	int height, int pixelSize, int flags)
    847 {
    848 	return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
    849 		height, getPixelFormat(pixelSize, flags), flags);
    850 }
    851