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