Home | History | Annotate | Download | only in libjpeg-turbo
      1 /*
      2  * Copyright (C)2009-2015 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 <ctype.h>
     35 #include <jinclude.h>
     36 #define JPEG_INTERNALS
     37 #include <jpeglib.h>
     38 #include <jerror.h>
     39 #include <setjmp.h>
     40 #include "./turbojpeg.h"
     41 #include "./tjutil.h"
     42 #include "transupp.h"
     43 #include "./jpegcomp.h"
     44 
     45 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
     46 	unsigned long *, boolean);
     47 extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
     48 
     49 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
     50 #define isPow2(x) (((x)&(x-1))==0)
     51 
     52 
     53 /* Error handling (based on example in example.c) */
     54 
     55 static char errStr[JMSG_LENGTH_MAX]="No error";
     56 
     57 struct my_error_mgr
     58 {
     59 	struct jpeg_error_mgr pub;
     60 	jmp_buf setjmp_buffer;
     61 	void (*emit_message)(j_common_ptr, int);
     62 	boolean warning;
     63 };
     64 typedef struct my_error_mgr *my_error_ptr;
     65 
     66 static void my_error_exit(j_common_ptr cinfo)
     67 {
     68 	my_error_ptr myerr=(my_error_ptr)cinfo->err;
     69 	(*cinfo->err->output_message)(cinfo);
     70 	longjmp(myerr->setjmp_buffer, 1);
     71 }
     72 
     73 /* Based on output_message() in jerror.c */
     74 
     75 static void my_output_message(j_common_ptr cinfo)
     76 {
     77 	(*cinfo->err->format_message)(cinfo, errStr);
     78 }
     79 
     80 static void my_emit_message(j_common_ptr cinfo, int msg_level)
     81 {
     82 	my_error_ptr myerr=(my_error_ptr)cinfo->err;
     83 	myerr->emit_message(cinfo, msg_level);
     84 	if(msg_level<0) myerr->warning=TRUE;
     85 }
     86 
     87 
     88 /* Global structures, macros, etc. */
     89 
     90 enum {COMPRESS=1, DECOMPRESS=2};
     91 
     92 typedef struct _tjinstance
     93 {
     94 	struct jpeg_compress_struct cinfo;
     95 	struct jpeg_decompress_struct dinfo;
     96 	struct my_error_mgr jerr;
     97 	int init, headerRead;
     98 } tjinstance;
     99 
    100 static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};
    101 
    102 static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
    103 {
    104 	JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
    105 	JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
    106 };
    107 
    108 #define NUMSF 16
    109 static const tjscalingfactor sf[NUMSF]={
    110 	{2, 1},
    111 	{15, 8},
    112 	{7, 4},
    113 	{13, 8},
    114 	{3, 2},
    115 	{11, 8},
    116 	{5, 4},
    117 	{9, 8},
    118 	{1, 1},
    119 	{7, 8},
    120 	{3, 4},
    121 	{5, 8},
    122 	{1, 2},
    123 	{3, 8},
    124 	{1, 4},
    125 	{1, 8}
    126 };
    127 
    128 #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
    129 	retval=-1;  goto bailout;}
    130 #define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
    131 	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
    132 	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
    133 		return -1;}  \
    134 	cinfo=&this->cinfo;  dinfo=&this->dinfo;  \
    135 	this->jerr.warning=FALSE;
    136 #define getcinstance(handle) tjinstance *this=(tjinstance *)handle;  \
    137 	j_compress_ptr cinfo=NULL;  \
    138 	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
    139 		return -1;}  \
    140 	cinfo=&this->cinfo;  \
    141 	this->jerr.warning=FALSE;
    142 #define getdinstance(handle) tjinstance *this=(tjinstance *)handle;  \
    143 	j_decompress_ptr dinfo=NULL;  \
    144 	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
    145 		return -1;}  \
    146 	dinfo=&this->dinfo;  \
    147 	this->jerr.warning=FALSE;
    148 
    149 static int getPixelFormat(int pixelSize, int flags)
    150 {
    151 	if(pixelSize==1) return TJPF_GRAY;
    152 	if(pixelSize==3)
    153 	{
    154 		if(flags&TJ_BGR) return TJPF_BGR;
    155 		else return TJPF_RGB;
    156 	}
    157 	if(pixelSize==4)
    158 	{
    159 		if(flags&TJ_ALPHAFIRST)
    160 		{
    161 			if(flags&TJ_BGR) return TJPF_XBGR;
    162 			else return TJPF_XRGB;
    163 		}
    164 		else
    165 		{
    166 			if(flags&TJ_BGR) return TJPF_BGRX;
    167 			else return TJPF_RGBX;
    168 		}
    169 	}
    170 	return -1;
    171 }
    172 
    173 static int setCompDefaults(struct jpeg_compress_struct *cinfo,
    174 	int pixelFormat, int subsamp, int jpegQual, int flags)
    175 {
    176 	int retval=0;
    177 	char *env=NULL;
    178 
    179 	switch(pixelFormat)
    180 	{
    181 		case TJPF_GRAY:
    182 			cinfo->in_color_space=JCS_GRAYSCALE;  break;
    183 		#if JCS_EXTENSIONS==1
    184 		case TJPF_RGB:
    185 			cinfo->in_color_space=JCS_EXT_RGB;  break;
    186 		case TJPF_BGR:
    187 			cinfo->in_color_space=JCS_EXT_BGR;  break;
    188 		case TJPF_RGBX:
    189 		case TJPF_RGBA:
    190 			cinfo->in_color_space=JCS_EXT_RGBX;  break;
    191 		case TJPF_BGRX:
    192 		case TJPF_BGRA:
    193 			cinfo->in_color_space=JCS_EXT_BGRX;  break;
    194 		case TJPF_XRGB:
    195 		case TJPF_ARGB:
    196 			cinfo->in_color_space=JCS_EXT_XRGB;  break;
    197 		case TJPF_XBGR:
    198 		case TJPF_ABGR:
    199 			cinfo->in_color_space=JCS_EXT_XBGR;  break;
    200 		#else
    201 		case TJPF_RGB:
    202 		case TJPF_BGR:
    203 		case TJPF_RGBX:
    204 		case TJPF_BGRX:
    205 		case TJPF_XRGB:
    206 		case TJPF_XBGR:
    207 		case TJPF_RGBA:
    208 		case TJPF_BGRA:
    209 		case TJPF_ARGB:
    210 		case TJPF_ABGR:
    211 			cinfo->in_color_space=JCS_RGB;  pixelFormat=TJPF_RGB;
    212 			break;
    213 		#endif
    214 		case TJPF_CMYK:
    215 			cinfo->in_color_space=JCS_CMYK;  break;
    216 	}
    217 
    218 	cinfo->input_components=tjPixelSize[pixelFormat];
    219 	jpeg_set_defaults(cinfo);
    220 
    221 #ifndef NO_GETENV
    222 	if((env=getenv("TJ_OPTIMIZE"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
    223 		cinfo->optimize_coding=TRUE;
    224 	if((env=getenv("TJ_ARITHMETIC"))!=NULL && strlen(env)>0	&& !strcmp(env, "1"))
    225 		cinfo->arith_code=TRUE;
    226 	if((env=getenv("TJ_RESTART"))!=NULL && strlen(env)>0)
    227 	{
    228 		int temp=-1;  char tempc=0;
    229 		if(sscanf(env, "%d%c", &temp, &tempc)>=1 && temp>=0 && temp<=65535)
    230 		{
    231 			if(toupper(tempc)=='B')
    232 			{
    233 				cinfo->restart_interval=temp;
    234 				cinfo->restart_in_rows=0;
    235 			}
    236 			else
    237 				cinfo->restart_in_rows=temp;
    238 		}
    239 	}
    240 #endif
    241 
    242 	if(jpegQual>=0)
    243 	{
    244 		jpeg_set_quality(cinfo, jpegQual, TRUE);
    245 		if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
    246 		else cinfo->dct_method=JDCT_FASTEST;
    247 	}
    248 	if(subsamp==TJSAMP_GRAY)
    249 		jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
    250 	else if(pixelFormat==TJPF_CMYK)
    251 		jpeg_set_colorspace(cinfo, JCS_YCCK);
    252 	else jpeg_set_colorspace(cinfo, JCS_YCbCr);
    253 
    254 #ifndef NO_GETENV
    255 	if((env=getenv("TJ_PROGRESSIVE"))!=NULL && strlen(env)>0
    256 		&& !strcmp(env, "1"))
    257 		jpeg_simple_progression(cinfo);
    258 #endif
    259 
    260 	cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
    261 	cinfo->comp_info[1].h_samp_factor=1;
    262 	cinfo->comp_info[2].h_samp_factor=1;
    263 	if(cinfo->num_components>3)
    264 		cinfo->comp_info[3].h_samp_factor=tjMCUWidth[subsamp]/8;
    265 	cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
    266 	cinfo->comp_info[1].v_samp_factor=1;
    267 	cinfo->comp_info[2].v_samp_factor=1;
    268 	if(cinfo->num_components>3)
    269 		cinfo->comp_info[3].v_samp_factor=tjMCUHeight[subsamp]/8;
    270 
    271 	return retval;
    272 }
    273 
    274 static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
    275 	int pixelFormat, int flags)
    276 {
    277 	int retval=0;
    278 
    279 	switch(pixelFormat)
    280 	{
    281 		case TJPF_GRAY:
    282 			dinfo->out_color_space=JCS_GRAYSCALE;  break;
    283 		#if JCS_EXTENSIONS==1
    284 		case TJPF_RGB:
    285 			dinfo->out_color_space=JCS_EXT_RGB;  break;
    286 		case TJPF_BGR:
    287 			dinfo->out_color_space=JCS_EXT_BGR;  break;
    288 		case TJPF_RGBX:
    289 			dinfo->out_color_space=JCS_EXT_RGBX;  break;
    290 		case TJPF_BGRX:
    291 			dinfo->out_color_space=JCS_EXT_BGRX;  break;
    292 		case TJPF_XRGB:
    293 			dinfo->out_color_space=JCS_EXT_XRGB;  break;
    294 		case TJPF_XBGR:
    295 			dinfo->out_color_space=JCS_EXT_XBGR;  break;
    296 		#if JCS_ALPHA_EXTENSIONS==1
    297 		case TJPF_RGBA:
    298 			dinfo->out_color_space=JCS_EXT_RGBA;  break;
    299 		case TJPF_BGRA:
    300 			dinfo->out_color_space=JCS_EXT_BGRA;  break;
    301 		case TJPF_ARGB:
    302 			dinfo->out_color_space=JCS_EXT_ARGB;  break;
    303 		case TJPF_ABGR:
    304 			dinfo->out_color_space=JCS_EXT_ABGR;  break;
    305 		#endif
    306 		#else
    307 		case TJPF_RGB:
    308 		case TJPF_BGR:
    309 		case TJPF_RGBX:
    310 		case TJPF_BGRX:
    311 		case TJPF_XRGB:
    312 		case TJPF_XBGR:
    313 		case TJPF_RGBA:
    314 		case TJPF_BGRA:
    315 		case TJPF_ARGB:
    316 		case TJPF_ABGR:
    317 			dinfo->out_color_space=JCS_RGB;  break;
    318 		#endif
    319 		case TJPF_CMYK:
    320 			dinfo->out_color_space=JCS_CMYK;  break;
    321 		default:
    322 			_throw("Unsupported pixel format");
    323 	}
    324 
    325 	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
    326 
    327 	bailout:
    328 	return retval;
    329 }
    330 
    331 
    332 static int getSubsamp(j_decompress_ptr dinfo)
    333 {
    334 	int retval=-1, i, k;
    335 
    336 	/* The sampling factors actually have no meaning with grayscale JPEG files,
    337 	   and in fact it's possible to generate grayscale JPEGs with sampling
    338 	   factors > 1 (even though those sampling factors are ignored by the
    339 	   decompressor.)  Thus, we need to treat grayscale as a special case. */
    340 	if(dinfo->num_components==1 && dinfo->jpeg_color_space==JCS_GRAYSCALE)
    341 		return TJSAMP_GRAY;
    342 
    343 	for(i=0; i<NUMSUBOPT; i++)
    344 	{
    345 		if(dinfo->num_components==pixelsize[i]
    346 			|| ((dinfo->jpeg_color_space==JCS_YCCK
    347 				|| dinfo->jpeg_color_space==JCS_CMYK)
    348 					&& pixelsize[i]==3 && dinfo->num_components==4))
    349 		{
    350 			if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
    351 				&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
    352 			{
    353 				int match=0;
    354 				for(k=1; k<dinfo->num_components; k++)
    355 				{
    356 					int href=1, vref=1;
    357 					if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
    358 					{
    359 						href=tjMCUWidth[i]/8;  vref=tjMCUHeight[i]/8;
    360 					}
    361 					if(dinfo->comp_info[k].h_samp_factor==href
    362 						&& dinfo->comp_info[k].v_samp_factor==vref)
    363 						match++;
    364 				}
    365 				if(match==dinfo->num_components-1)
    366 				{
    367 					retval=i;  break;
    368 				}
    369 			}
    370 		}
    371 	}
    372 	return retval;
    373 }
    374 
    375 
    376 #ifndef JCS_EXTENSIONS
    377 
    378 /* Conversion functions to emulate the colorspace extensions.  This allows the
    379    TurboJPEG wrapper to be used with libjpeg */
    380 
    381 #define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
    382 	int rowPad=pitch-width*PS;  \
    383 	while(height--)  \
    384 	{  \
    385 		unsigned char *endOfRow=src+width*PS;  \
    386 		while(src<endOfRow)  \
    387 		{  \
    388 			dst[RGB_RED]=src[ROFFSET];  \
    389 			dst[RGB_GREEN]=src[GOFFSET];  \
    390 			dst[RGB_BLUE]=src[BOFFSET];  \
    391 			dst+=RGB_PIXELSIZE;  src+=PS;  \
    392 		}  \
    393 		src+=rowPad;  \
    394 	}  \
    395 }
    396 
    397 static unsigned char *toRGB(unsigned char *src, int width, int pitch,
    398 	int height, int pixelFormat, unsigned char *dst)
    399 {
    400 	unsigned char *retval=src;
    401 	switch(pixelFormat)
    402 	{
    403 		case TJPF_RGB:
    404 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
    405 			retval=dst;  TORGB(3, 0, 1, 2);
    406 			#endif
    407 			break;
    408 		case TJPF_BGR:
    409 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
    410 			retval=dst;  TORGB(3, 2, 1, 0);
    411 			#endif
    412 			break;
    413 		case TJPF_RGBX:
    414 		case TJPF_RGBA:
    415 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
    416 			retval=dst;  TORGB(4, 0, 1, 2);
    417 			#endif
    418 			break;
    419 		case TJPF_BGRX:
    420 		case TJPF_BGRA:
    421 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
    422 			retval=dst;  TORGB(4, 2, 1, 0);
    423 			#endif
    424 			break;
    425 		case TJPF_XRGB:
    426 		case TJPF_ARGB:
    427 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
    428 			retval=dst;  TORGB(4, 1, 2, 3);
    429 			#endif
    430 			break;
    431 		case TJPF_XBGR:
    432 		case TJPF_ABGR:
    433 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
    434 			retval=dst;  TORGB(4, 3, 2, 1);
    435 			#endif
    436 			break;
    437 	}
    438 	return retval;
    439 }
    440 
    441 #define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) {  \
    442 	int rowPad=pitch-width*PS;  \
    443 	while(height--)  \
    444 	{  \
    445 		unsigned char *endOfRow=dst+width*PS;  \
    446 		while(dst<endOfRow)  \
    447 		{  \
    448 			dst[ROFFSET]=src[RGB_RED];  \
    449 			dst[GOFFSET]=src[RGB_GREEN];  \
    450 			dst[BOFFSET]=src[RGB_BLUE];  \
    451 			SETALPHA  \
    452 			dst+=PS;  src+=RGB_PIXELSIZE;  \
    453 		}  \
    454 		dst+=rowPad;  \
    455 	}  \
    456 }
    457 
    458 static void fromRGB(unsigned char *src, unsigned char *dst, int width,
    459 	int pitch, int height, int pixelFormat)
    460 {
    461 	switch(pixelFormat)
    462 	{
    463 		case TJPF_RGB:
    464 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
    465 			FROMRGB(3, 0, 1, 2,);
    466 			#endif
    467 			break;
    468 		case TJPF_BGR:
    469 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
    470 			FROMRGB(3, 2, 1, 0,);
    471 			#endif
    472 			break;
    473 		case TJPF_RGBX:
    474 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
    475 			FROMRGB(4, 0, 1, 2,);
    476 			#endif
    477 			break;
    478 		case TJPF_RGBA:
    479 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
    480 			FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
    481 			#endif
    482 			break;
    483 		case TJPF_BGRX:
    484 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
    485 			FROMRGB(4, 2, 1, 0,);
    486 			#endif
    487 			break;
    488 		case TJPF_BGRA:
    489 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
    490 			FROMRGB(4, 2, 1, 0, dst[3]=0xFF;);  return;
    491 			#endif
    492 			break;
    493 		case TJPF_XRGB:
    494 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
    495 			FROMRGB(4, 1, 2, 3,);  return;
    496 			#endif
    497 			break;
    498 		case TJPF_ARGB:
    499 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
    500 			FROMRGB(4, 1, 2, 3, dst[0]=0xFF;);  return;
    501 			#endif
    502 			break;
    503 		case TJPF_XBGR:
    504 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
    505 			FROMRGB(4, 3, 2, 1,);  return;
    506 			#endif
    507 			break;
    508 		case TJPF_ABGR:
    509 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
    510 			FROMRGB(4, 3, 2, 1, dst[0]=0xFF;);  return;
    511 			#endif
    512 			break;
    513 	}
    514 }
    515 
    516 #endif
    517 
    518 
    519 /* General API functions */
    520 
    521 DLLEXPORT char* DLLCALL tjGetErrorStr(void)
    522 {
    523 	return errStr;
    524 }
    525 
    526 
    527 DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
    528 {
    529 	getinstance(handle);
    530 	if(setjmp(this->jerr.setjmp_buffer)) return -1;
    531 	if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
    532 	if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
    533 	free(this);
    534 	return 0;
    535 }
    536 
    537 
    538 /* These are exposed mainly because Windows can't malloc() and free() across
    539    DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
    540    with turbojpeg.dll for compatibility reasons.  However, these functions
    541    can potentially be used for other purposes by different implementations. */
    542 
    543 DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
    544 {
    545 	if(buf) free(buf);
    546 }
    547 
    548 
    549 DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
    550 {
    551 	return (unsigned char *)malloc(bytes);
    552 }
    553 
    554 
    555 /* Compressor  */
    556 
    557 static tjhandle _tjInitCompress(tjinstance *this)
    558 {
    559 	unsigned char buffer[1], *buf=buffer;  unsigned long size=1;
    560 
    561 	/* This is also straight out of example.c */
    562 	this->cinfo.err=jpeg_std_error(&this->jerr.pub);
    563 	this->jerr.pub.error_exit=my_error_exit;
    564 	this->jerr.pub.output_message=my_output_message;
    565 	this->jerr.emit_message=this->jerr.pub.emit_message;
    566 	this->jerr.pub.emit_message=my_emit_message;
    567 
    568 	if(setjmp(this->jerr.setjmp_buffer))
    569 	{
    570 		/* If we get here, the JPEG code has signaled an error. */
    571 		if(this) free(this);  return NULL;
    572 	}
    573 
    574 	jpeg_create_compress(&this->cinfo);
    575 	/* Make an initial call so it will create the destination manager */
    576 	jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
    577 
    578 	this->init|=COMPRESS;
    579 	return (tjhandle)this;
    580 }
    581 
    582 DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
    583 {
    584 	tjinstance *this=NULL;
    585 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
    586 	{
    587 		snprintf(errStr, JMSG_LENGTH_MAX,
    588 			"tjInitCompress(): Memory allocation failure");
    589 		return NULL;
    590 	}
    591 	MEMZERO(this, sizeof(tjinstance));
    592 	return _tjInitCompress(this);
    593 }
    594 
    595 
    596 DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
    597 	int jpegSubsamp)
    598 {
    599 	unsigned long retval=0;  int mcuw, mcuh, chromasf;
    600 	if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
    601 		_throw("tjBufSize(): Invalid argument");
    602 
    603 	/* This allows for rare corner cases in which a JPEG image can actually be
    604 	   larger than the uncompressed input (we wouldn't mention it if it hadn't
    605 	   happened before.) */
    606 	mcuw=tjMCUWidth[jpegSubsamp];
    607 	mcuh=tjMCUHeight[jpegSubsamp];
    608 	chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
    609 	retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
    610 
    611 	bailout:
    612 	return retval;
    613 }
    614 
    615 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
    616 {
    617 	unsigned long retval=0;
    618 	if(width<1 || height<1)
    619 		_throw("TJBUFSIZE(): Invalid argument");
    620 
    621 	/* This allows for rare corner cases in which a JPEG image can actually be
    622 	   larger than the uncompressed input (we wouldn't mention it if it hadn't
    623 	   happened before.) */
    624 	retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
    625 
    626 	bailout:
    627 	return retval;
    628 }
    629 
    630 
    631 DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
    632 	int subsamp)
    633 {
    634 	int retval=0, nc, i;
    635 
    636 	if(subsamp<0 || subsamp>=NUMSUBOPT)
    637 		_throw("tjBufSizeYUV2(): Invalid argument");
    638 
    639 	nc=(subsamp==TJSAMP_GRAY? 1:3);
    640 	for(i=0; i<nc; i++)
    641 	{
    642 		int pw=tjPlaneWidth(i, width, subsamp);
    643 		int stride=PAD(pw, pad);
    644 		int ph=tjPlaneHeight(i, height, subsamp);
    645 		if(pw<0 || ph<0) return -1;
    646 		else retval+=stride*ph;
    647 	}
    648 
    649 	bailout:
    650 	return retval;
    651 }
    652 
    653 DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
    654 	int subsamp)
    655 {
    656 	return tjBufSizeYUV2(width, 4, height, subsamp);
    657 }
    658 
    659 DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
    660 	int subsamp)
    661 {
    662 	return tjBufSizeYUV(width, height, subsamp);
    663 }
    664 
    665 
    666 DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
    667 {
    668 	int pw, nc, retval=0;
    669 
    670 	if(width<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
    671 		_throw("tjPlaneWidth(): Invalid argument");
    672 	nc=(subsamp==TJSAMP_GRAY? 1:3);
    673 	if(componentID<0 || componentID>=nc)
    674 		_throw("tjPlaneWidth(): Invalid argument");
    675 
    676 	pw=PAD(width, tjMCUWidth[subsamp]/8);
    677 	if(componentID==0)
    678 		retval=pw;
    679 	else
    680 		retval=pw*8/tjMCUWidth[subsamp];
    681 
    682 	bailout:
    683 	return retval;
    684 }
    685 
    686 
    687 DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
    688 {
    689 	int ph, nc, retval=0;
    690 
    691 	if(height<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
    692 		_throw("tjPlaneHeight(): Invalid argument");
    693 	nc=(subsamp==TJSAMP_GRAY? 1:3);
    694 	if(componentID<0 || componentID>=nc)
    695 		_throw("tjPlaneHeight(): Invalid argument");
    696 
    697 	ph=PAD(height, tjMCUHeight[subsamp]/8);
    698 	if(componentID==0)
    699 		retval=ph;
    700 	else
    701 		retval=ph*8/tjMCUHeight[subsamp];
    702 
    703 	bailout:
    704 	return retval;
    705 }
    706 
    707 
    708 DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width,
    709 	int stride, int height, int subsamp)
    710 {
    711 	unsigned long retval=0;
    712 	int pw, ph;
    713 
    714 	if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
    715 		_throw("tjPlaneSizeYUV(): Invalid argument");
    716 
    717 	pw=tjPlaneWidth(componentID, width, subsamp);
    718 	ph=tjPlaneHeight(componentID, height, subsamp);
    719 	if(pw<0 || ph<0) return -1;
    720 
    721 	if(stride==0) stride=pw;
    722 	else stride=abs(stride);
    723 
    724 	retval=stride*(ph-1)+pw;
    725 
    726 	bailout:
    727 	return retval;
    728 }
    729 
    730 
    731 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
    732 	int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
    733 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
    734 {
    735 	int i, retval=0, alloc=1;  JSAMPROW *row_pointer=NULL;
    736 	#ifndef JCS_EXTENSIONS
    737 	unsigned char *rgbBuf=NULL;
    738 	#endif
    739 
    740 	getcinstance(handle)
    741 	if((this->init&COMPRESS)==0)
    742 		_throw("tjCompress2(): Instance has not been initialized for compression");
    743 
    744 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
    745 		|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
    746 		|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
    747 		_throw("tjCompress2(): Invalid argument");
    748 
    749 	if(setjmp(this->jerr.setjmp_buffer))
    750 	{
    751 		/* If we get here, the JPEG code has signaled an error. */
    752 		retval=-1;
    753 		goto bailout;
    754 	}
    755 
    756 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
    757 
    758 	#ifndef JCS_EXTENSIONS
    759 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
    760 	{
    761 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
    762 		if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
    763 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
    764 		pitch=width*RGB_PIXELSIZE;
    765 	}
    766 	#endif
    767 
    768 	cinfo->image_width=width;
    769 	cinfo->image_height=height;
    770 
    771 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    772 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
    773 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    774 
    775 	if(flags&TJFLAG_NOREALLOC)
    776 	{
    777 		alloc=0;  *jpegSize=tjBufSize(width, height, jpegSubsamp);
    778 	}
    779 	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
    780 	if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
    781 		return -1;
    782 
    783 	jpeg_start_compress(cinfo, TRUE);
    784 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
    785 		_throw("tjCompress2(): Memory allocation failure");
    786 	for(i=0; i<height; i++)
    787 	{
    788 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
    789 		else row_pointer[i]=&srcBuf[i*pitch];
    790 	}
    791 	while(cinfo->next_scanline<cinfo->image_height)
    792 	{
    793 		jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
    794 			cinfo->image_height-cinfo->next_scanline);
    795 	}
    796 	jpeg_finish_compress(cinfo);
    797 
    798 	bailout:
    799 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
    800 	#ifndef JCS_EXTENSIONS
    801 	if(rgbBuf) free(rgbBuf);
    802 	#endif
    803 	if(row_pointer) free(row_pointer);
    804 	if(this->jerr.warning) retval=-1;
    805 	return retval;
    806 }
    807 
    808 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
    809 	int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
    810 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
    811 {
    812 	int retval=0;  unsigned long size;
    813 	if(flags&TJ_YUV)
    814 	{
    815 		size=tjBufSizeYUV(width, height, jpegSubsamp);
    816 		retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
    817 			getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
    818 	}
    819 	else
    820 	{
    821 		retval=tjCompress2(handle, srcBuf, width, pitch, height,
    822 			getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
    823 			flags|TJFLAG_NOREALLOC);
    824 	}
    825 	*jpegSize=size;
    826 	return retval;
    827 }
    828 
    829 
    830 DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle, unsigned char *srcBuf,
    831 	int width, int pitch, int height, int pixelFormat, unsigned char **dstPlanes,
    832 	int *strides, int subsamp, int flags)
    833 {
    834 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
    835 	JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
    836 	JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
    837 	JSAMPROW *outbuf[MAX_COMPONENTS];
    838 	int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
    839 	JSAMPLE *ptr;
    840 	jpeg_component_info *compptr;
    841 	#ifndef JCS_EXTENSIONS
    842 	unsigned char *rgbBuf=NULL;
    843 	#endif
    844 
    845 	getcinstance(handle);
    846 
    847 	for(i=0; i<MAX_COMPONENTS; i++)
    848 	{
    849 		tmpbuf[i]=NULL;  _tmpbuf[i]=NULL;
    850 		tmpbuf2[i]=NULL;  _tmpbuf2[i]=NULL;  outbuf[i]=NULL;
    851 	}
    852 
    853 	if((this->init&COMPRESS)==0)
    854 		_throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
    855 
    856 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
    857 		|| pixelFormat>=TJ_NUMPF || !dstPlanes || !dstPlanes[0] || subsamp<0
    858 		|| subsamp>=NUMSUBOPT)
    859 		_throw("tjEncodeYUVPlanes(): Invalid argument");
    860 	if(subsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
    861 		_throw("tjEncodeYUVPlanes(): Invalid argument");
    862 
    863 	if(setjmp(this->jerr.setjmp_buffer))
    864 	{
    865 		/* If we get here, the JPEG code has signaled an error. */
    866 		retval=-1;
    867 		goto bailout;
    868 	}
    869 
    870 	if(pixelFormat==TJPF_CMYK)
    871 		_throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
    872 
    873 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
    874 
    875 	#ifndef JCS_EXTENSIONS
    876 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
    877 	{
    878 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
    879 		if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
    880 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
    881 		pitch=width*RGB_PIXELSIZE;
    882 	}
    883 	#endif
    884 
    885 	cinfo->image_width=width;
    886 	cinfo->image_height=height;
    887 
    888 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
    889 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
    890 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
    891 
    892 	if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
    893 
    894 	/* Execute only the parts of jpeg_start_compress() that we need.  If we
    895 	   were to call the whole jpeg_start_compress() function, then it would try
    896 	   to write the file headers, which could overflow the output buffer if the
    897 	   YUV image were very small. */
    898 	if(cinfo->global_state!=CSTATE_START)
    899 		_throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
    900 	(*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
    901 	jinit_c_master_control(cinfo, FALSE);
    902 	jinit_color_converter(cinfo);
    903 	jinit_downsampler(cinfo);
    904 	(*cinfo->cconvert->start_pass)(cinfo);
    905 
    906 	pw0=PAD(width, cinfo->max_h_samp_factor);
    907 	ph0=PAD(height, cinfo->max_v_samp_factor);
    908 
    909 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
    910 		_throw("tjEncodeYUVPlanes(): Memory allocation failure");
    911 	for(i=0; i<height; i++)
    912 	{
    913 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
    914 		else row_pointer[i]=&srcBuf[i*pitch];
    915 	}
    916 	if(height<ph0)
    917 		for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
    918 
    919 	for(i=0; i<cinfo->num_components; i++)
    920 	{
    921 		compptr=&cinfo->comp_info[i];
    922 		_tmpbuf[i]=(JSAMPLE *)malloc(
    923 			PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
    924 				/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
    925 		if(!_tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
    926 		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
    927 		if(!tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
    928 		for(row=0; row<cinfo->max_v_samp_factor; row++)
    929 		{
    930 			unsigned char *_tmpbuf_aligned=
    931 				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
    932 			tmpbuf[i][row]=&_tmpbuf_aligned[
    933 				PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
    934 					/compptr->h_samp_factor, 16) * row];
    935 		}
    936 		_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
    937 			* compptr->v_samp_factor + 16);
    938 		if(!_tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
    939 		tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
    940 		if(!tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
    941 		for(row=0; row<compptr->v_samp_factor; row++)
    942 		{
    943 			unsigned char *_tmpbuf2_aligned=
    944 				(unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
    945 			tmpbuf2[i][row]=&_tmpbuf2_aligned[
    946 				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
    947 		}
    948 		pw[i]=pw0*compptr->h_samp_factor/cinfo->max_h_samp_factor;
    949 		ph[i]=ph0*compptr->v_samp_factor/cinfo->max_v_samp_factor;
    950 		outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
    951 		if(!outbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
    952 		ptr=dstPlanes[i];
    953 		for(row=0; row<ph[i]; row++)
    954 		{
    955 			outbuf[i][row]=ptr;
    956 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
    957 		}
    958 	}
    959 
    960 	for(row=0; row<ph0; row+=cinfo->max_v_samp_factor)
    961 	{
    962 		(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
    963 			cinfo->max_v_samp_factor);
    964 		(cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
    965 		for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
    966 			jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
    967 				row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
    968 				compptr->v_samp_factor, pw[i]);
    969 	}
    970 	cinfo->next_scanline+=height;
    971 	jpeg_abort_compress(cinfo);
    972 
    973 	bailout:
    974 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
    975 	#ifndef JCS_EXTENSIONS
    976 	if(rgbBuf) free(rgbBuf);
    977 	#endif
    978 	if(row_pointer) free(row_pointer);
    979 	for(i=0; i<MAX_COMPONENTS; i++)
    980 	{
    981 		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
    982 		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
    983 		if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
    984 		if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
    985 		if(outbuf[i]!=NULL) free(outbuf[i]);
    986 	}
    987 	if(this->jerr.warning) retval=-1;
    988 	return retval;
    989 }
    990 
    991 DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle, unsigned char *srcBuf,
    992 	int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
    993 	int pad, int subsamp, int flags)
    994 {
    995 	unsigned char *dstPlanes[3];
    996 	int pw0, ph0, strides[3], retval=-1;
    997 
    998 	if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad)
    999 		|| subsamp<0 || subsamp>=NUMSUBOPT)
   1000 		_throw("tjEncodeYUV3(): Invalid argument");
   1001 
   1002 	pw0=tjPlaneWidth(0, width, subsamp);
   1003 	ph0=tjPlaneHeight(0, height, subsamp);
   1004 	dstPlanes[0]=dstBuf;
   1005 	strides[0]=PAD(pw0, pad);
   1006 	if(subsamp==TJSAMP_GRAY)
   1007 	{
   1008 		strides[1]=strides[2]=0;
   1009 		dstPlanes[1]=dstPlanes[2]=NULL;
   1010 	}
   1011 	else
   1012 	{
   1013 		int pw1=tjPlaneWidth(1, width, subsamp);
   1014 		int ph1=tjPlaneHeight(1, height, subsamp);
   1015 		strides[1]=strides[2]=PAD(pw1, pad);
   1016 		dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
   1017 		dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
   1018 	}
   1019 
   1020 	return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
   1021 		dstPlanes, strides, subsamp, flags);
   1022 
   1023 	bailout:
   1024 	return retval;
   1025 }
   1026 
   1027 DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
   1028 	int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
   1029 	int subsamp, int flags)
   1030 {
   1031 	return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
   1032 		dstBuf, 4, subsamp, flags);
   1033 }
   1034 
   1035 DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
   1036 	int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
   1037 	int subsamp, int flags)
   1038 {
   1039 	return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
   1040 		getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
   1041 }
   1042 
   1043 
   1044 DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
   1045 	unsigned char **srcPlanes, int width, int *strides, int height, int subsamp,
   1046 	unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)
   1047 {
   1048 	int i, row, retval=0, alloc=1;  JSAMPROW *inbuf[MAX_COMPONENTS];
   1049 	int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
   1050 		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
   1051 	JSAMPLE *_tmpbuf=NULL, *ptr;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
   1052 
   1053 	getcinstance(handle)
   1054 
   1055 	for(i=0; i<MAX_COMPONENTS; i++)
   1056 	{
   1057 		tmpbuf[i]=NULL;  inbuf[i]=NULL;
   1058 	}
   1059 
   1060 	if((this->init&COMPRESS)==0)
   1061 		_throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
   1062 
   1063 	if(!srcPlanes || !srcPlanes[0] || width<=0 || height<=0 || subsamp<0
   1064 		|| subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
   1065 		|| jpegQual>100)
   1066 		_throw("tjCompressFromYUVPlanes(): Invalid argument");
   1067 	if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
   1068 		_throw("tjCompressFromYUVPlanes(): Invalid argument");
   1069 
   1070 	if(setjmp(this->jerr.setjmp_buffer))
   1071 	{
   1072 		/* If we get here, the JPEG code has signaled an error. */
   1073 		retval=-1;
   1074 		goto bailout;
   1075 	}
   1076 
   1077 	cinfo->image_width=width;
   1078 	cinfo->image_height=height;
   1079 
   1080 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
   1081 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
   1082 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
   1083 
   1084 	if(flags&TJFLAG_NOREALLOC)
   1085 	{
   1086 		alloc=0;  *jpegSize=tjBufSize(width, height, subsamp);
   1087 	}
   1088 	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
   1089 	if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
   1090 		return -1;
   1091 	cinfo->raw_data_in=TRUE;
   1092 
   1093 	jpeg_start_compress(cinfo, TRUE);
   1094 	for(i=0; i<cinfo->num_components; i++)
   1095 	{
   1096 		jpeg_component_info *compptr=&cinfo->comp_info[i];
   1097 		int ih;
   1098 		iw[i]=compptr->width_in_blocks*DCTSIZE;
   1099 		ih=compptr->height_in_blocks*DCTSIZE;
   1100 		pw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
   1101 			*compptr->h_samp_factor/cinfo->max_h_samp_factor;
   1102 		ph[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
   1103 			*compptr->v_samp_factor/cinfo->max_v_samp_factor;
   1104 		if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
   1105 		th[i]=compptr->v_samp_factor*DCTSIZE;
   1106 		tmpbufsize+=iw[i]*th[i];
   1107 		if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
   1108 			_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
   1109 		ptr=srcPlanes[i];
   1110 		for(row=0; row<ph[i]; row++)
   1111 		{
   1112 			inbuf[i][row]=ptr;
   1113 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
   1114 		}
   1115 	}
   1116 	if(usetmpbuf)
   1117 	{
   1118 		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
   1119 			_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
   1120 		ptr=_tmpbuf;
   1121 		for(i=0; i<cinfo->num_components; i++)
   1122 		{
   1123 			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
   1124 				_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
   1125 			for(row=0; row<th[i]; row++)
   1126 			{
   1127 				tmpbuf[i][row]=ptr;
   1128 				ptr+=iw[i];
   1129 			}
   1130 		}
   1131 	}
   1132 
   1133 	for(row=0; row<(int)cinfo->image_height;
   1134 		row+=cinfo->max_v_samp_factor*DCTSIZE)
   1135 	{
   1136 		JSAMPARRAY yuvptr[MAX_COMPONENTS];
   1137 		int crow[MAX_COMPONENTS];
   1138 		for(i=0; i<cinfo->num_components; i++)
   1139 		{
   1140 			jpeg_component_info *compptr=&cinfo->comp_info[i];
   1141 			crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
   1142 			if(usetmpbuf)
   1143 			{
   1144 				int j, k;
   1145 				for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
   1146 				{
   1147 					memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], pw[i]);
   1148 					/* Duplicate last sample in row to fill out MCU */
   1149 					for(k=pw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][pw[i]-1];
   1150 				}
   1151 				/* Duplicate last row to fill out MCU */
   1152 				for(j=ph[i]-crow[i]; j<th[i]; j++)
   1153 					memcpy(tmpbuf[i][j], tmpbuf[i][ph[i]-crow[i]-1], iw[i]);
   1154 				yuvptr[i]=tmpbuf[i];
   1155 			}
   1156 			else
   1157 				yuvptr[i]=&inbuf[i][crow[i]];
   1158 		}
   1159 		jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
   1160 	}
   1161 	jpeg_finish_compress(cinfo);
   1162 
   1163 	bailout:
   1164 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
   1165 	for(i=0; i<MAX_COMPONENTS; i++)
   1166 	{
   1167 		if(tmpbuf[i]) free(tmpbuf[i]);
   1168 		if(inbuf[i]) free(inbuf[i]);
   1169 	}
   1170 	if(_tmpbuf) free(_tmpbuf);
   1171 	if(this->jerr.warning) retval=-1;
   1172 	return retval;
   1173 }
   1174 
   1175 DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle, unsigned char *srcBuf,
   1176 	int width, int pad, int height, int subsamp, unsigned char **jpegBuf,
   1177 	unsigned long *jpegSize, int jpegQual, int flags)
   1178 {
   1179 	unsigned char *srcPlanes[3];
   1180 	int pw0, ph0, strides[3], retval=-1;
   1181 
   1182 	if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
   1183 		|| subsamp>=NUMSUBOPT)
   1184 		_throw("tjCompressFromYUV(): Invalid argument");
   1185 
   1186 	pw0=tjPlaneWidth(0, width, subsamp);
   1187 	ph0=tjPlaneHeight(0, height, subsamp);
   1188 	srcPlanes[0]=srcBuf;
   1189 	strides[0]=PAD(pw0, pad);
   1190 	if(subsamp==TJSAMP_GRAY)
   1191 	{
   1192 		strides[1]=strides[2]=0;
   1193 		srcPlanes[1]=srcPlanes[2]=NULL;
   1194 	}
   1195 	else
   1196 	{
   1197 		int pw1=tjPlaneWidth(1, width, subsamp);
   1198 		int ph1=tjPlaneHeight(1, height, subsamp);
   1199 		strides[1]=strides[2]=PAD(pw1, pad);
   1200 		srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
   1201 		srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
   1202 	}
   1203 
   1204 	return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
   1205 		subsamp, jpegBuf, jpegSize, jpegQual, flags);
   1206 
   1207 	bailout:
   1208 	return retval;
   1209 }
   1210 
   1211 
   1212 /* Decompressor */
   1213 
   1214 static tjhandle _tjInitDecompress(tjinstance *this)
   1215 {
   1216 	unsigned char buffer[1];
   1217 
   1218 	/* This is also straight out of example.c */
   1219 	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
   1220 	this->jerr.pub.error_exit=my_error_exit;
   1221 	this->jerr.pub.output_message=my_output_message;
   1222 	this->jerr.emit_message=this->jerr.pub.emit_message;
   1223 	this->jerr.pub.emit_message=my_emit_message;
   1224 
   1225 	if(setjmp(this->jerr.setjmp_buffer))
   1226 	{
   1227 		/* If we get here, the JPEG code has signaled an error. */
   1228 		if(this) free(this);  return NULL;
   1229 	}
   1230 
   1231 	jpeg_create_decompress(&this->dinfo);
   1232 	/* Make an initial call so it will create the source manager */
   1233 	jpeg_mem_src_tj(&this->dinfo, buffer, 1);
   1234 
   1235 	this->init|=DECOMPRESS;
   1236 	return (tjhandle)this;
   1237 }
   1238 
   1239 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
   1240 {
   1241 	tjinstance *this;
   1242 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
   1243 	{
   1244 		snprintf(errStr, JMSG_LENGTH_MAX,
   1245 			"tjInitDecompress(): Memory allocation failure");
   1246 		return NULL;
   1247 	}
   1248 	MEMZERO(this, sizeof(tjinstance));
   1249 	return _tjInitDecompress(this);
   1250 }
   1251 
   1252 
   1253 DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
   1254 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
   1255 	int *jpegSubsamp, int *jpegColorspace)
   1256 {
   1257 	int retval=0;
   1258 
   1259 	getdinstance(handle);
   1260 	if((this->init&DECOMPRESS)==0)
   1261 		_throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
   1262 
   1263 	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
   1264 		|| jpegSubsamp==NULL || jpegColorspace==NULL)
   1265 		_throw("tjDecompressHeader3(): Invalid argument");
   1266 
   1267 	if(setjmp(this->jerr.setjmp_buffer))
   1268 	{
   1269 		/* If we get here, the JPEG code has signaled an error. */
   1270 		return -1;
   1271 	}
   1272 
   1273 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
   1274 	jpeg_read_header(dinfo, TRUE);
   1275 
   1276 	*width=dinfo->image_width;
   1277 	*height=dinfo->image_height;
   1278 	*jpegSubsamp=getSubsamp(dinfo);
   1279 	switch(dinfo->jpeg_color_space)
   1280 	{
   1281 		case JCS_GRAYSCALE:  *jpegColorspace=TJCS_GRAY;  break;
   1282 		case JCS_RGB:        *jpegColorspace=TJCS_RGB;  break;
   1283 		case JCS_YCbCr:      *jpegColorspace=TJCS_YCbCr;  break;
   1284 		case JCS_CMYK:       *jpegColorspace=TJCS_CMYK;  break;
   1285 		case JCS_YCCK:       *jpegColorspace=TJCS_YCCK;  break;
   1286 		default:             *jpegColorspace=-1;  break;
   1287 	}
   1288 
   1289 	jpeg_abort_decompress(dinfo);
   1290 
   1291 	if(*jpegSubsamp<0)
   1292 		_throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
   1293 	if(*jpegColorspace<0)
   1294 		_throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
   1295 	if(*width<1 || *height<1)
   1296 		_throw("tjDecompressHeader3(): Invalid data returned in header");
   1297 
   1298 	bailout:
   1299 	if(this->jerr.warning) retval=-1;
   1300 	return retval;
   1301 }
   1302 
   1303 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
   1304 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
   1305 	int *jpegSubsamp)
   1306 {
   1307 	int jpegColorspace;
   1308 	return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
   1309 		jpegSubsamp, &jpegColorspace);
   1310 }
   1311 
   1312 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
   1313 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
   1314 {
   1315 	int jpegSubsamp;
   1316 	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
   1317 		&jpegSubsamp);
   1318 }
   1319 
   1320 
   1321 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
   1322 {
   1323 	if(numscalingfactors==NULL)
   1324 	{
   1325 		snprintf(errStr, JMSG_LENGTH_MAX,
   1326 			"tjGetScalingFactors(): Invalid argument");
   1327 		return NULL;
   1328 	}
   1329 
   1330 	*numscalingfactors=NUMSF;
   1331 	return (tjscalingfactor *)sf;
   1332 }
   1333 
   1334 
   1335 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
   1336 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
   1337 	int height, int pixelFormat, int flags)
   1338 {
   1339 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
   1340 	int jpegwidth, jpegheight, scaledw, scaledh;
   1341 	#ifndef JCS_EXTENSIONS
   1342 	unsigned char *rgbBuf=NULL;
   1343 	unsigned char *_dstBuf=NULL;  int _pitch=0;
   1344 	#endif
   1345 
   1346 	getdinstance(handle);
   1347 	if((this->init&DECOMPRESS)==0)
   1348 		_throw("tjDecompress2(): Instance has not been initialized for decompression");
   1349 
   1350 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
   1351 		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
   1352 		_throw("tjDecompress2(): Invalid argument");
   1353 
   1354 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
   1355 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
   1356 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
   1357 
   1358 	if(setjmp(this->jerr.setjmp_buffer))
   1359 	{
   1360 		/* If we get here, the JPEG code has signaled an error. */
   1361 		retval=-1;
   1362 		goto bailout;
   1363 	}
   1364 
   1365 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
   1366 	jpeg_read_header(dinfo, TRUE);
   1367 	if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
   1368 	{
   1369 		retval=-1;  goto bailout;
   1370 	}
   1371 
   1372 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
   1373 
   1374 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
   1375 	if(width==0) width=jpegwidth;
   1376 	if(height==0) height=jpegheight;
   1377 	for(i=0; i<NUMSF; i++)
   1378 	{
   1379 		scaledw=TJSCALED(jpegwidth, sf[i]);
   1380 		scaledh=TJSCALED(jpegheight, sf[i]);
   1381 		if(scaledw<=width && scaledh<=height)
   1382 			break;
   1383 	}
   1384 	if(i>=NUMSF)
   1385 		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
   1386 	width=scaledw;  height=scaledh;
   1387 	dinfo->scale_num=sf[i].num;
   1388 	dinfo->scale_denom=sf[i].denom;
   1389 
   1390 	jpeg_start_decompress(dinfo);
   1391 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
   1392 
   1393 	#ifndef JCS_EXTENSIONS
   1394 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
   1395 		(RGB_RED!=tjRedOffset[pixelFormat] ||
   1396 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
   1397 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
   1398 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
   1399 	{
   1400 		rgbBuf=(unsigned char *)malloc(width*height*3);
   1401 		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
   1402 		_pitch=pitch;  pitch=width*3;
   1403 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
   1404 	}
   1405 	#endif
   1406 
   1407 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
   1408 		*dinfo->output_height))==NULL)
   1409 		_throw("tjDecompress2(): Memory allocation failure");
   1410 	for(i=0; i<(int)dinfo->output_height; i++)
   1411 	{
   1412 		if(flags&TJFLAG_BOTTOMUP)
   1413 			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
   1414 		else row_pointer[i]=&dstBuf[i*pitch];
   1415 	}
   1416 	while(dinfo->output_scanline<dinfo->output_height)
   1417 	{
   1418 		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
   1419 			dinfo->output_height-dinfo->output_scanline);
   1420 	}
   1421 	jpeg_finish_decompress(dinfo);
   1422 
   1423 	#ifndef JCS_EXTENSIONS
   1424 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
   1425 	#endif
   1426 
   1427 	bailout:
   1428 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
   1429 	#ifndef JCS_EXTENSIONS
   1430 	if(rgbBuf) free(rgbBuf);
   1431 	#endif
   1432 	if(row_pointer) free(row_pointer);
   1433 	if(this->jerr.warning) retval=-1;
   1434 	return retval;
   1435 }
   1436 
   1437 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
   1438 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
   1439 	int height, int pixelSize, int flags)
   1440 {
   1441 	if(flags&TJ_YUV)
   1442 		return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
   1443 	else
   1444 		return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
   1445 			height, getPixelFormat(pixelSize, flags), flags);
   1446 }
   1447 
   1448 
   1449 static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
   1450 	int pixelFormat, int subsamp, int flags)
   1451 {
   1452 	int i;
   1453 
   1454 	dinfo->scale_num=dinfo->scale_denom=1;
   1455 
   1456 	if(subsamp==TJSAMP_GRAY)
   1457 	{
   1458 		dinfo->num_components=dinfo->comps_in_scan=1;
   1459 		dinfo->jpeg_color_space=JCS_GRAYSCALE;
   1460 	}
   1461 	else
   1462 	{
   1463 		dinfo->num_components=dinfo->comps_in_scan=3;
   1464 		dinfo->jpeg_color_space=JCS_YCbCr;
   1465 	}
   1466 
   1467 	dinfo->comp_info=(jpeg_component_info *)
   1468 		(*dinfo->mem->alloc_small)((j_common_ptr)dinfo, JPOOL_IMAGE,
   1469 			dinfo->num_components*sizeof(jpeg_component_info));
   1470 
   1471 	for(i=0; i<dinfo->num_components; i++)
   1472 	{
   1473 		jpeg_component_info *compptr=&dinfo->comp_info[i];
   1474 		compptr->h_samp_factor=(i==0)? tjMCUWidth[subsamp]/8:1;
   1475 		compptr->v_samp_factor=(i==0)? tjMCUHeight[subsamp]/8:1;
   1476 		compptr->component_index=i;
   1477 		compptr->component_id=i+1;
   1478 		compptr->quant_tbl_no=compptr->dc_tbl_no=compptr->ac_tbl_no=
   1479 			(i==0)? 0:1;
   1480 		dinfo->cur_comp_info[i]=compptr;
   1481 	}
   1482 	dinfo->data_precision=8;
   1483 	for(i=0; i<2; i++)
   1484 	{
   1485 		if(dinfo->quant_tbl_ptrs[i]==NULL)
   1486 			dinfo->quant_tbl_ptrs[i]=jpeg_alloc_quant_table((j_common_ptr)dinfo);
   1487 	}
   1488 
   1489 	return 0;
   1490 }
   1491 
   1492 
   1493 int my_read_markers(j_decompress_ptr dinfo)
   1494 {
   1495 	return JPEG_REACHED_SOS;
   1496 }
   1497 
   1498 void my_reset_marker_reader(j_decompress_ptr dinfo)
   1499 {
   1500 }
   1501 
   1502 DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
   1503 	unsigned char **srcPlanes, int *strides, int subsamp, unsigned char *dstBuf,
   1504 	int width, int pitch, int height, int pixelFormat, int flags)
   1505 {
   1506 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
   1507 	JSAMPLE *_tmpbuf[MAX_COMPONENTS];
   1508 	JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
   1509 	int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
   1510 	JSAMPLE *ptr;
   1511 	jpeg_component_info *compptr;
   1512 	#ifndef JCS_EXTENSIONS
   1513 	unsigned char *rgbBuf=NULL;
   1514 	unsigned char *_dstBuf=NULL;  int _pitch=0;
   1515 	#endif
   1516 	int (*old_read_markers)(j_decompress_ptr);
   1517 	void (*old_reset_marker_reader)(j_decompress_ptr);
   1518 
   1519 	getdinstance(handle);
   1520 
   1521 	for(i=0; i<MAX_COMPONENTS; i++)
   1522 	{
   1523 		tmpbuf[i]=NULL;  _tmpbuf[i]=NULL;  inbuf[i]=NULL;
   1524 	}
   1525 
   1526 	if((this->init&DECOMPRESS)==0)
   1527 		_throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
   1528 
   1529 	if(!srcPlanes || !srcPlanes[0] || subsamp<0 || subsamp>=NUMSUBOPT
   1530 		|| dstBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
   1531 		|| pixelFormat>=TJ_NUMPF)
   1532 		_throw("tjDecodeYUVPlanes(): Invalid argument");
   1533 	if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
   1534 		_throw("tjDecodeYUVPlanes(): Invalid argument");
   1535 
   1536 	if(setjmp(this->jerr.setjmp_buffer))
   1537 	{
   1538 		/* If we get here, the JPEG code has signaled an error. */
   1539 		retval=-1;
   1540 		goto bailout;
   1541 	}
   1542 
   1543 	if(pixelFormat==TJPF_CMYK)
   1544 		_throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
   1545 
   1546 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
   1547 	dinfo->image_width=width;
   1548 	dinfo->image_height=height;
   1549 
   1550 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
   1551 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
   1552 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
   1553 
   1554 	if(setDecodeDefaults(dinfo, pixelFormat, subsamp, flags)==-1)
   1555 	{
   1556 		retval=-1;  goto bailout;
   1557 	}
   1558 	old_read_markers=dinfo->marker->read_markers;
   1559 	dinfo->marker->read_markers=my_read_markers;
   1560 	old_reset_marker_reader=dinfo->marker->reset_marker_reader;
   1561 	dinfo->marker->reset_marker_reader=my_reset_marker_reader;
   1562 	jpeg_read_header(dinfo, TRUE);
   1563 	dinfo->marker->read_markers=old_read_markers;
   1564 	dinfo->marker->reset_marker_reader=old_reset_marker_reader;
   1565 
   1566 	if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
   1567 	{
   1568 		retval=-1;  goto bailout;
   1569 	}
   1570 	dinfo->do_fancy_upsampling=FALSE;
   1571 	dinfo->Se=DCTSIZE2-1;
   1572 	jinit_master_decompress(dinfo);
   1573 	(*dinfo->upsample->start_pass)(dinfo);
   1574 
   1575 	pw0=PAD(width, dinfo->max_h_samp_factor);
   1576 	ph0=PAD(height, dinfo->max_v_samp_factor);
   1577 
   1578 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
   1579 
   1580 	#ifndef JCS_EXTENSIONS
   1581 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
   1582 		(RGB_RED!=tjRedOffset[pixelFormat] ||
   1583 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
   1584 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
   1585 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
   1586 	{
   1587 		rgbBuf=(unsigned char *)malloc(width*height*3);
   1588 		if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
   1589 		_pitch=pitch;  pitch=width*3;
   1590 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
   1591 	}
   1592 	#endif
   1593 
   1594 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
   1595 		_throw("tjDecodeYUVPlanes(): Memory allocation failure");
   1596 	for(i=0; i<height; i++)
   1597 	{
   1598 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch];
   1599 		else row_pointer[i]=&dstBuf[i*pitch];
   1600 	}
   1601 	if(height<ph0)
   1602 		for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
   1603 
   1604 	for(i=0; i<dinfo->num_components; i++)
   1605 	{
   1606 		compptr=&dinfo->comp_info[i];
   1607 		_tmpbuf[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
   1608 			* compptr->v_samp_factor + 16);
   1609 		if(!_tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
   1610 		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
   1611 		if(!tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
   1612 		for(row=0; row<compptr->v_samp_factor; row++)
   1613 		{
   1614 			unsigned char *_tmpbuf_aligned=
   1615 				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
   1616 			tmpbuf[i][row]=&_tmpbuf_aligned[
   1617 				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
   1618 		}
   1619 		pw[i]=pw0*compptr->h_samp_factor/dinfo->max_h_samp_factor;
   1620 		ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor;
   1621 		inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
   1622 		if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
   1623 		ptr=srcPlanes[i];
   1624 		for(row=0; row<ph[i]; row++)
   1625 		{
   1626 			inbuf[i][row]=ptr;
   1627 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
   1628 		}
   1629 	}
   1630 
   1631 	for(row=0; row<ph0; row+=dinfo->max_v_samp_factor)
   1632 	{
   1633 		JDIMENSION inrow=0, outrow=0;
   1634 		for(i=0, compptr=dinfo->comp_info; i<dinfo->num_components; i++, compptr++)
   1635 			jcopy_sample_rows(inbuf[i],
   1636 				row*compptr->v_samp_factor/dinfo->max_v_samp_factor, tmpbuf[i], 0,
   1637 				compptr->v_samp_factor, pw[i]);
   1638 		(dinfo->upsample->upsample)(dinfo, tmpbuf, &inrow,
   1639 			dinfo->max_v_samp_factor, &row_pointer[row], &outrow,
   1640 			dinfo->max_v_samp_factor);
   1641 	}
   1642 	jpeg_abort_decompress(dinfo);
   1643 
   1644 	#ifndef JCS_EXTENSIONS
   1645 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
   1646 	#endif
   1647 
   1648 	bailout:
   1649 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
   1650 	#ifndef JCS_EXTENSIONS
   1651 	if(rgbBuf) free(rgbBuf);
   1652 	#endif
   1653 	if(row_pointer) free(row_pointer);
   1654 	for(i=0; i<MAX_COMPONENTS; i++)
   1655 	{
   1656 		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
   1657 		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
   1658 		if(inbuf[i]!=NULL) free(inbuf[i]);
   1659 	}
   1660 	if(this->jerr.warning) retval=-1;
   1661 	return retval;
   1662 }
   1663 
   1664 DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, unsigned char *srcBuf,
   1665 	int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
   1666 	int height, int pixelFormat, int flags)
   1667 {
   1668 	unsigned char *srcPlanes[3];
   1669 	int pw0, ph0, strides[3], retval=-1;
   1670 
   1671 	if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
   1672 		|| width<=0 || height<=0)
   1673 		_throw("tjDecodeYUV(): Invalid argument");
   1674 
   1675 	pw0=tjPlaneWidth(0, width, subsamp);
   1676 	ph0=tjPlaneHeight(0, height, subsamp);
   1677 	srcPlanes[0]=srcBuf;
   1678 	strides[0]=PAD(pw0, pad);
   1679 	if(subsamp==TJSAMP_GRAY)
   1680 	{
   1681 		strides[1]=strides[2]=0;
   1682 		srcPlanes[1]=srcPlanes[2]=NULL;
   1683 	}
   1684 	else
   1685 	{
   1686 		int pw1=tjPlaneWidth(1, width, subsamp);
   1687 		int ph1=tjPlaneHeight(1, height, subsamp);
   1688 		strides[1]=strides[2]=PAD(pw1, pad);
   1689 		srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
   1690 		srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
   1691 	}
   1692 
   1693 	return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
   1694 		pitch, height, pixelFormat, flags);
   1695 
   1696 	bailout:
   1697 	return retval;
   1698 }
   1699 
   1700 DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
   1701 	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char **dstPlanes,
   1702 	int width, int *strides, int height, int flags)
   1703 {
   1704 	int i, sfi, row, retval=0;  JSAMPROW *outbuf[MAX_COMPONENTS];
   1705 	int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
   1706 	int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
   1707 		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
   1708 	JSAMPLE *_tmpbuf=NULL, *ptr;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
   1709 	int dctsize;
   1710 
   1711 	getdinstance(handle);
   1712 
   1713 	for(i=0; i<MAX_COMPONENTS; i++)
   1714 	{
   1715 		tmpbuf[i]=NULL;  outbuf[i]=NULL;
   1716 	}
   1717 
   1718 	if((this->init&DECOMPRESS)==0)
   1719 		_throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
   1720 
   1721 	if(jpegBuf==NULL || jpegSize<=0 || !dstPlanes || !dstPlanes[0] || width<0
   1722 		|| height<0)
   1723 		_throw("tjDecompressToYUVPlanes(): Invalid argument");
   1724 
   1725 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
   1726 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
   1727 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
   1728 
   1729 	if(setjmp(this->jerr.setjmp_buffer))
   1730 	{
   1731 		/* If we get here, the JPEG code has signaled an error. */
   1732 		retval=-1;
   1733 		goto bailout;
   1734 	}
   1735 
   1736 	if(!this->headerRead)
   1737 	{
   1738 		jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
   1739 		jpeg_read_header(dinfo, TRUE);
   1740 	}
   1741 	this->headerRead=0;
   1742 	jpegSubsamp=getSubsamp(dinfo);
   1743 	if(jpegSubsamp<0)
   1744 		_throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
   1745 
   1746 	if(jpegSubsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
   1747 		_throw("tjDecompressToYUVPlanes(): Invalid argument");
   1748 
   1749 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
   1750 	if(width==0) width=jpegwidth;
   1751 	if(height==0) height=jpegheight;
   1752 	for(i=0; i<NUMSF; i++)
   1753 	{
   1754 		scaledw=TJSCALED(jpegwidth, sf[i]);
   1755 		scaledh=TJSCALED(jpegheight, sf[i]);
   1756 		if(scaledw<=width && scaledh<=height)
   1757 			break;
   1758 	}
   1759 	if(i>=NUMSF)
   1760 		_throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
   1761 	if(dinfo->num_components>3)
   1762 		_throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
   1763 
   1764 	width=scaledw;  height=scaledh;
   1765 	dinfo->scale_num=sf[i].num;
   1766 	dinfo->scale_denom=sf[i].denom;
   1767 	sfi=i;
   1768 	jpeg_calc_output_dimensions(dinfo);
   1769 
   1770 	dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
   1771 
   1772 	for(i=0; i<dinfo->num_components; i++)
   1773 	{
   1774 		jpeg_component_info *compptr=&dinfo->comp_info[i];
   1775 		int ih;
   1776 		iw[i]=compptr->width_in_blocks*dctsize;
   1777 		ih=compptr->height_in_blocks*dctsize;
   1778 		pw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
   1779 			*compptr->h_samp_factor/dinfo->max_h_samp_factor;
   1780 		ph[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
   1781 			*compptr->v_samp_factor/dinfo->max_v_samp_factor;
   1782 		if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
   1783 		th[i]=compptr->v_samp_factor*dctsize;
   1784 		tmpbufsize+=iw[i]*th[i];
   1785 		if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
   1786 			_throw("tjDecompressToYUVPlanes(): Memory allocation failure");
   1787 		ptr=dstPlanes[i];
   1788 		for(row=0; row<ph[i]; row++)
   1789 		{
   1790 			outbuf[i][row]=ptr;
   1791 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
   1792 		}
   1793 	}
   1794 	if(usetmpbuf)
   1795 	{
   1796 		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
   1797 			_throw("tjDecompressToYUVPlanes(): Memory allocation failure");
   1798 		ptr=_tmpbuf;
   1799 		for(i=0; i<dinfo->num_components; i++)
   1800 		{
   1801 			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
   1802 				_throw("tjDecompressToYUVPlanes(): Memory allocation failure");
   1803 			for(row=0; row<th[i]; row++)
   1804 			{
   1805 				tmpbuf[i][row]=ptr;
   1806 				ptr+=iw[i];
   1807 			}
   1808 		}
   1809 	}
   1810 
   1811 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
   1812 	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
   1813 	dinfo->raw_data_out=TRUE;
   1814 
   1815 	jpeg_start_decompress(dinfo);
   1816 	for(row=0; row<(int)dinfo->output_height;
   1817 		row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
   1818 	{
   1819 		JSAMPARRAY yuvptr[MAX_COMPONENTS];
   1820 		int crow[MAX_COMPONENTS];
   1821 		for(i=0; i<dinfo->num_components; i++)
   1822 		{
   1823 			jpeg_component_info *compptr=&dinfo->comp_info[i];
   1824 			if(jpegSubsamp==TJ_420)
   1825 			{
   1826 				/* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
   1827 				   to be clever and use the IDCT to perform upsampling on the U and V
   1828 				   planes.  For instance, if the output image is to be scaled by 1/2
   1829 				   relative to the JPEG image, then the scaling factor and upsampling
   1830 				   effectively cancel each other, so a normal 8x8 IDCT can be used.
   1831 				   However, this is not desirable when using the decompress-to-YUV
   1832 				   functionality in TurboJPEG, since we want to output the U and V
   1833 				   planes in their subsampled form.  Thus, we have to override some
   1834 				   internal libjpeg parameters to force it to use the "scaled" IDCT
   1835 				   functions on the U and V planes. */
   1836 				compptr->_DCT_scaled_size=dctsize;
   1837 				compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
   1838 					sf[sfi].num/sf[sfi].denom*
   1839 					compptr->v_samp_factor/dinfo->max_v_samp_factor;
   1840 				dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
   1841 			}
   1842 			crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
   1843 			if(usetmpbuf) yuvptr[i]=tmpbuf[i];
   1844 			else yuvptr[i]=&outbuf[i][crow[i]];
   1845 		}
   1846 		jpeg_read_raw_data(dinfo, yuvptr,
   1847 			dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
   1848 		if(usetmpbuf)
   1849 		{
   1850 			int j;
   1851 			for(i=0; i<dinfo->num_components; i++)
   1852 			{
   1853 				for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
   1854 				{
   1855 					memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], pw[i]);
   1856 				}
   1857 			}
   1858 		}
   1859 	}
   1860 	jpeg_finish_decompress(dinfo);
   1861 
   1862 	bailout:
   1863 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
   1864 	for(i=0; i<MAX_COMPONENTS; i++)
   1865 	{
   1866 		if(tmpbuf[i]) free(tmpbuf[i]);
   1867 		if(outbuf[i]) free(outbuf[i]);
   1868 	}
   1869 	if(_tmpbuf) free(_tmpbuf);
   1870 	if(this->jerr.warning) retval=-1;
   1871 	return retval;
   1872 }
   1873 
   1874 DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
   1875 	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
   1876 	int width, int pad, int height, int flags)
   1877 {
   1878 	unsigned char *dstPlanes[3];
   1879 	int pw0, ph0, strides[3], retval=-1, jpegSubsamp=-1;
   1880 	int i, jpegwidth, jpegheight, scaledw, scaledh;
   1881 
   1882 	getdinstance(handle);
   1883 
   1884 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
   1885 		|| !isPow2(pad) || height<0)
   1886 		_throw("tjDecompressToYUV2(): Invalid argument");
   1887 
   1888 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
   1889 	jpeg_read_header(dinfo, TRUE);
   1890 	jpegSubsamp=getSubsamp(dinfo);
   1891 	if(jpegSubsamp<0)
   1892 		_throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
   1893 
   1894 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
   1895 	if(width==0) width=jpegwidth;
   1896 	if(height==0) height=jpegheight;
   1897 
   1898 	for(i=0; i<NUMSF; i++)
   1899 	{
   1900 		scaledw=TJSCALED(jpegwidth, sf[i]);
   1901 		scaledh=TJSCALED(jpegheight, sf[i]);
   1902 		if(scaledw<=width && scaledh<=height)
   1903 			break;
   1904 	}
   1905 	if(i>=NUMSF)
   1906 		_throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
   1907 
   1908 	pw0=tjPlaneWidth(0, width, jpegSubsamp);
   1909 	ph0=tjPlaneHeight(0, height, jpegSubsamp);
   1910 	dstPlanes[0]=dstBuf;
   1911 	strides[0]=PAD(pw0, pad);
   1912 	if(jpegSubsamp==TJSAMP_GRAY)
   1913 	{
   1914 		strides[1]=strides[2]=0;
   1915 		dstPlanes[1]=dstPlanes[2]=NULL;
   1916 	}
   1917 	else
   1918 	{
   1919 		int pw1=tjPlaneWidth(1, width, jpegSubsamp);
   1920 		int ph1=tjPlaneHeight(1, height, jpegSubsamp);
   1921 		strides[1]=strides[2]=PAD(pw1, pad);
   1922 		dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
   1923 		dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
   1924 	}
   1925 
   1926 	this->headerRead=1;
   1927 	return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
   1928 		strides, height, flags);
   1929 
   1930 	bailout:
   1931 	return retval;
   1932 
   1933 }
   1934 
   1935 DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
   1936 	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
   1937 	int flags)
   1938 {
   1939 	return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
   1940 }
   1941 
   1942 
   1943 /* Transformer */
   1944 
   1945 DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
   1946 {
   1947 	tjinstance *this=NULL;  tjhandle handle=NULL;
   1948 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
   1949 	{
   1950 		snprintf(errStr, JMSG_LENGTH_MAX,
   1951 			"tjInitTransform(): Memory allocation failure");
   1952 		return NULL;
   1953 	}
   1954 	MEMZERO(this, sizeof(tjinstance));
   1955 	handle=_tjInitCompress(this);
   1956 	if(!handle) return NULL;
   1957 	handle=_tjInitDecompress(this);
   1958 	return handle;
   1959 }
   1960 
   1961 
   1962 DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
   1963 	unsigned long jpegSize, int n, unsigned char **dstBufs,
   1964 	unsigned long *dstSizes, tjtransform *t, int flags)
   1965 {
   1966 	jpeg_transform_info *xinfo=NULL;
   1967 	jvirt_barray_ptr *srccoefs, *dstcoefs;
   1968 	int retval=0, i, jpegSubsamp;
   1969 
   1970 	getinstance(handle);
   1971 	if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
   1972 		_throw("tjTransform(): Instance has not been initialized for transformation");
   1973 
   1974 	if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
   1975 		|| t==NULL || flags<0)
   1976 		_throw("tjTransform(): Invalid argument");
   1977 
   1978 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
   1979 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
   1980 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
   1981 
   1982 	if(setjmp(this->jerr.setjmp_buffer))
   1983 	{
   1984 		/* If we get here, the JPEG code has signaled an error. */
   1985 		retval=-1;
   1986 		goto bailout;
   1987 	}
   1988 
   1989 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
   1990 
   1991 	if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
   1992 		==NULL)
   1993 		_throw("tjTransform(): Memory allocation failure");
   1994 	MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
   1995 
   1996 	for(i=0; i<n; i++)
   1997 	{
   1998 		xinfo[i].transform=xformtypes[t[i].op];
   1999 		xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
   2000 		xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
   2001 		xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
   2002 		xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
   2003 		if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
   2004 		else xinfo[i].slow_hflip=0;
   2005 
   2006 		if(xinfo[i].crop)
   2007 		{
   2008 			xinfo[i].crop_xoffset=t[i].r.x;  xinfo[i].crop_xoffset_set=JCROP_POS;
   2009 			xinfo[i].crop_yoffset=t[i].r.y;  xinfo[i].crop_yoffset_set=JCROP_POS;
   2010 			if(t[i].r.w!=0)
   2011 			{
   2012 				xinfo[i].crop_width=t[i].r.w;  xinfo[i].crop_width_set=JCROP_POS;
   2013 			}
   2014 			else xinfo[i].crop_width=JCROP_UNSET;
   2015 			if(t[i].r.h!=0)
   2016 			{
   2017 				xinfo[i].crop_height=t[i].r.h;  xinfo[i].crop_height_set=JCROP_POS;
   2018 			}
   2019 			else xinfo[i].crop_height=JCROP_UNSET;
   2020 		}
   2021 	}
   2022 
   2023 	jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
   2024 	jpeg_read_header(dinfo, TRUE);
   2025 	jpegSubsamp=getSubsamp(dinfo);
   2026 	if(jpegSubsamp<0)
   2027 		_throw("tjTransform(): Could not determine subsampling type for JPEG image");
   2028 
   2029 	for(i=0; i<n; i++)
   2030 	{
   2031 		if(!jtransform_request_workspace(dinfo, &xinfo[i]))
   2032 			_throw("tjTransform(): Transform is not perfect");
   2033 
   2034 		if(xinfo[i].crop)
   2035 		{
   2036 			if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
   2037 				|| (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
   2038 			{
   2039 				snprintf(errStr, JMSG_LENGTH_MAX,
   2040 					"To crop this JPEG image, x must be a multiple of %d\n"
   2041 					"and y must be a multiple of %d.\n",
   2042 					xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
   2043 				retval=-1;  goto bailout;
   2044 			}
   2045 		}
   2046 	}
   2047 
   2048 	srccoefs=jpeg_read_coefficients(dinfo);
   2049 
   2050 	for(i=0; i<n; i++)
   2051 	{
   2052 		int w, h, alloc=1;
   2053 		if(!xinfo[i].crop)
   2054 		{
   2055 			w=dinfo->image_width;  h=dinfo->image_height;
   2056 		}
   2057 		else
   2058 		{
   2059 			w=xinfo[i].crop_width;  h=xinfo[i].crop_height;
   2060 		}
   2061 		if(flags&TJFLAG_NOREALLOC)
   2062 		{
   2063 			alloc=0;  dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
   2064 		}
   2065 		if(!(t[i].options&TJXOPT_NOOUTPUT))
   2066 			jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
   2067 		jpeg_copy_critical_parameters(dinfo, cinfo);
   2068 		dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
   2069 			&xinfo[i]);
   2070 		if(!(t[i].options&TJXOPT_NOOUTPUT))
   2071 		{
   2072 			jpeg_write_coefficients(cinfo, dstcoefs);
   2073 			jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
   2074 		}
   2075 		else jinit_c_master_control(cinfo, TRUE);
   2076 		jtransform_execute_transformation(dinfo, cinfo, srccoefs,
   2077 			&xinfo[i]);
   2078 		if(t[i].customFilter)
   2079 		{
   2080 			int ci, y;  JDIMENSION by;
   2081 			for(ci=0; ci<cinfo->num_components; ci++)
   2082 			{
   2083 				jpeg_component_info *compptr=&cinfo->comp_info[ci];
   2084 				tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
   2085 					DCTSIZE};
   2086 				tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
   2087 					compptr->height_in_blocks*DCTSIZE};
   2088 				for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
   2089 				{
   2090 					JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
   2091 						((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
   2092 						TRUE);
   2093 					for(y=0; y<compptr->v_samp_factor; y++)
   2094 					{
   2095 						if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
   2096 							ci, i, &t[i])==-1)
   2097 							_throw("tjTransform(): Error in custom filter");
   2098 						arrayRegion.y+=DCTSIZE;
   2099 					}
   2100 				}
   2101 			}
   2102 		}
   2103 		if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
   2104 	}
   2105 
   2106 	jpeg_finish_decompress(dinfo);
   2107 
   2108 	bailout:
   2109 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
   2110 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
   2111 	if(xinfo) free(xinfo);
   2112 	if(this->jerr.warning) retval=-1;
   2113 	return retval;
   2114 }
   2115