turbojpeg.c revision 54918b37fc858a50f8481ba3862e9bffa44c8b7f
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	if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
760
761	/* Execute only the parts of jpeg_start_compress() that we need.  If we
762	   were to call the whole jpeg_start_compress() function, then it would try
763	   to write the file headers, which could overflow the output buffer if the
764	   YUV image were very small. */
765	if(cinfo->global_state!=CSTATE_START)
766		_throw("tjEncodeYUV3(): libjpeg API is in the wrong state");
767	(*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
768	jinit_c_master_control(cinfo, FALSE);
769	jinit_color_converter(cinfo);
770	jinit_downsampler(cinfo);
771
772	pw=PAD(width, cinfo->max_h_samp_factor);
773	ph=PAD(height, cinfo->max_v_samp_factor);
774
775	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
776		_throw("tjEncodeYUV3(): Memory allocation failure");
777	for(i=0; i<height; i++)
778	{
779		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
780		else row_pointer[i]=&srcBuf[i*pitch];
781	}
782	if(height<ph)
783		for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
784
785	for(i=0; i<cinfo->num_components; i++)
786	{
787		compptr=&cinfo->comp_info[i];
788		_tmpbuf[i]=(JSAMPLE *)malloc(
789			PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
790				/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
791		if(!_tmpbuf[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
792		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
793		if(!tmpbuf[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
794		for(row=0; row<cinfo->max_v_samp_factor; row++)
795		{
796			unsigned char *_tmpbuf_aligned=
797				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
798			tmpbuf[i][row]=&_tmpbuf_aligned[
799				PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
800					/compptr->h_samp_factor, 16) * row];
801		}
802		_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
803			* compptr->v_samp_factor + 16);
804		if(!_tmpbuf2[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
805		tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
806		if(!tmpbuf2[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
807		for(row=0; row<compptr->v_samp_factor; row++)
808		{
809			unsigned char *_tmpbuf2_aligned=
810				(unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
811			tmpbuf2[i][row]=&_tmpbuf2_aligned[
812				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
813		}
814		cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
815		ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
816		outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
817		if(!outbuf[i]) _throw("tjEncodeYUV3(): Memory allocation failure");
818		for(row=0; row<ch[i]; row++)
819		{
820			outbuf[i][row]=ptr;
821			ptr+=PAD(cw[i], pad);
822		}
823	}
824	if(yuvsize!=(unsigned long)(ptr-dstBuf))
825		_throw("tjEncodeYUV3(): Generated image is not the correct size");
826
827	for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
828	{
829		(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
830			cinfo->max_v_samp_factor);
831		(cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
832		for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
833			jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
834				row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
835				compptr->v_samp_factor, cw[i]);
836	}
837	cinfo->next_scanline+=height;
838	jpeg_abort_compress(cinfo);
839
840	bailout:
841	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
842	#ifndef JCS_EXTENSIONS
843	if(rgbBuf) free(rgbBuf);
844	#endif
845	if(row_pointer) free(row_pointer);
846	for(i=0; i<MAX_COMPONENTS; i++)
847	{
848		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
849		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
850		if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
851		if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
852		if(outbuf[i]!=NULL) free(outbuf[i]);
853	}
854	return retval;
855}
856
857DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
858	int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
859	int subsamp, int flags)
860{
861	return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
862		dstBuf, 4, subsamp, flags);
863}
864
865DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
866	int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
867	int subsamp, int flags)
868{
869	return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
870		getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
871}
872
873
874DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle, unsigned char *srcBuf,
875	int width, int pad, int height, int subsamp, unsigned char **jpegBuf,
876	unsigned long *jpegSize, int jpegQual, int flags)
877{
878	int i, row, retval=0, alloc=1;  JSAMPROW *inbuf[MAX_COMPONENTS];
879	int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
880		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
881	JSAMPLE *_tmpbuf=NULL, *ptr=srcBuf;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
882
883	getinstance(handle)
884
885	for(i=0; i<MAX_COMPONENTS; i++)
886	{
887		tmpbuf[i]=NULL;  inbuf[i]=NULL;
888	}
889
890	if((this->init&COMPRESS)==0)
891		_throw("tjCompressFromYUV(): Instance has not been initialized for compression");
892
893	if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
894		|| subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
895		|| jpegQual>100)
896		_throw("tjCompressFromYUV(): Invalid argument");
897
898	if(setjmp(this->jerr.setjmp_buffer))
899	{
900		/* If we get here, the JPEG code has signaled an error. */
901		retval=-1;
902		goto bailout;
903	}
904
905	cinfo->image_width=width;
906	cinfo->image_height=height;
907
908	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
909	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
910	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
911
912	if(flags&TJFLAG_NOREALLOC)
913	{
914		alloc=0;  *jpegSize=tjBufSize(width, height, subsamp);
915	}
916	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
917	if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
918		return -1;
919	cinfo->raw_data_in=TRUE;
920
921	jpeg_start_compress(cinfo, TRUE);
922	for(i=0; i<cinfo->num_components; i++)
923	{
924		jpeg_component_info *compptr=&cinfo->comp_info[i];
925		int ih;
926		iw[i]=compptr->width_in_blocks*DCTSIZE;
927		ih=compptr->height_in_blocks*DCTSIZE;
928		cw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
929			*compptr->h_samp_factor/cinfo->max_h_samp_factor;
930		ch[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
931			*compptr->v_samp_factor/cinfo->max_v_samp_factor;
932		if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
933		th[i]=compptr->v_samp_factor*DCTSIZE;
934		tmpbufsize+=iw[i]*th[i];
935		if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
936			_throw("tjCompressFromYUV(): Memory allocation failure");
937		for(row=0; row<ch[i]; row++)
938		{
939			inbuf[i][row]=ptr;
940			ptr+=PAD(cw[i], pad);
941		}
942	}
943	if(usetmpbuf)
944	{
945		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
946			_throw("tjCompressFromYUV(): Memory allocation failure");
947		ptr=_tmpbuf;
948		for(i=0; i<cinfo->num_components; i++)
949		{
950			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
951				_throw("tjCompressFromYUV(): Memory allocation failure");
952			for(row=0; row<th[i]; row++)
953			{
954				tmpbuf[i][row]=ptr;
955				ptr+=iw[i];
956			}
957		}
958	}
959
960	for(row=0; row<(int)cinfo->image_height;
961		row+=cinfo->max_v_samp_factor*DCTSIZE)
962	{
963		JSAMPARRAY yuvptr[MAX_COMPONENTS];
964		int crow[MAX_COMPONENTS];
965		for(i=0; i<cinfo->num_components; i++)
966		{
967			jpeg_component_info *compptr=&cinfo->comp_info[i];
968			crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
969			if(usetmpbuf)
970			{
971				int j, k;
972				for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
973				{
974					memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], cw[i]);
975					/* Duplicate last sample in row to fill out MCU */
976					for(k=cw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][cw[i]-1];
977				}
978				/* Duplicate last row to fill out MCU */
979				for(j=ch[i]-crow[i]; j<th[i]; j++)
980					memcpy(tmpbuf[i][j], tmpbuf[i][ch[i]-crow[i]-1], iw[i]);
981				yuvptr[i]=tmpbuf[i];
982			}
983			else
984				yuvptr[i]=&inbuf[i][crow[i]];
985		}
986		jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
987	}
988	jpeg_finish_compress(cinfo);
989
990	bailout:
991	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
992	for(i=0; i<MAX_COMPONENTS; i++)
993	{
994		if(tmpbuf[i]) free(tmpbuf[i]);
995		if(inbuf[i]) free(inbuf[i]);
996	}
997	if(_tmpbuf) free(_tmpbuf);
998	return retval;
999}
1000
1001
1002/* Decompressor */
1003
1004static tjhandle _tjInitDecompress(tjinstance *this)
1005{
1006	unsigned char buffer[1];
1007
1008	/* This is also straight out of example.c */
1009	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
1010	this->jerr.pub.error_exit=my_error_exit;
1011	this->jerr.pub.output_message=my_output_message;
1012
1013	if(setjmp(this->jerr.setjmp_buffer))
1014	{
1015		/* If we get here, the JPEG code has signaled an error. */
1016		if(this) free(this);  return NULL;
1017	}
1018
1019	jpeg_create_decompress(&this->dinfo);
1020	/* Make an initial call so it will create the source manager */
1021	jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1022
1023	this->init|=DECOMPRESS;
1024	return (tjhandle)this;
1025}
1026
1027DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
1028{
1029	tjinstance *this;
1030	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1031	{
1032		snprintf(errStr, JMSG_LENGTH_MAX,
1033			"tjInitDecompress(): Memory allocation failure");
1034		return NULL;
1035	}
1036	MEMZERO(this, sizeof(tjinstance));
1037	return _tjInitDecompress(this);
1038}
1039
1040
1041DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
1042	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
1043	int *jpegSubsamp, int *jpegColorspace)
1044{
1045	int retval=0;
1046
1047	getinstance(handle);
1048	if((this->init&DECOMPRESS)==0)
1049		_throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
1050
1051	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
1052		|| jpegSubsamp==NULL || jpegColorspace==NULL)
1053		_throw("tjDecompressHeader3(): Invalid argument");
1054
1055	if(setjmp(this->jerr.setjmp_buffer))
1056	{
1057		/* If we get here, the JPEG code has signaled an error. */
1058		return -1;
1059	}
1060
1061	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1062	jpeg_read_header(dinfo, TRUE);
1063
1064	*width=dinfo->image_width;
1065	*height=dinfo->image_height;
1066	*jpegSubsamp=getSubsamp(dinfo);
1067	switch(dinfo->jpeg_color_space)
1068	{
1069		case JCS_GRAYSCALE:  *jpegColorspace=TJCS_GRAY;  break;
1070		case JCS_RGB:        *jpegColorspace=TJCS_RGB;  break;
1071		case JCS_YCbCr:      *jpegColorspace=TJCS_YCbCr;  break;
1072		case JCS_CMYK:       *jpegColorspace=TJCS_CMYK;  break;
1073		case JCS_YCCK:       *jpegColorspace=TJCS_YCCK;  break;
1074		default:             *jpegColorspace=-1;  break;
1075	}
1076
1077	jpeg_abort_decompress(dinfo);
1078
1079	if(*jpegSubsamp<0)
1080		_throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1081	if(*jpegColorspace<0)
1082		_throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1083	if(*width<1 || *height<1)
1084		_throw("tjDecompressHeader3(): Invalid data returned in header");
1085
1086	bailout:
1087	return retval;
1088}
1089
1090DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
1091	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
1092	int *jpegSubsamp)
1093{
1094	int jpegColorspace;
1095	return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1096		jpegSubsamp, &jpegColorspace);
1097}
1098
1099DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
1100	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
1101{
1102	int jpegSubsamp;
1103	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1104		&jpegSubsamp);
1105}
1106
1107
1108DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
1109{
1110	if(numscalingfactors==NULL)
1111	{
1112		snprintf(errStr, JMSG_LENGTH_MAX,
1113			"tjGetScalingFactors(): Invalid argument");
1114		return NULL;
1115	}
1116
1117	*numscalingfactors=NUMSF;
1118	return (tjscalingfactor *)sf;
1119}
1120
1121
1122DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
1123	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1124	int height, int pixelFormat, int flags)
1125{
1126	int i, retval=0;  JSAMPROW *row_pointer=NULL;
1127	int jpegwidth, jpegheight, scaledw, scaledh;
1128	#ifndef JCS_EXTENSIONS
1129	unsigned char *rgbBuf=NULL;
1130	unsigned char *_dstBuf=NULL;  int _pitch=0;
1131	#endif
1132
1133	getinstance(handle);
1134	if((this->init&DECOMPRESS)==0)
1135		_throw("tjDecompress2(): Instance has not been initialized for decompression");
1136
1137	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
1138		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
1139		_throw("tjDecompress2(): Invalid argument");
1140
1141	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1142	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1143	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1144
1145	if(setjmp(this->jerr.setjmp_buffer))
1146	{
1147		/* If we get here, the JPEG code has signaled an error. */
1148		retval=-1;
1149		goto bailout;
1150	}
1151
1152	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1153	jpeg_read_header(dinfo, TRUE);
1154	if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
1155	{
1156		retval=-1;  goto bailout;
1157	}
1158
1159	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1160
1161	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
1162	if(width==0) width=jpegwidth;
1163	if(height==0) height=jpegheight;
1164	for(i=0; i<NUMSF; i++)
1165	{
1166		scaledw=TJSCALED(jpegwidth, sf[i]);
1167		scaledh=TJSCALED(jpegheight, sf[i]);
1168		if(scaledw<=width && scaledh<=height)
1169			break;
1170	}
1171	if(scaledw>width || scaledh>height)
1172		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
1173	width=scaledw;  height=scaledh;
1174	dinfo->scale_num=sf[i].num;
1175	dinfo->scale_denom=sf[i].denom;
1176
1177	jpeg_start_decompress(dinfo);
1178	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1179
1180	#ifndef JCS_EXTENSIONS
1181	if(pixelFormat!=TJPF_GRAY &&
1182		(RGB_RED!=tjRedOffset[pixelFormat] ||
1183			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1184			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1185			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1186	{
1187		rgbBuf=(unsigned char *)malloc(width*height*3);
1188		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1189		_pitch=pitch;  pitch=width*3;
1190		_dstBuf=dstBuf;  dstBuf=rgbBuf;
1191	}
1192	#endif
1193
1194	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1195		*dinfo->output_height))==NULL)
1196		_throw("tjDecompress2(): Memory allocation failure");
1197	for(i=0; i<(int)dinfo->output_height; i++)
1198	{
1199		if(flags&TJFLAG_BOTTOMUP)
1200			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1201		else row_pointer[i]=&dstBuf[i*pitch];
1202	}
1203	while(dinfo->output_scanline<dinfo->output_height)
1204	{
1205		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1206			dinfo->output_height-dinfo->output_scanline);
1207	}
1208	jpeg_finish_decompress(dinfo);
1209
1210	#ifndef JCS_EXTENSIONS
1211	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1212	#endif
1213
1214	bailout:
1215	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1216	#ifndef JCS_EXTENSIONS
1217	if(rgbBuf) free(rgbBuf);
1218	#endif
1219	if(row_pointer) free(row_pointer);
1220	return retval;
1221}
1222
1223DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1224	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1225	int height, int pixelSize, int flags)
1226{
1227	if(flags&TJ_YUV)
1228		return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1229	else
1230		return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1231			height, getPixelFormat(pixelSize, flags), flags);
1232}
1233
1234
1235DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
1236	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1237	int width, int pad, int height, int flags)
1238{
1239	int i, sfi, row, retval=0;  JSAMPROW *outbuf[MAX_COMPONENTS];
1240	int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
1241	int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1242		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1243	JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
1244	int dctsize;
1245
1246	getinstance(handle);
1247
1248	for(i=0; i<MAX_COMPONENTS; i++)
1249	{
1250		tmpbuf[i]=NULL;  outbuf[i]=NULL;
1251	}
1252
1253	if((this->init&DECOMPRESS)==0)
1254		_throw("tjDecompressToYUV2(): Instance has not been initialized for decompression");
1255
1256	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1257		|| !isPow2(pad) || height<0)
1258		_throw("tjDecompressToYUV2(): Invalid argument");
1259
1260	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1261	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1262	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1263
1264	if(setjmp(this->jerr.setjmp_buffer))
1265	{
1266		/* If we get here, the JPEG code has signaled an error. */
1267		retval=-1;
1268		goto bailout;
1269	}
1270
1271	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1272	jpeg_read_header(dinfo, TRUE);
1273	jpegSubsamp=getSubsamp(dinfo);
1274	if(jpegSubsamp<0)
1275		_throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1276
1277	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
1278	if(width==0) width=jpegwidth;
1279	if(height==0) height=jpegheight;
1280	for(i=0; i<NUMSF; i++)
1281	{
1282		scaledw=TJSCALED(jpegwidth, sf[i]);
1283		scaledh=TJSCALED(jpegheight, sf[i]);
1284		if(scaledw<=width && scaledh<=height)
1285			break;
1286	}
1287	if(scaledw>width || scaledh>height)
1288		_throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1289	if(dinfo->num_components>3)
1290		_throw("tjDecompressToYUV2(): JPEG image must have 3 or fewer components");
1291
1292	width=scaledw;  height=scaledh;
1293	dinfo->scale_num=sf[i].num;
1294	dinfo->scale_denom=sf[i].denom;
1295	sfi=i;
1296	jpeg_calc_output_dimensions(dinfo);
1297
1298	dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
1299
1300	for(i=0; i<dinfo->num_components; i++)
1301	{
1302		jpeg_component_info *compptr=&dinfo->comp_info[i];
1303		int ih;
1304		iw[i]=compptr->width_in_blocks*dctsize;
1305		ih=compptr->height_in_blocks*dctsize;
1306		cw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
1307			*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1308		ch[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
1309			*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1310		if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
1311		th[i]=compptr->v_samp_factor*dctsize;
1312		tmpbufsize+=iw[i]*th[i];
1313		if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
1314			_throw("tjDecompressToYUV2(): Memory allocation failure");
1315		for(row=0; row<ch[i]; row++)
1316		{
1317			outbuf[i][row]=ptr;
1318			ptr+=PAD(cw[i], pad);
1319		}
1320	}
1321	if(usetmpbuf)
1322	{
1323		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1324			_throw("tjDecompressToYUV2(): Memory allocation failure");
1325		ptr=_tmpbuf;
1326		for(i=0; i<dinfo->num_components; i++)
1327		{
1328			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1329				_throw("tjDecompressToYUV2(): Memory allocation failure");
1330			for(row=0; row<th[i]; row++)
1331			{
1332				tmpbuf[i][row]=ptr;
1333				ptr+=iw[i];
1334			}
1335		}
1336	}
1337
1338	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1339	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
1340	dinfo->raw_data_out=TRUE;
1341
1342	jpeg_start_decompress(dinfo);
1343	for(row=0; row<(int)dinfo->output_height;
1344		row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
1345	{
1346		JSAMPARRAY yuvptr[MAX_COMPONENTS];
1347		int crow[MAX_COMPONENTS];
1348		for(i=0; i<dinfo->num_components; i++)
1349		{
1350			jpeg_component_info *compptr=&dinfo->comp_info[i];
1351			if(jpegSubsamp==TJ_420)
1352			{
1353				/* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1354				   to be clever and use the IDCT to perform upsampling on the U and V
1355				   planes.  For instance, if the output image is to be scaled by 1/2
1356				   relative to the JPEG image, then the scaling factor and upsampling
1357				   effectively cancel each other, so a normal 8x8 IDCT can be used.
1358				   However, this is not desirable when using the decompress-to-YUV
1359				   functionality in TurboJPEG, since we want to output the U and V
1360				   planes in their subsampled form.  Thus, we have to override some
1361				   internal libjpeg parameters to force it to use the "scaled" IDCT
1362				   functions on the U and V planes. */
1363				compptr->_DCT_scaled_size=dctsize;
1364				compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1365					sf[sfi].num/sf[sfi].denom*
1366					compptr->v_samp_factor/dinfo->max_v_samp_factor;
1367				dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1368			}
1369			crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1370			if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1371			else yuvptr[i]=&outbuf[i][crow[i]];
1372		}
1373		jpeg_read_raw_data(dinfo, yuvptr,
1374			dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
1375		if(usetmpbuf)
1376		{
1377			int j;
1378			for(i=0; i<dinfo->num_components; i++)
1379			{
1380				for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
1381				{
1382					memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
1383				}
1384			}
1385		}
1386	}
1387	jpeg_finish_decompress(dinfo);
1388
1389	bailout:
1390	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1391	for(i=0; i<MAX_COMPONENTS; i++)
1392	{
1393		if(tmpbuf[i]) free(tmpbuf[i]);
1394		if(outbuf[i]) free(outbuf[i]);
1395	}
1396	if(_tmpbuf) free(_tmpbuf);
1397	return retval;
1398}
1399
1400DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1401	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1402	int flags)
1403{
1404	return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1405}
1406
1407
1408/* Transformer */
1409
1410DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1411{
1412	tjinstance *this=NULL;  tjhandle handle=NULL;
1413	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1414	{
1415		snprintf(errStr, JMSG_LENGTH_MAX,
1416			"tjInitTransform(): Memory allocation failure");
1417		return NULL;
1418	}
1419	MEMZERO(this, sizeof(tjinstance));
1420	handle=_tjInitCompress(this);
1421	if(!handle) return NULL;
1422	handle=_tjInitDecompress(this);
1423	return handle;
1424}
1425
1426
1427DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1428	unsigned long jpegSize, int n, unsigned char **dstBufs,
1429	unsigned long *dstSizes, tjtransform *t, int flags)
1430{
1431	jpeg_transform_info *xinfo=NULL;
1432	jvirt_barray_ptr *srccoefs, *dstcoefs;
1433	int retval=0, i, jpegSubsamp;
1434
1435	getinstance(handle);
1436	if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
1437		_throw("tjTransform(): Instance has not been initialized for transformation");
1438
1439	if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1440		|| t==NULL || flags<0)
1441		_throw("tjTransform(): Invalid argument");
1442
1443	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1444	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1445	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1446
1447	if(setjmp(this->jerr.setjmp_buffer))
1448	{
1449		/* If we get here, the JPEG code has signaled an error. */
1450		retval=-1;
1451		goto bailout;
1452	}
1453
1454	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1455
1456	if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1457		==NULL)
1458		_throw("tjTransform(): Memory allocation failure");
1459	MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
1460
1461	for(i=0; i<n; i++)
1462	{
1463		xinfo[i].transform=xformtypes[t[i].op];
1464		xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1465		xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1466		xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1467		xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1468		if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
1469		else xinfo[i].slow_hflip=0;
1470
1471		if(xinfo[i].crop)
1472		{
1473			xinfo[i].crop_xoffset=t[i].r.x;  xinfo[i].crop_xoffset_set=JCROP_POS;
1474			xinfo[i].crop_yoffset=t[i].r.y;  xinfo[i].crop_yoffset_set=JCROP_POS;
1475			if(t[i].r.w!=0)
1476			{
1477				xinfo[i].crop_width=t[i].r.w;  xinfo[i].crop_width_set=JCROP_POS;
1478			}
1479			else xinfo[i].crop_width=JCROP_UNSET;
1480			if(t[i].r.h!=0)
1481			{
1482				xinfo[i].crop_height=t[i].r.h;  xinfo[i].crop_height_set=JCROP_POS;
1483			}
1484			else xinfo[i].crop_height=JCROP_UNSET;
1485		}
1486	}
1487
1488	jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1489	jpeg_read_header(dinfo, TRUE);
1490	jpegSubsamp=getSubsamp(dinfo);
1491	if(jpegSubsamp<0)
1492		_throw("tjTransform(): Could not determine subsampling type for JPEG image");
1493
1494	for(i=0; i<n; i++)
1495	{
1496		if(!jtransform_request_workspace(dinfo, &xinfo[i]))
1497			_throw("tjTransform(): Transform is not perfect");
1498
1499		if(xinfo[i].crop)
1500		{
1501			if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1502				|| (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1503			{
1504				snprintf(errStr, JMSG_LENGTH_MAX,
1505					"To crop this JPEG image, x must be a multiple of %d\n"
1506					"and y must be a multiple of %d.\n",
1507					xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1508				retval=-1;  goto bailout;
1509			}
1510		}
1511	}
1512
1513	srccoefs=jpeg_read_coefficients(dinfo);
1514
1515	for(i=0; i<n; i++)
1516	{
1517		int w, h, alloc=1;
1518		if(!xinfo[i].crop)
1519		{
1520			w=dinfo->image_width;  h=dinfo->image_height;
1521		}
1522		else
1523		{
1524			w=xinfo[i].crop_width;  h=xinfo[i].crop_height;
1525		}
1526		if(flags&TJFLAG_NOREALLOC)
1527		{
1528			alloc=0;  dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
1529		}
1530		if(!(t[i].options&TJXOPT_NOOUTPUT))
1531			jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
1532		jpeg_copy_critical_parameters(dinfo, cinfo);
1533		dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
1534			&xinfo[i]);
1535		if(!(t[i].options&TJXOPT_NOOUTPUT))
1536		{
1537			jpeg_write_coefficients(cinfo, dstcoefs);
1538			jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1539		}
1540		else jinit_c_master_control(cinfo, TRUE);
1541		jtransform_execute_transformation(dinfo, cinfo, srccoefs,
1542			&xinfo[i]);
1543		if(t[i].customFilter)
1544		{
1545			int ci, y;  JDIMENSION by;
1546			for(ci=0; ci<cinfo->num_components; ci++)
1547			{
1548				jpeg_component_info *compptr=&cinfo->comp_info[ci];
1549				tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1550					DCTSIZE};
1551				tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1552					compptr->height_in_blocks*DCTSIZE};
1553				for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1554				{
1555					JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1556						((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1557						TRUE);
1558					for(y=0; y<compptr->v_samp_factor; y++)
1559					{
1560						if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
1561							ci, i, &t[i])==-1)
1562							_throw("tjTransform(): Error in custom filter");
1563						arrayRegion.y+=DCTSIZE;
1564					}
1565				}
1566			}
1567		}
1568		if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
1569	}
1570
1571	jpeg_finish_decompress(dinfo);
1572
1573	bailout:
1574	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1575	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1576	if(xinfo) free(xinfo);
1577	return retval;
1578}
1579