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
45extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
46	unsigned long *, boolean);
47extern 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
55static char errStr[JMSG_LENGTH_MAX]="No error";
56
57struct 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};
64typedef struct my_error_mgr *my_error_ptr;
65
66static 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
75static void my_output_message(j_common_ptr cinfo)
76{
77	(*cinfo->err->format_message)(cinfo, errStr);
78}
79
80static 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
90enum {COMPRESS=1, DECOMPRESS=2};
91
92typedef 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
100static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};
101
102static 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
109static 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
149static 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
173static 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
274static 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
332static 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
397static 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
458static 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
521DLLEXPORT char* DLLCALL tjGetErrorStr(void)
522{
523	return errStr;
524}
525
526
527DLLEXPORT 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
543DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
544{
545	if(buf) free(buf);
546}
547
548
549DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
550{
551	return (unsigned char *)malloc(bytes);
552}
553
554
555/* Compressor  */
556
557static 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
582DLLEXPORT 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
596DLLEXPORT 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
615DLLEXPORT 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
631DLLEXPORT 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
653DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
654	int subsamp)
655{
656	return tjBufSizeYUV2(width, 4, height, subsamp);
657}
658
659DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
660	int subsamp)
661{
662	return tjBufSizeYUV(width, height, subsamp);
663}
664
665
666DLLEXPORT 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
687DLLEXPORT 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
708DLLEXPORT 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
731DLLEXPORT 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
808DLLEXPORT 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
830DLLEXPORT 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
991DLLEXPORT 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
1027DLLEXPORT 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
1035DLLEXPORT 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
1044DLLEXPORT 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
1175DLLEXPORT 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
1214static 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
1239DLLEXPORT 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
1253DLLEXPORT 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
1303DLLEXPORT 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
1312DLLEXPORT 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
1321DLLEXPORT 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
1335DLLEXPORT 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
1437DLLEXPORT 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
1449static 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
1493int my_read_markers(j_decompress_ptr dinfo)
1494{
1495	return JPEG_REACHED_SOS;
1496}
1497
1498void my_reset_marker_reader(j_decompress_ptr dinfo)
1499{
1500}
1501
1502DLLEXPORT 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
1664DLLEXPORT 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
1700DLLEXPORT 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
1874DLLEXPORT 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
1935DLLEXPORT 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
1945DLLEXPORT 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
1962DLLEXPORT 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