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