Home | History | Annotate | Download | only in libjpeg_turbo
      1 /*
      2  * Copyright (C)2009-2012, 2014 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/LJT:  this implements the TurboJPEG API using libjpeg or
     30    libjpeg-turbo */
     31 
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <jinclude.h>
     35 #define JPEG_INTERNALS
     36 #include <jpeglib.h>
     37 #include <jerror.h>
     38 #include <setjmp.h>
     39 #include "./turbojpeg.h"
     40 #include "./tjutil.h"
     41 #include "transupp.h"
     42 
     43 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
     44 	unsigned long *, boolean);
     45 extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
     46 
     47 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
     48 
     49 
     50 /* Error handling (based on example in example.c) */
     51 
     52 static char errStr[JMSG_LENGTH_MAX]="No error";
     53 
     54 struct my_error_mgr
     55 {
     56 	struct jpeg_error_mgr pub;
     57 	jmp_buf setjmp_buffer;
     58 };
     59 typedef struct my_error_mgr *my_error_ptr;
     60 
     61 static void my_error_exit(j_common_ptr cinfo)
     62 {
     63 	my_error_ptr myerr=(my_error_ptr)cinfo->err;
     64 	(*cinfo->err->output_message)(cinfo);
     65 	longjmp(myerr->setjmp_buffer, 1);
     66 }
     67 
     68 /* Based on output_message() in jerror.c */
     69 
     70 static void my_output_message(j_common_ptr cinfo)
     71 {
     72 	(*cinfo->err->format_message)(cinfo, errStr);
     73 }
     74 
     75 
     76 /* Global structures, macros, etc. */
     77 
     78 enum {COMPRESS=1, DECOMPRESS=2};
     79 
     80 typedef struct _tjinstance
     81 {
     82 	struct jpeg_compress_struct cinfo;
     83 	struct jpeg_decompress_struct dinfo;
     84 	struct my_error_mgr jerr;
     85 	int init;
     86 } tjinstance;
     87 
     88 static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
     89 
     90 static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
     91 {
     92 	JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
     93 	JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
     94 };
     95 
     96 #define NUMSF 16
     97 static const tjscalingfactor sf[NUMSF]={
     98 	{2, 1},
     99 	{15, 8},
    100 	{7, 4},
    101 	{13, 8},
    102 	{3, 2},
    103 	{11, 8},
    104 	{5, 4},
    105 	{9, 8},
    106 	{1, 1},
    107 	{7, 8},
    108 	{3, 4},
    109 	{5, 8},
    110 	{1, 2},
    111 	{3, 8},
    112 	{1, 4},
    113 	{1, 8}
    114 };
    115 
    116 #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
    117 	retval=-1;  goto bailout;}
    118 #define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
    119 	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
    120 	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
    121 		return -1;}  \
    122 	cinfo=&this->cinfo;  dinfo=&this->dinfo;
    123 
    124 static int getPixelFormat(int pixelSize, int flags)
    125 {
    126 	if(pixelSize==1) return TJPF_GRAY;
    127 	if(pixelSize==3)
    128 	{
    129 		if(flags&TJ_BGR) return TJPF_BGR;
    130 		else return TJPF_RGB;
    131 	}
    132 	if(pixelSize==4)
    133 	{
    134 		if(flags&TJ_ALPHAFIRST)
    135 		{
    136 			if(flags&TJ_BGR) return TJPF_XBGR;
    137 			else return TJPF_XRGB;
    138 		}
    139 		else
    140 		{
    141 			if(flags&TJ_BGR) return TJPF_BGRX;
    142 			else return TJPF_RGBX;
    143 		}
    144 	}
    145 	return -1;
    146 }
    147 
    148 static int setCompDefaults(struct jpeg_compress_struct *cinfo,
    149 	int pixelFormat, int subsamp, int jpegQual, int flags)
    150 {
    151 	int retval=0;
    152 
    153 	switch(pixelFormat)
    154 	{
    155 		case TJPF_GRAY:
    156 			cinfo->in_color_space=JCS_GRAYSCALE;  break;
    157 		#if JCS_EXTENSIONS==1
    158 		case TJPF_RGB:
    159 			cinfo->in_color_space=JCS_EXT_RGB;  break;
    160 		case TJPF_BGR:
    161 			cinfo->in_color_space=JCS_EXT_BGR;  break;
    162 		case TJPF_RGBX:
    163 		case TJPF_RGBA:
    164 			cinfo->in_color_space=JCS_EXT_RGBX;  break;
    165 		case TJPF_BGRX:
    166 		case TJPF_BGRA:
    167 			cinfo->in_color_space=JCS_EXT_BGRX;  break;
    168 		case TJPF_XRGB:
    169 		case TJPF_ARGB:
    170 			cinfo->in_color_space=JCS_EXT_XRGB;  break;
    171 		case TJPF_XBGR:
    172 		case TJPF_ABGR:
    173 			cinfo->in_color_space=JCS_EXT_XBGR;  break;
    174 		#else
    175 		case TJPF_RGB:
    176 		case TJPF_BGR:
    177 		case TJPF_RGBX:
    178 		case TJPF_BGRX:
    179 		case TJPF_XRGB:
    180 		case TJPF_XBGR:
    181 		case TJPF_RGBA:
    182 		case TJPF_BGRA:
    183 		case TJPF_ARGB:
    184 		case TJPF_ABGR:
    185 			cinfo->in_color_space=JCS_RGB;  pixelFormat=TJPF_RGB;
    186 			break;
    187 		#endif
    188 	}
    189 
    190 	cinfo->input_components=tjPixelSize[pixelFormat];
    191 	jpeg_set_defaults(cinfo);
    192 	if(jpegQual>=0)
    193 	{
    194 		jpeg_set_quality(cinfo, jpegQual, TRUE);
    195 		if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
    196 		else cinfo->dct_method=JDCT_FASTEST;
    197 	}
    198 	if(subsamp==TJSAMP_GRAY)
    199 		jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
    200 	else
    201 		jpeg_set_colorspace(cinfo, JCS_YCbCr);
    202 
    203 	cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
    204 	cinfo->comp_info[1].h_samp_factor=1;
    205 	cinfo->comp_info[2].h_samp_factor=1;
    206 	cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
    207 	cinfo->comp_info[1].v_samp_factor=1;
    208 	cinfo->comp_info[2].v_samp_factor=1;
    209 
    210 	return retval;
    211 }
    212 
    213 static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
    214 	int pixelFormat, int flags)
    215 {
    216 	int retval=0;
    217 
    218 	switch(pixelFormat)
    219 	{
    220 		case TJPF_GRAY:
    221 			dinfo->out_color_space=JCS_GRAYSCALE;  break;
    222 		#if JCS_EXTENSIONS==1
    223 		case TJPF_RGB:
    224 			dinfo->out_color_space=JCS_EXT_RGB;  break;
    225 		case TJPF_BGR:
    226 			dinfo->out_color_space=JCS_EXT_BGR;  break;
    227 		case TJPF_RGBX:
    228 			dinfo->out_color_space=JCS_EXT_RGBX;  break;
    229 		case TJPF_BGRX:
    230 			dinfo->out_color_space=JCS_EXT_BGRX;  break;
    231 		case TJPF_XRGB:
    232 			dinfo->out_color_space=JCS_EXT_XRGB;  break;
    233 		case TJPF_XBGR:
    234 			dinfo->out_color_space=JCS_EXT_XBGR;  break;
    235 		#if JCS_ALPHA_EXTENSIONS==1
    236 		case TJPF_RGBA:
    237 			dinfo->out_color_space=JCS_EXT_RGBA;  break;
    238 		case TJPF_BGRA:
    239 			dinfo->out_color_space=JCS_EXT_BGRA;  break;
    240 		case TJPF_ARGB:
    241 			dinfo->out_color_space=JCS_EXT_ARGB;  break;
    242 		case TJPF_ABGR:
    243 			dinfo->out_color_space=JCS_EXT_ABGR;  break;
    244 		#endif
    245 		#else
    246 		case TJPF_RGB:
    247 		case TJPF_BGR:
    248 		case TJPF_RGBX:
    249 		case TJPF_BGRX:
    250 		case TJPF_XRGB:
    251 		case TJPF_XBGR:
    252 		case TJPF_RGBA:
    253 		case TJPF_BGRA:
    254 		case TJPF_ARGB:
    255 		case TJPF_ABGR:
    256 			dinfo->out_color_space=JCS_RGB;  break;
    257 		#endif
    258 		default:
    259 			_throw("Unsupported pixel format");
    260 	}
    261 
    262 	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
    263 
    264 	bailout:
    265 	return retval;
    266 }
    267 
    268 
    269 static int getSubsamp(j_decompress_ptr dinfo)
    270 {
    271 	int retval=-1, i, k;
    272 	for(i=0; i<NUMSUBOPT; i++)
    273 	{
    274 		if(dinfo->num_components==pixelsize[i])
    275 		{
    276 			if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
    277 				&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
    278 			{
    279 				int match=0;
    280 				for(k=1; k<dinfo->num_components; k++)
    281 				{
    282 					if(dinfo->comp_info[k].h_samp_factor==1
    283 						&& dinfo->comp_info[k].v_samp_factor==1)
    284 						match++;
    285 				}
    286 				if(match==dinfo->num_components-1)
    287 				{
    288 					retval=i;  break;
    289 				}
    290 			}
    291 		}
    292 	}
    293 	return retval;
    294 }
    295 
    296 
    297 #ifndef JCS_EXTENSIONS
    298 
    299 /* Conversion functions to emulate the colorspace extensions.  This allows the
    300    TurboJPEG wrapper to be used with libjpeg */
    301 
    302 #define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
    303 	int rowPad=pitch-width*PS;  \
    304 	while(height--)  \
    305 	{  \
    306 		unsigned char *endOfRow=src+width*PS;  \
    307 		while(src<endOfRow)  \
    308 		{  \
    309 			dst[RGB_RED]=src[ROFFSET];  \
    310 			dst[RGB_GREEN]=src[GOFFSET];  \
    311 			dst[RGB_BLUE]=src[BOFFSET];  \
    312 			dst+=RGB_PIXELSIZE;  src+=PS;  \
    313 		}  \
    314 		src+=rowPad;  \
    315 	}  \
    316 }
    317 
    318 static unsigned char *toRGB(unsigned char *src, int width, int pitch,
    319 	int height, int pixelFormat, unsigned char *dst)
    320 {
    321 	unsigned char *retval=src;
    322 	switch(pixelFormat)
    323 	{
    324 		case TJPF_RGB:
    325 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
    326 			retval=dst;  TORGB(3, 0, 1, 2);
    327 			#endif
    328 			break;
    329 		case TJPF_BGR:
    330 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
    331 			retval=dst;  TORGB(3, 2, 1, 0);
    332 			#endif
    333 			break;
    334 		case TJPF_RGBX:
    335 		case TJPF_RGBA:
    336 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
    337 			retval=dst;  TORGB(4, 0, 1, 2);
    338 			#endif
    339 			break;
    340 		case TJPF_BGRX:
    341 		case TJPF_BGRA:
    342 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
    343 			retval=dst;  TORGB(4, 2, 1, 0);
    344 			#endif
    345 			break;
    346 		case TJPF_XRGB:
    347 		case TJPF_ARGB:
    348 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
    349 			retval=dst;  TORGB(4, 1, 2, 3);
    350 			#endif
    351 			break;
    352 		case TJPF_XBGR:
    353 		case TJPF_ABGR:
    354 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
    355 			retval=dst;  TORGB(4, 3, 2, 1);
    356 			#endif
    357 			break;
    358 	}
    359 	return retval;
    360 }
    361 
    362 #define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) {  \
    363 	int rowPad=pitch-width*PS;  \
    364 	while(height--)  \
    365 	{  \
    366 		unsigned char *endOfRow=dst+width*PS;  \
    367 		while(dst<endOfRow)  \
    368 		{  \
    369 			dst[ROFFSET]=src[RGB_RED];  \
    370 			dst[GOFFSET]=src[RGB_GREEN];  \
    371 			dst[BOFFSET]=src[RGB_BLUE];  \
    372 			SETALPHA  \
    373 			dst+=PS;  src+=RGB_PIXELSIZE;  \
    374 		}  \
    375 		dst+=rowPad;  \
    376 	}  \
    377 }
    378 
    379 static void fromRGB(unsigned char *src, unsigned char *dst, int width,
    380 	int pitch, int height, int pixelFormat)
    381 {
    382 	switch(pixelFormat)
    383 	{
    384 		case TJPF_RGB:
    385 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
    386 			FROMRGB(3, 0, 1, 2,);
    387 			#endif
    388 			break;
    389 		case TJPF_BGR:
    390 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
    391 			FROMRGB(3, 2, 1, 0,);
    392 			#endif
    393 			break;
    394 		case TJPF_RGBX:
    395 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
    396 			FROMRGB(4, 0, 1, 2,);
    397 			#endif
    398 			break;
    399 		case TJPF_RGBA:
    400 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
    401 			FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
    402 			#endif
    403 			break;
    404 		case TJPF_BGRX:
    405 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
    406 			FROMRGB(4, 2, 1, 0,);
    407 			#endif
    408 			break;
    409 		case TJPF_BGRA:
    410 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
    411 			FROMRGB(4, 2, 1, 0, dst[3]=0xFF;);  return;
    412 			#endif
    413 			break;
    414 		case TJPF_XRGB:
    415 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
    416 			FROMRGB(4, 1, 2, 3,);  return;
    417 			#endif
    418 			break;
    419 		case TJPF_ARGB:
    420 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
    421 			FROMRGB(4, 1, 2, 3, dst[0]=0xFF;);  return;
    422 			#endif
    423 			break;
    424 		case TJPF_XBGR:
    425 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
    426 			FROMRGB(4, 3, 2, 1,);  return;
    427 			#endif
    428 			break;
    429 		case TJPF_ABGR:
    430 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
    431 			FROMRGB(4, 3, 2, 1, dst[0]=0xFF;);  return;
    432 			#endif
    433 			break;
    434 	}
    435 }
    436 
    437 #endif
    438 
    439 
    440 /* General API functions */
    441 
    442 DLLEXPORT char* DLLCALL tjGetErrorStr(void)
    443 {
    444 	return errStr;
    445 }
    446 
    447 
    448 DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
    449 {
    450 	getinstance(handle);
    451 	if(setjmp(this->jerr.setjmp_buffer)) return -1;
    452 	if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
    453 	if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
    454 	free(this);
    455 	return 0;
    456 }
    457 
    458 
    459 /* These are exposed mainly because Windows can't malloc() and free() across
    460    DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
    461    with turbojpeg.dll for compatibility reasons.  However, these functions
    462    can potentially be used for other purposes by different implementations. */
    463 
    464 DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
    465 {
    466 	if(buf) free(buf);
    467 }
    468 
    469 
    470 DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
    471 {
    472 	return (unsigned char *)malloc(bytes);
    473 }
    474 
    475 
    476 /* Compressor  */
    477 
    478 static tjhandle _tjInitCompress(tjinstance *this)
    479 {
    480 	unsigned char buffer[1], *buf=buffer;  unsigned long size=1;
    481 
    482 	/* This is also straight out of example.c */
    483 	this->cinfo.err=jpeg_std_error(&this->jerr.pub);
    484 	this->jerr.pub.error_exit=my_error_exit;
    485 	this->jerr.pub.output_message=my_output_message;
    486 
    487 	if(setjmp(this->jerr.setjmp_buffer))
    488 	{
    489 		/* If we get here, the JPEG code has signaled an error. */
    490 		if(this) free(this);  return NULL;
    491 	}
    492 
    493 	jpeg_create_compress(&this->cinfo);
    494 	/* Make an initial call so it will create the destination manager */
    495 	jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
    496 
    497 	this->init|=COMPRESS;
    498 	return (tjhandle)this;
    499 }
    500 
    501 DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
    502 {
    503 	tjinstance *this=NULL;
    504 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
    505 	{
    506 		snprintf(errStr, JMSG_LENGTH_MAX,
    507 			"tjInitCompress(): Memory allocation failure");
    508 		return NULL;
    509 	}
    510 	MEMZERO(this, sizeof(tjinstance));
    511 	return _tjInitCompress(this);
    512 }
    513 
    514 
    515 DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
    516 	int jpegSubsamp)
    517 {
    518 	unsigned long retval=0;  int mcuw, mcuh, chromasf;
    519 	if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
    520 		_throw("tjBufSize(): Invalid argument");
    521 
    522 	/* This allows for rare corner cases in which a JPEG image can actually be
    523 	   larger than the uncompressed input (we wouldn't mention it if it hadn't
    524 	   happened before.) */
    525 	mcuw=tjMCUWidth[jpegSubsamp];
    526 	mcuh=tjMCUHeight[jpegSubsamp];
    527 	chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
    528 	retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
    529 
    530 	bailout:
    531 	return retval;
    532 }
    533 
    534 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
    535 {
    536 	unsigned long retval=0;
    537 	if(width<1 || height<1)
    538 		_throw("TJBUFSIZE(): Invalid argument");
    539 
    540 	/* This allows for rare corner cases in which a JPEG image can actually be
    541 	   larger than the uncompressed input (we wouldn't mention it if it hadn't
    542 	   happened before.) */
    543 	retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
    544 
    545 	bailout:
    546 	return retval;
    547 }
    548 
    549 
    550 DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
    551 	int subsamp)
    552 {
    553 	unsigned long retval=0;
    554 	int pw, ph, cw, ch;
    555 	if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
    556 		_throw("tjBufSizeYUV(): Invalid argument");
    557 	pw=PAD(width, tjMCUWidth[subsamp]/8);
    558 	ph=PAD(height, tjMCUHeight[subsamp]/8);
    559 	cw=pw*8/tjMCUWidth[subsamp];  ch=ph*8/tjMCUHeight[subsamp];
    560 	retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2);
    561 
    562 	bailout:
    563 	return retval;
    564 }
    565 
    566 
    567 DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
    568 	int subsamp)
    569 {
    570 	return tjBufSizeYUV(width, height, subsamp);
    571 }
    572 
    573 
    574 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
    575 	int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
    576 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
    577 {
    578 	int i, retval=0, alloc=1;  JSAMPROW *row_pointer=NULL;
    579 	#ifndef JCS_EXTENSIONS
    580 	unsigned char *rgbBuf=NULL;
    581 	#endif
    582 
    583 	getinstance(handle)
    584 	if((this->init&COMPRESS)==0)
    585 		_throw("tjCompress2(): Instance has not been initialized for compression");
    586 
    587 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
    588 		|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
    589 		|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
    590 		_throw("tjCompress2(): Invalid argument");
    591 
    592 	if(setjmp(this->jerr.setjmp_buffer))
    593 	{
    594 		/* If we get here, the JPEG code has signaled an error. */
    595 		retval=-1;
    596 		goto bailout;
    597 	}
    598 
    599 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
    600 
    601 	#ifndef JCS_EXTENSIONS
    602 	if(pixelFormat!=TJPF_GRAY)
    603 	{
    604 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
    605 		if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
    606 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
    607 		pitch=width*RGB_PIXELSIZE;
    608 	}
    609 	#endif
    610 
    611 	cinfo->image_width=width;
    612 	cinfo->image_height=height;
    613 
    614 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    615 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
    616 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    617 
    618 	if(flags&TJFLAG_NOREALLOC)
    619 	{
    620 		alloc=0;  *jpegSize=tjBufSize(width, height, jpegSubsamp);
    621 	}
    622 	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
    623 	if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
    624 		return -1;
    625 
    626 	jpeg_start_compress(cinfo, TRUE);
    627 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
    628 		_throw("tjCompress2(): Memory allocation failure");
    629 	for(i=0; i<height; i++)
    630 	{
    631 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
    632 		else row_pointer[i]=&srcBuf[i*pitch];
    633 	}
    634 	while(cinfo->next_scanline<cinfo->image_height)
    635 	{
    636 		jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
    637 			cinfo->image_height-cinfo->next_scanline);
    638 	}
    639 	jpeg_finish_compress(cinfo);
    640 
    641 	bailout:
    642 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
    643 	#ifndef JCS_EXTENSIONS
    644 	if(rgbBuf) free(rgbBuf);
    645 	#endif
    646 	if(row_pointer) free(row_pointer);
    647 	return retval;
    648 }
    649 
    650 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
    651 	int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
    652 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
    653 {
    654 	int retval=0;  unsigned long size;
    655 	if(flags&TJ_YUV)
    656 	{
    657 		size=tjBufSizeYUV(width, height, jpegSubsamp);
    658 		retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
    659 			getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
    660 	}
    661 	else
    662 	{
    663 		retval=tjCompress2(handle, srcBuf, width, pitch, height,
    664 			getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
    665 			flags|TJFLAG_NOREALLOC);
    666 	}
    667 	*jpegSize=size;
    668 	return retval;
    669 }
    670 
    671 
    672 DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
    673 	int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
    674 	int subsamp, int flags)
    675 {
    676 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
    677 	JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
    678 	JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
    679 	JSAMPROW *outbuf[MAX_COMPONENTS];
    680 	int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
    681 	JSAMPLE *ptr=dstBuf;
    682 	unsigned long yuvsize=0;
    683 	jpeg_component_info *compptr;
    684 	#ifndef JCS_EXTENSIONS
    685 	unsigned char *rgbBuf=NULL;
    686 	#endif
    687 
    688 	getinstance(handle);
    689 
    690 	for(i=0; i<MAX_COMPONENTS; i++)
    691 	{
    692 		tmpbuf[i]=NULL;  _tmpbuf[i]=NULL;
    693 		tmpbuf2[i]=NULL;  _tmpbuf2[i]=NULL;  outbuf[i]=NULL;
    694 	}
    695 
    696 	if((this->init&COMPRESS)==0)
    697 		_throw("tjEncodeYUV2(): Instance has not been initialized for compression");
    698 
    699 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
    700 		|| pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
    701 		|| subsamp>=NUMSUBOPT)
    702 		_throw("tjEncodeYUV2(): Invalid argument");
    703 
    704 	if(setjmp(this->jerr.setjmp_buffer))
    705 	{
    706 		/* If we get here, the JPEG code has signaled an error. */
    707 		retval=-1;
    708 		goto bailout;
    709 	}
    710 
    711 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
    712 
    713 	#ifndef JCS_EXTENSIONS
    714 	if(pixelFormat!=TJPF_GRAY)
    715 	{
    716 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
    717 		if(!rgbBuf) _throw("tjEncodeYUV2(): Memory allocation failure");
    718 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
    719 		pitch=width*RGB_PIXELSIZE;
    720 	}
    721 	#endif
    722 
    723 	cinfo->image_width=width;
    724 	cinfo->image_height=height;
    725 
    726 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    727 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
    728 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    729 
    730 	yuvsize=tjBufSizeYUV(width, height, subsamp);
    731 	if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
    732 
    733 	/* Execute only the parts of jpeg_start_compress() that we need.  If we
    734 	   were to call the whole jpeg_start_compress() function, then it would try
    735 	   to write the file headers, which could overflow the output buffer if the
    736 	   YUV image were very small. */
    737 	if(cinfo->global_state!=CSTATE_START)
    738 		_throw("tjEncodeYUV3(): libjpeg API is in the wrong state");
    739 	(*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
    740 	jinit_c_master_control(cinfo, FALSE);
    741 	jinit_color_converter(cinfo);
    742 	jinit_downsampler(cinfo);
    743 	(*cinfo->cconvert->start_pass)(cinfo);
    744 
    745 	pw=PAD(width, cinfo->max_h_samp_factor);
    746 	ph=PAD(height, cinfo->max_v_samp_factor);
    747 
    748 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
    749 		_throw("tjEncodeYUV2(): Memory allocation failure");
    750 	for(i=0; i<height; i++)
    751 	{
    752 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
    753 		else row_pointer[i]=&srcBuf[i*pitch];
    754 	}
    755 	if(height<ph)
    756 		for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
    757 
    758 	for(i=0; i<cinfo->num_components; i++)
    759 	{
    760 		compptr=&cinfo->comp_info[i];
    761 		_tmpbuf[i]=(JSAMPLE *)malloc(
    762 			PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
    763 				/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
    764 		if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
    765 		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
    766 		if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
    767 		for(row=0; row<cinfo->max_v_samp_factor; row++)
    768 		{
    769 			unsigned char *_tmpbuf_aligned=
    770 				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
    771 			tmpbuf[i][row]=&_tmpbuf_aligned[
    772 				PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
    773 					/compptr->h_samp_factor, 16) * row];
    774 		}
    775 		_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
    776 			* compptr->v_samp_factor + 16);
    777 		if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
    778 		tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
    779 		if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
    780 		for(row=0; row<compptr->v_samp_factor; row++)
    781 		{
    782 			unsigned char *_tmpbuf2_aligned=
    783 				(unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
    784 			tmpbuf2[i][row]=&_tmpbuf2_aligned[
    785 				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
    786 		}
    787 		cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
    788 		ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
    789 		outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
    790 		if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
    791 		for(row=0; row<ch[i]; row++)
    792 		{
    793 			outbuf[i][row]=ptr;
    794 			ptr+=PAD(cw[i], 4);
    795 		}
    796 	}
    797 	if(yuvsize!=(unsigned long)(ptr-dstBuf))
    798 		_throw("tjEncodeYUV2(): Generated image is not the correct size");
    799 
    800 	for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
    801 	{
    802 		(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
    803 			cinfo->max_v_samp_factor);
    804 		(cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
    805 		for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
    806 			jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
    807 				row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
    808 				compptr->v_samp_factor, cw[i]);
    809 	}
    810 	cinfo->next_scanline+=height;
    811 	jpeg_abort_compress(cinfo);
    812 
    813 	bailout:
    814 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
    815 	#ifndef JCS_EXTENSIONS
    816 	if(rgbBuf) free(rgbBuf);
    817 	#endif
    818 	if(row_pointer) free(row_pointer);
    819 	for(i=0; i<MAX_COMPONENTS; i++)
    820 	{
    821 		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
    822 		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
    823 		if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
    824 		if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
    825 		if(outbuf[i]!=NULL) free(outbuf[i]);
    826 	}
    827 	return retval;
    828 }
    829 
    830 DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
    831 	int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
    832 	int subsamp, int flags)
    833 {
    834 	return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
    835 		getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
    836 }
    837 
    838 
    839 /* Decompressor */
    840 
    841 static tjhandle _tjInitDecompress(tjinstance *this)
    842 {
    843 	unsigned char buffer[1];
    844 
    845 	/* This is also straight out of example.c */
    846 	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
    847 	this->jerr.pub.error_exit=my_error_exit;
    848 	this->jerr.pub.output_message=my_output_message;
    849 
    850 	if(setjmp(this->jerr.setjmp_buffer))
    851 	{
    852 		/* If we get here, the JPEG code has signaled an error. */
    853 		if(this) free(this);  return NULL;
    854 	}
    855 
    856 	jpeg_create_decompress(&this->dinfo);
    857 	/* Make an initial call so it will create the source manager */
    858 	jpeg_mem_src_tj(&this->dinfo, buffer, 1);
    859 
    860 	this->init|=DECOMPRESS;
    861 	return (tjhandle)this;
    862 }
    863 
    864 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
    865 {
    866 	tjinstance *this;
    867 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
    868 	{
    869 		snprintf(errStr, JMSG_LENGTH_MAX,
    870 			"tjInitDecompress(): Memory allocation failure");
    871 		return NULL;
    872 	}
    873 	MEMZERO(this, sizeof(tjinstance));
    874 	return _tjInitDecompress(this);
    875 }
    876 
    877 
    878 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
    879 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
    880 	int *jpegSubsamp)
    881 {
    882 	int retval=0;
    883 
    884 	getinstance(handle);
    885 	if((this->init&DECOMPRESS)==0)
    886 		_throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
    887 
    888 	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
    889 		|| jpegSubsamp==NULL)
    890 		_throw("tjDecompressHeader2(): Invalid argument");
    891 
    892 	if(setjmp(this->jerr.setjmp_buffer))
    893 	{
    894 		/* If we get here, the JPEG code has signaled an error. */
    895 		return -1;
    896 	}
    897 
    898 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
    899 	jpeg_read_header(dinfo, TRUE);
    900 
    901 	*width=dinfo->image_width;
    902 	*height=dinfo->image_height;
    903 	*jpegSubsamp=getSubsamp(dinfo);
    904 
    905 	jpeg_abort_decompress(dinfo);
    906 
    907 	if(*jpegSubsamp<0)
    908 		_throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
    909 	if(*width<1 || *height<1)
    910 		_throw("tjDecompressHeader2(): Invalid data returned in header");
    911 
    912 	bailout:
    913 	return retval;
    914 }
    915 
    916 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
    917 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
    918 {
    919 	int jpegSubsamp;
    920 	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
    921 		&jpegSubsamp);
    922 }
    923 
    924 
    925 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
    926 {
    927 	if(numscalingfactors==NULL)
    928 	{
    929 		snprintf(errStr, JMSG_LENGTH_MAX,
    930 			"tjGetScalingFactors(): Invalid argument");
    931 		return NULL;
    932 	}
    933 
    934 	*numscalingfactors=NUMSF;
    935 	return (tjscalingfactor *)sf;
    936 }
    937 
    938 
    939 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
    940 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
    941 	int height, int pixelFormat, int flags)
    942 {
    943 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
    944 	int jpegwidth, jpegheight, scaledw, scaledh;
    945 	#ifndef JCS_EXTENSIONS
    946 	unsigned char *rgbBuf=NULL;
    947 	unsigned char *_dstBuf=NULL;  int _pitch=0;
    948 	#endif
    949 
    950 	getinstance(handle);
    951 	if((this->init&DECOMPRESS)==0)
    952 		_throw("tjDecompress2(): Instance has not been initialized for decompression");
    953 
    954 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
    955 		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
    956 		_throw("tjDecompress2(): Invalid argument");
    957 
    958 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    959 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
    960 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    961 
    962 	if(setjmp(this->jerr.setjmp_buffer))
    963 	{
    964 		/* If we get here, the JPEG code has signaled an error. */
    965 		retval=-1;
    966 		goto bailout;
    967 	}
    968 
    969 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
    970 	jpeg_read_header(dinfo, TRUE);
    971 	if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
    972 	{
    973 		retval=-1;  goto bailout;
    974 	}
    975 
    976 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
    977 
    978 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
    979 	if(width==0) width=jpegwidth;
    980 	if(height==0) height=jpegheight;
    981 	for(i=0; i<NUMSF; i++)
    982 	{
    983 		scaledw=TJSCALED(jpegwidth, sf[i]);
    984 		scaledh=TJSCALED(jpegheight, sf[i]);
    985 		if(scaledw<=width && scaledh<=height)
    986 			break;
    987 	}
    988 	if(scaledw>width || scaledh>height)
    989 		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
    990 	width=scaledw;  height=scaledh;
    991 	dinfo->scale_num=sf[i].num;
    992 	dinfo->scale_denom=sf[i].denom;
    993 
    994 	jpeg_start_decompress(dinfo);
    995 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
    996 
    997 	#ifndef JCS_EXTENSIONS
    998 	if(pixelFormat!=TJPF_GRAY &&
    999 		(RGB_RED!=tjRedOffset[pixelFormat] ||
   1000 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
   1001 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
   1002 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
   1003 	{
   1004 		rgbBuf=(unsigned char *)malloc(width*height*3);
   1005 		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
   1006 		_pitch=pitch;  pitch=width*3;
   1007 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
   1008 	}
   1009 	#endif
   1010 
   1011 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
   1012 		*dinfo->output_height))==NULL)
   1013 		_throw("tjDecompress2(): Memory allocation failure");
   1014 	for(i=0; i<(int)dinfo->output_height; i++)
   1015 	{
   1016 		if(flags&TJFLAG_BOTTOMUP)
   1017 			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
   1018 		else row_pointer[i]=&dstBuf[i*pitch];
   1019 	}
   1020 	while(dinfo->output_scanline<dinfo->output_height)
   1021 	{
   1022 		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
   1023 			dinfo->output_height-dinfo->output_scanline);
   1024 	}
   1025 	jpeg_finish_decompress(dinfo);
   1026 
   1027 	#ifndef JCS_EXTENSIONS
   1028 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
   1029 	#endif
   1030 
   1031 	bailout:
   1032 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
   1033 	#ifndef JCS_EXTENSIONS
   1034 	if(rgbBuf) free(rgbBuf);
   1035 	#endif
   1036 	if(row_pointer) free(row_pointer);
   1037 	return retval;
   1038 }
   1039 
   1040 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
   1041 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
   1042 	int height, int pixelSize, int flags)
   1043 {
   1044 	if(flags&TJ_YUV)
   1045 		return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
   1046 	else
   1047 		return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
   1048 			height, getPixelFormat(pixelSize, flags), flags);
   1049 }
   1050 
   1051 
   1052 DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
   1053 	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
   1054 	int flags)
   1055 {
   1056 	int i, row, retval=0;  JSAMPROW *outbuf[MAX_COMPONENTS];
   1057 	int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
   1058 		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
   1059 	JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
   1060 
   1061 	getinstance(handle);
   1062 
   1063 	for(i=0; i<MAX_COMPONENTS; i++)
   1064 	{
   1065 		tmpbuf[i]=NULL;  outbuf[i]=NULL;
   1066 	}
   1067 
   1068 	if((this->init&DECOMPRESS)==0)
   1069 		_throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
   1070 
   1071 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
   1072 		_throw("tjDecompressToYUV(): Invalid argument");
   1073 
   1074 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
   1075 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
   1076 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
   1077 
   1078 	if(setjmp(this->jerr.setjmp_buffer))
   1079 	{
   1080 		/* If we get here, the JPEG code has signaled an error. */
   1081 		retval=-1;
   1082 		goto bailout;
   1083 	}
   1084 
   1085 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
   1086 	jpeg_read_header(dinfo, TRUE);
   1087 
   1088 	for(i=0; i<dinfo->num_components; i++)
   1089 	{
   1090 		jpeg_component_info *compptr=&dinfo->comp_info[i];
   1091 		int ih;
   1092 		iw[i]=compptr->width_in_blocks*DCTSIZE;
   1093 		ih=compptr->height_in_blocks*DCTSIZE;
   1094 		cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
   1095 			*compptr->h_samp_factor/dinfo->max_h_samp_factor;
   1096 		ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
   1097 			*compptr->v_samp_factor/dinfo->max_v_samp_factor;
   1098 		if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
   1099 		th[i]=compptr->v_samp_factor*DCTSIZE;
   1100 		tmpbufsize+=iw[i]*th[i];
   1101 		if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
   1102 			_throw("tjDecompressToYUV(): Memory allocation failure");
   1103 		for(row=0; row<ch[i]; row++)
   1104 		{
   1105 			outbuf[i][row]=ptr;
   1106 			ptr+=PAD(cw[i], 4);
   1107 		}
   1108 	}
   1109 	if(usetmpbuf)
   1110 	{
   1111 		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
   1112 			_throw("tjDecompressToYUV(): Memory allocation failure");
   1113 		ptr=_tmpbuf;
   1114 		for(i=0; i<dinfo->num_components; i++)
   1115 		{
   1116 			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
   1117 				_throw("tjDecompressToYUV(): Memory allocation failure");
   1118 			for(row=0; row<th[i]; row++)
   1119 			{
   1120 				tmpbuf[i][row]=ptr;
   1121 				ptr+=iw[i];
   1122 			}
   1123 		}
   1124 	}
   1125 
   1126 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
   1127 	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
   1128 	dinfo->raw_data_out=TRUE;
   1129 
   1130 	jpeg_start_decompress(dinfo);
   1131 	for(row=0; row<(int)dinfo->output_height;
   1132 		row+=dinfo->max_v_samp_factor*DCTSIZE)
   1133 	{
   1134 		JSAMPARRAY yuvptr[MAX_COMPONENTS];
   1135 		int crow[MAX_COMPONENTS];
   1136 		for(i=0; i<dinfo->num_components; i++)
   1137 		{
   1138 			jpeg_component_info *compptr=&dinfo->comp_info[i];
   1139 			crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
   1140 			if(usetmpbuf) yuvptr[i]=tmpbuf[i];
   1141 			else yuvptr[i]=&outbuf[i][crow[i]];
   1142 		}
   1143 		jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
   1144 		if(usetmpbuf)
   1145 		{
   1146 			int j;
   1147 			for(i=0; i<dinfo->num_components; i++)
   1148 			{
   1149 				for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
   1150 				{
   1151 					memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
   1152 				}
   1153 			}
   1154 		}
   1155 	}
   1156 	jpeg_finish_decompress(dinfo);
   1157 
   1158 	bailout:
   1159 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
   1160 	for(i=0; i<MAX_COMPONENTS; i++)
   1161 	{
   1162 		if(tmpbuf[i]) free(tmpbuf[i]);
   1163 		if(outbuf[i]) free(outbuf[i]);
   1164 	}
   1165 	if(_tmpbuf) free(_tmpbuf);
   1166 	return retval;
   1167 }
   1168 
   1169 
   1170 /* Transformer */
   1171 
   1172 DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
   1173 {
   1174 	tjinstance *this=NULL;  tjhandle handle=NULL;
   1175 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
   1176 	{
   1177 		snprintf(errStr, JMSG_LENGTH_MAX,
   1178 			"tjInitTransform(): Memory allocation failure");
   1179 		return NULL;
   1180 	}
   1181 	MEMZERO(this, sizeof(tjinstance));
   1182 	handle=_tjInitCompress(this);
   1183 	if(!handle) return NULL;
   1184 	handle=_tjInitDecompress(this);
   1185 	return handle;
   1186 }
   1187 
   1188 
   1189 DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
   1190 	unsigned long jpegSize, int n, unsigned char **dstBufs,
   1191 	unsigned long *dstSizes, tjtransform *t, int flags)
   1192 {
   1193 	jpeg_transform_info *xinfo=NULL;
   1194 	jvirt_barray_ptr *srccoefs, *dstcoefs;
   1195 	int retval=0, i, jpegSubsamp;
   1196 
   1197 	getinstance(handle);
   1198 	if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
   1199 		_throw("tjTransform(): Instance has not been initialized for transformation");
   1200 
   1201 	if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
   1202 		|| t==NULL || flags<0)
   1203 		_throw("tjTransform(): Invalid argument");
   1204 
   1205 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
   1206 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
   1207 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
   1208 
   1209 	if(setjmp(this->jerr.setjmp_buffer))
   1210 	{
   1211 		/* If we get here, the JPEG code has signaled an error. */
   1212 		retval=-1;
   1213 		goto bailout;
   1214 	}
   1215 
   1216 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
   1217 
   1218 	if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
   1219 		==NULL)
   1220 		_throw("tjTransform(): Memory allocation failure");
   1221 	MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
   1222 
   1223 	for(i=0; i<n; i++)
   1224 	{
   1225 		xinfo[i].transform=xformtypes[t[i].op];
   1226 		xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
   1227 		xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
   1228 		xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
   1229 		xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
   1230 		if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
   1231 		else xinfo[i].slow_hflip=0;
   1232 
   1233 		if(xinfo[i].crop)
   1234 		{
   1235 			xinfo[i].crop_xoffset=t[i].r.x;  xinfo[i].crop_xoffset_set=JCROP_POS;
   1236 			xinfo[i].crop_yoffset=t[i].r.y;  xinfo[i].crop_yoffset_set=JCROP_POS;
   1237 			if(t[i].r.w!=0)
   1238 			{
   1239 				xinfo[i].crop_width=t[i].r.w;  xinfo[i].crop_width_set=JCROP_POS;
   1240 			}
   1241 			else xinfo[i].crop_width=JCROP_UNSET;
   1242 			if(t[i].r.h!=0)
   1243 			{
   1244 				xinfo[i].crop_height=t[i].r.h;  xinfo[i].crop_height_set=JCROP_POS;
   1245 			}
   1246 			else xinfo[i].crop_height=JCROP_UNSET;
   1247 		}
   1248 	}
   1249 
   1250 	jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
   1251 	jpeg_read_header(dinfo, TRUE);
   1252 	jpegSubsamp=getSubsamp(dinfo);
   1253 	if(jpegSubsamp<0)
   1254 		_throw("tjTransform(): Could not determine subsampling type for JPEG image");
   1255 
   1256 	for(i=0; i<n; i++)
   1257 	{
   1258 		if(!jtransform_request_workspace(dinfo, &xinfo[i]))
   1259 			_throw("tjTransform(): Transform is not perfect");
   1260 
   1261 		if(xinfo[i].crop)
   1262 		{
   1263 			if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
   1264 				|| (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
   1265 			{
   1266 				snprintf(errStr, JMSG_LENGTH_MAX,
   1267 					"To crop this JPEG image, x must be a multiple of %d\n"
   1268 					"and y must be a multiple of %d.\n",
   1269 					xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
   1270 				retval=-1;  goto bailout;
   1271 			}
   1272 		}
   1273 	}
   1274 
   1275 	srccoefs=jpeg_read_coefficients(dinfo);
   1276 
   1277 	for(i=0; i<n; i++)
   1278 	{
   1279 		int w, h, alloc=1;
   1280 		if(!xinfo[i].crop)
   1281 		{
   1282 			w=dinfo->image_width;  h=dinfo->image_height;
   1283 		}
   1284 		else
   1285 		{
   1286 			w=xinfo[i].crop_width;  h=xinfo[i].crop_height;
   1287 		}
   1288 		if(flags&TJFLAG_NOREALLOC)
   1289 		{
   1290 			alloc=0;  dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
   1291 		}
   1292 		if(!(t[i].options&TJXOPT_NOOUTPUT))
   1293 			jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
   1294 		jpeg_copy_critical_parameters(dinfo, cinfo);
   1295 		dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
   1296 			&xinfo[i]);
   1297 		if(!(t[i].options&TJXOPT_NOOUTPUT))
   1298 		{
   1299 			jpeg_write_coefficients(cinfo, dstcoefs);
   1300 			jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
   1301 		}
   1302 		else jinit_c_master_control(cinfo, TRUE);
   1303 		jtransform_execute_transformation(dinfo, cinfo, srccoefs,
   1304 			&xinfo[i]);
   1305 		if(t[i].customFilter)
   1306 		{
   1307 			int ci, y;  JDIMENSION by;
   1308 			for(ci=0; ci<cinfo->num_components; ci++)
   1309 			{
   1310 				jpeg_component_info *compptr=&cinfo->comp_info[ci];
   1311 				tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
   1312 					DCTSIZE};
   1313 				tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
   1314 					compptr->height_in_blocks*DCTSIZE};
   1315 				for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
   1316 				{
   1317 					JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
   1318 						((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
   1319 						TRUE);
   1320 					for(y=0; y<compptr->v_samp_factor; y++)
   1321 					{
   1322 						if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
   1323 							ci, i, &t[i])==-1)
   1324 							_throw("tjTransform(): Error in custom filter");
   1325 						arrayRegion.y+=DCTSIZE;
   1326 					}
   1327 				}
   1328 			}
   1329 		}
   1330 		if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
   1331 	}
   1332 
   1333 	jpeg_finish_decompress(dinfo);
   1334 
   1335 	bailout:
   1336 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
   1337 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
   1338 	if(xinfo) free(xinfo);
   1339 	return retval;
   1340 }
   1341