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 	/*
    506 	 * This allows for rare corner cases in which a JPEG image can actually be
    507 	 * larger than the uncompressed input (we wouldn't mention it if it hadn't
    508 	 * happened before.)
    509 	 */
    510 	mcuw=tjMCUWidth[jpegSubsamp];
    511 	mcuh=tjMCUHeight[jpegSubsamp];
    512 	chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
    513 	retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
    514 
    515 	bailout:
    516 	return retval;
    517 }
    518 
    519 
    520 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
    521 {
    522 	unsigned long retval=0;
    523 	if(width<1 || height<1)
    524 		_throw("TJBUFSIZE(): Invalid argument");
    525 
    526 	/*
    527 	 * This allows for rare corner cases in which a JPEG image can actually be
    528 	 * larger than the uncompressed input (we wouldn't mention it if it hadn't
    529 	 * happened before.)
    530 	 */
    531 	retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
    532 
    533 	bailout:
    534 	return retval;
    535 }
    536 
    537 
    538 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
    539 	int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
    540 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
    541 {
    542 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
    543 	#ifndef JCS_EXTENSIONS
    544 	unsigned char *rgbBuf=NULL;
    545 	#endif
    546 
    547 	getinstance(handle)
    548 	if((this->init&COMPRESS)==0)
    549 		_throw("tjCompress2(): Instance has not been initialized for compression");
    550 
    551 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
    552 		|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
    553 		|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
    554 		_throw("tjCompress2(): Invalid argument");
    555 
    556 	if(setjmp(this->jerr.setjmp_buffer))
    557 	{
    558 		/* If we get here, the JPEG code has signaled an error. */
    559 		retval=-1;
    560 		goto bailout;
    561 	}
    562 
    563 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
    564 
    565 	#ifndef JCS_EXTENSIONS
    566 	if(pixelFormat!=TJPF_GRAY)
    567 	{
    568 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
    569 		if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
    570 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
    571 		pitch=width*RGB_PIXELSIZE;
    572 	}
    573 	#endif
    574 
    575 	cinfo->image_width=width;
    576 	cinfo->image_height=height;
    577 
    578 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    579 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
    580 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    581 
    582 	if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1)
    583 		return -1;
    584 
    585 	this->jdst.next_output_byte=*jpegBuf;
    586 	this->jdst.free_in_buffer=tjBufSize(width, height, jpegSubsamp);
    587 
    588 	jpeg_start_compress(cinfo, TRUE);
    589 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
    590 		_throw("tjCompress2(): Memory allocation failure");
    591 	for(i=0; i<height; i++)
    592 	{
    593 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
    594 		else row_pointer[i]=&srcBuf[i*pitch];
    595 	}
    596 	while(cinfo->next_scanline<cinfo->image_height)
    597 	{
    598 		jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
    599 			cinfo->image_height-cinfo->next_scanline);
    600 	}
    601 	jpeg_finish_compress(cinfo);
    602  	*jpegSize=tjBufSize(width, height, jpegSubsamp)
    603 		-(unsigned long)(this->jdst.free_in_buffer);
    604 
    605 	bailout:
    606 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
    607 	#ifndef JCS_EXTENSIONS
    608 	if(rgbBuf) free(rgbBuf);
    609 	#endif
    610 	if(row_pointer) free(row_pointer);
    611 	return retval;
    612 }
    613 
    614 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
    615 	int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
    616 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
    617 {
    618 	int retval=0;  unsigned long size;
    619 	retval=tjCompress2(handle, srcBuf, width, pitch, height,
    620 		getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
    621 		flags);
    622 	*jpegSize=size;
    623 	return retval;
    624 }
    625 
    626 
    627 /* Decompressor */
    628 
    629 static boolean fill_input_buffer(j_decompress_ptr dinfo)
    630 {
    631 	ERREXIT(dinfo, JERR_BUFFER_SIZE);
    632 	return TRUE;
    633 }
    634 
    635 static void skip_input_data(j_decompress_ptr dinfo, long num_bytes)
    636 {
    637 	dinfo->src->next_input_byte += (size_t) num_bytes;
    638 	dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
    639 }
    640 
    641 static void src_noop(j_decompress_ptr dinfo)
    642 {
    643 }
    644 
    645 static tjhandle _tjInitDecompress(tjinstance *this)
    646 {
    647 	/* This is also straight out of example.c */
    648 	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
    649 	this->jerr.pub.error_exit=my_error_exit;
    650 	this->jerr.pub.output_message=my_output_message;
    651 
    652 	if(setjmp(this->jerr.setjmp_buffer))
    653 	{
    654 		/* If we get here, the JPEG code has signaled an error. */
    655 		if(this) free(this);  return NULL;
    656 	}
    657 
    658 	jpeg_create_decompress(&this->dinfo);
    659 	this->dinfo.src=&this->jsrc;
    660 	this->jsrc.init_source=src_noop;
    661 	this->jsrc.fill_input_buffer=fill_input_buffer;
    662 	this->jsrc.skip_input_data=skip_input_data;
    663 	this->jsrc.resync_to_restart=jpeg_resync_to_restart;
    664 	this->jsrc.term_source=src_noop;
    665 
    666 	this->init|=DECOMPRESS;
    667 	return (tjhandle)this;
    668 }
    669 
    670 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
    671 {
    672 	tjinstance *this;
    673 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
    674 	{
    675 		snprintf(errStr, JMSG_LENGTH_MAX,
    676 			"tjInitDecompress(): Memory allocation failure");
    677 		return NULL;
    678 	}
    679 	MEMZERO(this, sizeof(tjinstance));
    680 	return _tjInitDecompress(this);
    681 }
    682 
    683 
    684 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
    685 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
    686 	int *jpegSubsamp)
    687 {
    688 	int retval=0;
    689 
    690 	getinstance(handle);
    691 	if((this->init&DECOMPRESS)==0)
    692 		_throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
    693 
    694 	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
    695 		|| jpegSubsamp==NULL)
    696 		_throw("tjDecompressHeader2(): Invalid argument");
    697 
    698 	if(setjmp(this->jerr.setjmp_buffer))
    699 	{
    700 		/* If we get here, the JPEG code has signaled an error. */
    701 		return -1;
    702 	}
    703 
    704 	this->jsrc.bytes_in_buffer=jpegSize;
    705 	this->jsrc.next_input_byte=jpegBuf;
    706 	jpeg_read_header(dinfo, TRUE);
    707 
    708 	*width=dinfo->image_width;
    709 	*height=dinfo->image_height;
    710 	*jpegSubsamp=getSubsamp(dinfo);
    711 
    712 	jpeg_abort_decompress(dinfo);
    713 
    714 	if(*jpegSubsamp<0)
    715 		_throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
    716 	if(*width<1 || *height<1)
    717 		_throw("tjDecompressHeader2(): Invalid data returned in header");
    718 
    719 	bailout:
    720 	return retval;
    721 }
    722 
    723 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
    724 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
    725 {
    726 	int jpegSubsamp;
    727 	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
    728 		&jpegSubsamp);
    729 }
    730 
    731 
    732 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
    733 {
    734 	if(numscalingfactors==NULL)
    735 	{
    736 		snprintf(errStr, JMSG_LENGTH_MAX,
    737 			"tjGetScalingFactors(): Invalid argument");
    738 		return NULL;
    739 	}
    740 
    741 	*numscalingfactors=NUMSF;
    742 	return (tjscalingfactor *)sf;
    743 }
    744 
    745 
    746 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
    747 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
    748 	int height, int pixelFormat, int flags)
    749 {
    750 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
    751 	int jpegwidth, jpegheight, scaledw, scaledh;
    752 	#ifndef JCS_EXTENSIONS
    753 	unsigned char *rgbBuf=NULL;
    754 	unsigned char *_dstBuf=NULL;  int _pitch=0;
    755 	#endif
    756 
    757 	getinstance(handle);
    758 	if((this->init&DECOMPRESS)==0)
    759 		_throw("tjDecompress2(): Instance has not been initialized for decompression");
    760 
    761 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
    762 		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
    763 		_throw("tjDecompress2(): Invalid argument");
    764 
    765 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    766 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
    767 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    768 
    769 	if(setjmp(this->jerr.setjmp_buffer))
    770 	{
    771 		/* If we get here, the JPEG code has signaled an error. */
    772 		retval=-1;
    773 		goto bailout;
    774 	}
    775 
    776 	this->jsrc.bytes_in_buffer=jpegSize;
    777 	this->jsrc.next_input_byte=jpegBuf;
    778 	jpeg_read_header(dinfo, TRUE);
    779 	if(setDecompDefaults(dinfo, pixelFormat)==-1)
    780 	{
    781 		retval=-1;  goto bailout;
    782 	}
    783 
    784 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
    785 
    786 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
    787 	if(width==0) width=jpegwidth;
    788 	if(height==0) height=jpegheight;
    789 	for(i=0; i<NUMSF; i++)
    790 	{
    791 		scaledw=TJSCALED(jpegwidth, sf[i]);
    792 		scaledh=TJSCALED(jpegheight, sf[i]);
    793 		if(scaledw<=width && scaledh<=height)
    794 				break;
    795 	}
    796 	if(scaledw>width || scaledh>height)
    797 		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
    798 	width=scaledw;  height=scaledh;
    799 	dinfo->scale_num=sf[i].num;
    800 	dinfo->scale_denom=sf[i].denom;
    801 
    802 	jpeg_start_decompress(dinfo);
    803 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
    804 
    805 	#ifndef JCS_EXTENSIONS
    806 	if(pixelFormat!=TJPF_GRAY &&
    807 		(RGB_RED!=tjRedOffset[pixelFormat] ||
    808 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
    809 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
    810 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
    811 	{
    812 		rgbBuf=(unsigned char *)malloc(width*height*3);
    813 		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
    814 		_pitch=pitch;  pitch=width*3;
    815 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
    816 	}
    817 	#endif
    818 
    819 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
    820 		*dinfo->output_height))==NULL)
    821 		_throw("tjDecompress2(): Memory allocation failure");
    822 	for(i=0; i<(int)dinfo->output_height; i++)
    823 	{
    824 		if(flags&TJFLAG_BOTTOMUP)
    825 			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
    826 		else row_pointer[i]=&dstBuf[i*pitch];
    827 	}
    828 	while(dinfo->output_scanline<dinfo->output_height)
    829 	{
    830 		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
    831 			dinfo->output_height-dinfo->output_scanline);
    832 	}
    833 	jpeg_finish_decompress(dinfo);
    834 
    835 	#ifndef JCS_EXTENSIONS
    836 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
    837 	#endif
    838 
    839 	bailout:
    840 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
    841 	#ifndef JCS_EXTENSIONS
    842 	if(rgbBuf) free(rgbBuf);
    843 	#endif
    844 	if(row_pointer) free(row_pointer);
    845 	return retval;
    846 }
    847 
    848 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
    849 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
    850 	int height, int pixelSize, int flags)
    851 {
    852 	return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
    853 		height, getPixelFormat(pixelSize, flags), flags);
    854 }
    855