1/*
2 * Copyright (C)2009-2012, 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
43extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
44	unsigned long *, boolean);
45extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
46
47#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
48
49
50/* Error handling (based on example in example.c) */
51
52static char errStr[JMSG_LENGTH_MAX]="No error";
53
54struct my_error_mgr
55{
56	struct jpeg_error_mgr pub;
57	jmp_buf setjmp_buffer;
58};
59typedef struct my_error_mgr *my_error_ptr;
60
61static void my_error_exit(j_common_ptr cinfo)
62{
63	my_error_ptr myerr=(my_error_ptr)cinfo->err;
64	(*cinfo->err->output_message)(cinfo);
65	longjmp(myerr->setjmp_buffer, 1);
66}
67
68/* Based on output_message() in jerror.c */
69
70static void my_output_message(j_common_ptr cinfo)
71{
72	(*cinfo->err->format_message)(cinfo, errStr);
73}
74
75
76/* Global structures, macros, etc. */
77
78enum {COMPRESS=1, DECOMPRESS=2};
79
80typedef struct _tjinstance
81{
82	struct jpeg_compress_struct cinfo;
83	struct jpeg_decompress_struct dinfo;
84	struct my_error_mgr jerr;
85	int init;
86} tjinstance;
87
88static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
89
90static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
91{
92	JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
93	JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
94};
95
96#define NUMSF 16
97static const tjscalingfactor sf[NUMSF]={
98	{2, 1},
99	{15, 8},
100	{7, 4},
101	{13, 8},
102	{3, 2},
103	{11, 8},
104	{5, 4},
105	{9, 8},
106	{1, 1},
107	{7, 8},
108	{3, 4},
109	{5, 8},
110	{1, 2},
111	{3, 8},
112	{1, 4},
113	{1, 8}
114};
115
116#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
117	retval=-1;  goto bailout;}
118#define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
119	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
120	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
121		return -1;}  \
122	cinfo=&this->cinfo;  dinfo=&this->dinfo;
123
124static int getPixelFormat(int pixelSize, int flags)
125{
126	if(pixelSize==1) return TJPF_GRAY;
127	if(pixelSize==3)
128	{
129		if(flags&TJ_BGR) return TJPF_BGR;
130		else return TJPF_RGB;
131	}
132	if(pixelSize==4)
133	{
134		if(flags&TJ_ALPHAFIRST)
135		{
136			if(flags&TJ_BGR) return TJPF_XBGR;
137			else return TJPF_XRGB;
138		}
139		else
140		{
141			if(flags&TJ_BGR) return TJPF_BGRX;
142			else return TJPF_RGBX;
143		}
144	}
145	return -1;
146}
147
148static int setCompDefaults(struct jpeg_compress_struct *cinfo,
149	int pixelFormat, int subsamp, int jpegQual, int flags)
150{
151	int retval=0;
152
153	switch(pixelFormat)
154	{
155		case TJPF_GRAY:
156			cinfo->in_color_space=JCS_GRAYSCALE;  break;
157		#if JCS_EXTENSIONS==1
158		case TJPF_RGB:
159			cinfo->in_color_space=JCS_EXT_RGB;  break;
160		case TJPF_BGR:
161			cinfo->in_color_space=JCS_EXT_BGR;  break;
162		case TJPF_RGBX:
163		case TJPF_RGBA:
164			cinfo->in_color_space=JCS_EXT_RGBX;  break;
165		case TJPF_BGRX:
166		case TJPF_BGRA:
167			cinfo->in_color_space=JCS_EXT_BGRX;  break;
168		case TJPF_XRGB:
169		case TJPF_ARGB:
170			cinfo->in_color_space=JCS_EXT_XRGB;  break;
171		case TJPF_XBGR:
172		case TJPF_ABGR:
173			cinfo->in_color_space=JCS_EXT_XBGR;  break;
174		#else
175		case TJPF_RGB:
176		case TJPF_BGR:
177		case TJPF_RGBX:
178		case TJPF_BGRX:
179		case TJPF_XRGB:
180		case TJPF_XBGR:
181		case TJPF_RGBA:
182		case TJPF_BGRA:
183		case TJPF_ARGB:
184		case TJPF_ABGR:
185			cinfo->in_color_space=JCS_RGB;  pixelFormat=TJPF_RGB;
186			break;
187		#endif
188	}
189
190	cinfo->input_components=tjPixelSize[pixelFormat];
191	jpeg_set_defaults(cinfo);
192	if(jpegQual>=0)
193	{
194		jpeg_set_quality(cinfo, jpegQual, TRUE);
195		if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
196		else cinfo->dct_method=JDCT_FASTEST;
197	}
198	if(subsamp==TJSAMP_GRAY)
199		jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
200	else
201		jpeg_set_colorspace(cinfo, JCS_YCbCr);
202
203	cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
204	cinfo->comp_info[1].h_samp_factor=1;
205	cinfo->comp_info[2].h_samp_factor=1;
206	cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
207	cinfo->comp_info[1].v_samp_factor=1;
208	cinfo->comp_info[2].v_samp_factor=1;
209
210	return retval;
211}
212
213static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
214	int pixelFormat, int flags)
215{
216	int retval=0;
217
218	switch(pixelFormat)
219	{
220		case TJPF_GRAY:
221			dinfo->out_color_space=JCS_GRAYSCALE;  break;
222		#if JCS_EXTENSIONS==1
223		case TJPF_RGB:
224			dinfo->out_color_space=JCS_EXT_RGB;  break;
225		case TJPF_BGR:
226			dinfo->out_color_space=JCS_EXT_BGR;  break;
227		case TJPF_RGBX:
228			dinfo->out_color_space=JCS_EXT_RGBX;  break;
229		case TJPF_BGRX:
230			dinfo->out_color_space=JCS_EXT_BGRX;  break;
231		case TJPF_XRGB:
232			dinfo->out_color_space=JCS_EXT_XRGB;  break;
233		case TJPF_XBGR:
234			dinfo->out_color_space=JCS_EXT_XBGR;  break;
235		#if JCS_ALPHA_EXTENSIONS==1
236		case TJPF_RGBA:
237			dinfo->out_color_space=JCS_EXT_RGBA;  break;
238		case TJPF_BGRA:
239			dinfo->out_color_space=JCS_EXT_BGRA;  break;
240		case TJPF_ARGB:
241			dinfo->out_color_space=JCS_EXT_ARGB;  break;
242		case TJPF_ABGR:
243			dinfo->out_color_space=JCS_EXT_ABGR;  break;
244		#endif
245		#else
246		case TJPF_RGB:
247		case TJPF_BGR:
248		case TJPF_RGBX:
249		case TJPF_BGRX:
250		case TJPF_XRGB:
251		case TJPF_XBGR:
252		case TJPF_RGBA:
253		case TJPF_BGRA:
254		case TJPF_ARGB:
255		case TJPF_ABGR:
256			dinfo->out_color_space=JCS_RGB;  break;
257		#endif
258		default:
259			_throw("Unsupported pixel format");
260	}
261
262	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
263
264	bailout:
265	return retval;
266}
267
268
269static int getSubsamp(j_decompress_ptr dinfo)
270{
271	int retval=-1, i, k;
272	for(i=0; i<NUMSUBOPT; i++)
273	{
274		if(dinfo->num_components==pixelsize[i])
275		{
276			if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
277				&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
278			{
279				int match=0;
280				for(k=1; k<dinfo->num_components; k++)
281				{
282					if(dinfo->comp_info[k].h_samp_factor==1
283						&& dinfo->comp_info[k].v_samp_factor==1)
284						match++;
285				}
286				if(match==dinfo->num_components-1)
287				{
288					retval=i;  break;
289				}
290			}
291		}
292	}
293	return retval;
294}
295
296
297#ifndef JCS_EXTENSIONS
298
299/* Conversion functions to emulate the colorspace extensions.  This allows the
300   TurboJPEG wrapper to be used with libjpeg */
301
302#define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
303	int rowPad=pitch-width*PS;  \
304	while(height--)  \
305	{  \
306		unsigned char *endOfRow=src+width*PS;  \
307		while(src<endOfRow)  \
308		{  \
309			dst[RGB_RED]=src[ROFFSET];  \
310			dst[RGB_GREEN]=src[GOFFSET];  \
311			dst[RGB_BLUE]=src[BOFFSET];  \
312			dst+=RGB_PIXELSIZE;  src+=PS;  \
313		}  \
314		src+=rowPad;  \
315	}  \
316}
317
318static unsigned char *toRGB(unsigned char *src, int width, int pitch,
319	int height, int pixelFormat, unsigned char *dst)
320{
321	unsigned char *retval=src;
322	switch(pixelFormat)
323	{
324		case TJPF_RGB:
325			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
326			retval=dst;  TORGB(3, 0, 1, 2);
327			#endif
328			break;
329		case TJPF_BGR:
330			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
331			retval=dst;  TORGB(3, 2, 1, 0);
332			#endif
333			break;
334		case TJPF_RGBX:
335		case TJPF_RGBA:
336			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
337			retval=dst;  TORGB(4, 0, 1, 2);
338			#endif
339			break;
340		case TJPF_BGRX:
341		case TJPF_BGRA:
342			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
343			retval=dst;  TORGB(4, 2, 1, 0);
344			#endif
345			break;
346		case TJPF_XRGB:
347		case TJPF_ARGB:
348			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
349			retval=dst;  TORGB(4, 1, 2, 3);
350			#endif
351			break;
352		case TJPF_XBGR:
353		case TJPF_ABGR:
354			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
355			retval=dst;  TORGB(4, 3, 2, 1);
356			#endif
357			break;
358	}
359	return retval;
360}
361
362#define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) {  \
363	int rowPad=pitch-width*PS;  \
364	while(height--)  \
365	{  \
366		unsigned char *endOfRow=dst+width*PS;  \
367		while(dst<endOfRow)  \
368		{  \
369			dst[ROFFSET]=src[RGB_RED];  \
370			dst[GOFFSET]=src[RGB_GREEN];  \
371			dst[BOFFSET]=src[RGB_BLUE];  \
372			SETALPHA  \
373			dst+=PS;  src+=RGB_PIXELSIZE;  \
374		}  \
375		dst+=rowPad;  \
376	}  \
377}
378
379static void fromRGB(unsigned char *src, unsigned char *dst, int width,
380	int pitch, int height, int pixelFormat)
381{
382	switch(pixelFormat)
383	{
384		case TJPF_RGB:
385			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
386			FROMRGB(3, 0, 1, 2,);
387			#endif
388			break;
389		case TJPF_BGR:
390			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
391			FROMRGB(3, 2, 1, 0,);
392			#endif
393			break;
394		case TJPF_RGBX:
395			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
396			FROMRGB(4, 0, 1, 2,);
397			#endif
398			break;
399		case TJPF_RGBA:
400			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
401			FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
402			#endif
403			break;
404		case TJPF_BGRX:
405			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
406			FROMRGB(4, 2, 1, 0,);
407			#endif
408			break;
409		case TJPF_BGRA:
410			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
411			FROMRGB(4, 2, 1, 0, dst[3]=0xFF;);  return;
412			#endif
413			break;
414		case TJPF_XRGB:
415			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
416			FROMRGB(4, 1, 2, 3,);  return;
417			#endif
418			break;
419		case TJPF_ARGB:
420			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
421			FROMRGB(4, 1, 2, 3, dst[0]=0xFF;);  return;
422			#endif
423			break;
424		case TJPF_XBGR:
425			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
426			FROMRGB(4, 3, 2, 1,);  return;
427			#endif
428			break;
429		case TJPF_ABGR:
430			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
431			FROMRGB(4, 3, 2, 1, dst[0]=0xFF;);  return;
432			#endif
433			break;
434	}
435}
436
437#endif
438
439
440/* General API functions */
441
442DLLEXPORT char* DLLCALL tjGetErrorStr(void)
443{
444	return errStr;
445}
446
447
448DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
449{
450	getinstance(handle);
451	if(setjmp(this->jerr.setjmp_buffer)) return -1;
452	if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
453	if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
454	free(this);
455	return 0;
456}
457
458
459/* These are exposed mainly because Windows can't malloc() and free() across
460   DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
461   with turbojpeg.dll for compatibility reasons.  However, these functions
462   can potentially be used for other purposes by different implementations. */
463
464DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
465{
466	if(buf) free(buf);
467}
468
469
470DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
471{
472	return (unsigned char *)malloc(bytes);
473}
474
475
476/* Compressor  */
477
478static tjhandle _tjInitCompress(tjinstance *this)
479{
480	unsigned char buffer[1], *buf=buffer;  unsigned long size=1;
481
482	/* This is also straight out of example.c */
483	this->cinfo.err=jpeg_std_error(&this->jerr.pub);
484	this->jerr.pub.error_exit=my_error_exit;
485	this->jerr.pub.output_message=my_output_message;
486
487	if(setjmp(this->jerr.setjmp_buffer))
488	{
489		/* If we get here, the JPEG code has signaled an error. */
490		if(this) free(this);  return NULL;
491	}
492
493	jpeg_create_compress(&this->cinfo);
494	/* Make an initial call so it will create the destination manager */
495	jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
496
497	this->init|=COMPRESS;
498	return (tjhandle)this;
499}
500
501DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
502{
503	tjinstance *this=NULL;
504	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
505	{
506		snprintf(errStr, JMSG_LENGTH_MAX,
507			"tjInitCompress(): Memory allocation failure");
508		return NULL;
509	}
510	MEMZERO(this, sizeof(tjinstance));
511	return _tjInitCompress(this);
512}
513
514
515DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
516	int jpegSubsamp)
517{
518	unsigned long retval=0;  int mcuw, mcuh, chromasf;
519	if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
520		_throw("tjBufSize(): Invalid argument");
521
522	/* This allows for rare corner cases in which a JPEG image can actually be
523	   larger than the uncompressed input (we wouldn't mention it if it hadn't
524	   happened before.) */
525	mcuw=tjMCUWidth[jpegSubsamp];
526	mcuh=tjMCUHeight[jpegSubsamp];
527	chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
528	retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
529
530	bailout:
531	return retval;
532}
533
534DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
535{
536	unsigned long retval=0;
537	if(width<1 || height<1)
538		_throw("TJBUFSIZE(): Invalid argument");
539
540	/* This allows for rare corner cases in which a JPEG image can actually be
541	   larger than the uncompressed input (we wouldn't mention it if it hadn't
542	   happened before.) */
543	retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
544
545	bailout:
546	return retval;
547}
548
549
550DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
551	int subsamp)
552{
553	unsigned long retval=0;
554	int pw, ph, cw, ch;
555	if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
556		_throw("tjBufSizeYUV(): Invalid argument");
557	pw=PAD(width, tjMCUWidth[subsamp]/8);
558	ph=PAD(height, tjMCUHeight[subsamp]/8);
559	cw=pw*8/tjMCUWidth[subsamp];  ch=ph*8/tjMCUHeight[subsamp];
560	retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2);
561
562	bailout:
563	return retval;
564}
565
566
567DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
568	int subsamp)
569{
570	return tjBufSizeYUV(width, height, subsamp);
571}
572
573
574DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
575	int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
576	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
577{
578	int i, retval=0, alloc=1;  JSAMPROW *row_pointer=NULL;
579	#ifndef JCS_EXTENSIONS
580	unsigned char *rgbBuf=NULL;
581	#endif
582
583	getinstance(handle)
584	if((this->init&COMPRESS)==0)
585		_throw("tjCompress2(): Instance has not been initialized for compression");
586
587	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
588		|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
589		|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
590		_throw("tjCompress2(): Invalid argument");
591
592	if(setjmp(this->jerr.setjmp_buffer))
593	{
594		/* If we get here, the JPEG code has signaled an error. */
595		retval=-1;
596		goto bailout;
597	}
598
599	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
600
601	#ifndef JCS_EXTENSIONS
602	if(pixelFormat!=TJPF_GRAY)
603	{
604		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
605		if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
606		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
607		pitch=width*RGB_PIXELSIZE;
608	}
609	#endif
610
611	cinfo->image_width=width;
612	cinfo->image_height=height;
613
614	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
615	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
616	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
617
618	if(flags&TJFLAG_NOREALLOC)
619	{
620		alloc=0;  *jpegSize=tjBufSize(width, height, jpegSubsamp);
621	}
622	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
623	if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
624		return -1;
625
626	jpeg_start_compress(cinfo, TRUE);
627	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
628		_throw("tjCompress2(): Memory allocation failure");
629	for(i=0; i<height; i++)
630	{
631		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
632		else row_pointer[i]=&srcBuf[i*pitch];
633	}
634	while(cinfo->next_scanline<cinfo->image_height)
635	{
636		jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
637			cinfo->image_height-cinfo->next_scanline);
638	}
639	jpeg_finish_compress(cinfo);
640
641	bailout:
642	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
643	#ifndef JCS_EXTENSIONS
644	if(rgbBuf) free(rgbBuf);
645	#endif
646	if(row_pointer) free(row_pointer);
647	return retval;
648}
649
650DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
651	int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
652	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
653{
654	int retval=0;  unsigned long size;
655	if(flags&TJ_YUV)
656	{
657		size=tjBufSizeYUV(width, height, jpegSubsamp);
658		retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
659			getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
660	}
661	else
662	{
663		retval=tjCompress2(handle, srcBuf, width, pitch, height,
664			getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
665			flags|TJFLAG_NOREALLOC);
666	}
667	*jpegSize=size;
668	return retval;
669}
670
671
672DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
673	int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
674	int subsamp, int flags)
675{
676	int i, retval=0;  JSAMPROW *row_pointer=NULL;
677	JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
678	JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
679	JSAMPROW *outbuf[MAX_COMPONENTS];
680	int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
681	JSAMPLE *ptr=dstBuf;
682	unsigned long yuvsize=0;
683	jpeg_component_info *compptr;
684	#ifndef JCS_EXTENSIONS
685	unsigned char *rgbBuf=NULL;
686	#endif
687
688	getinstance(handle);
689
690	for(i=0; i<MAX_COMPONENTS; i++)
691	{
692		tmpbuf[i]=NULL;  _tmpbuf[i]=NULL;
693		tmpbuf2[i]=NULL;  _tmpbuf2[i]=NULL;  outbuf[i]=NULL;
694	}
695
696	if((this->init&COMPRESS)==0)
697		_throw("tjEncodeYUV2(): Instance has not been initialized for compression");
698
699	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
700		|| pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
701		|| subsamp>=NUMSUBOPT)
702		_throw("tjEncodeYUV2(): Invalid argument");
703
704	if(setjmp(this->jerr.setjmp_buffer))
705	{
706		/* If we get here, the JPEG code has signaled an error. */
707		retval=-1;
708		goto bailout;
709	}
710
711	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
712
713	#ifndef JCS_EXTENSIONS
714	if(pixelFormat!=TJPF_GRAY)
715	{
716		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
717		if(!rgbBuf) _throw("tjEncodeYUV2(): Memory allocation failure");
718		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
719		pitch=width*RGB_PIXELSIZE;
720	}
721	#endif
722
723	cinfo->image_width=width;
724	cinfo->image_height=height;
725
726	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
727	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
728	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
729
730	yuvsize=tjBufSizeYUV(width, height, subsamp);
731	if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
732
733	/* Execute only the parts of jpeg_start_compress() that we need.  If we
734	   were to call the whole jpeg_start_compress() function, then it would try
735	   to write the file headers, which could overflow the output buffer if the
736	   YUV image were very small. */
737	if(cinfo->global_state!=CSTATE_START)
738		_throw("tjEncodeYUV3(): libjpeg API is in the wrong state");
739	(*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
740	jinit_c_master_control(cinfo, FALSE);
741	jinit_color_converter(cinfo);
742	jinit_downsampler(cinfo);
743	(*cinfo->cconvert->start_pass)(cinfo);
744
745	pw=PAD(width, cinfo->max_h_samp_factor);
746	ph=PAD(height, cinfo->max_v_samp_factor);
747
748	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
749		_throw("tjEncodeYUV2(): Memory allocation failure");
750	for(i=0; i<height; i++)
751	{
752		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
753		else row_pointer[i]=&srcBuf[i*pitch];
754	}
755	if(height<ph)
756		for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
757
758	for(i=0; i<cinfo->num_components; i++)
759	{
760		compptr=&cinfo->comp_info[i];
761		_tmpbuf[i]=(JSAMPLE *)malloc(
762			PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
763				/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
764		if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
765		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
766		if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
767		for(row=0; row<cinfo->max_v_samp_factor; row++)
768		{
769			unsigned char *_tmpbuf_aligned=
770				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
771			tmpbuf[i][row]=&_tmpbuf_aligned[
772				PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
773					/compptr->h_samp_factor, 16) * row];
774		}
775		_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
776			* compptr->v_samp_factor + 16);
777		if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
778		tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
779		if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
780		for(row=0; row<compptr->v_samp_factor; row++)
781		{
782			unsigned char *_tmpbuf2_aligned=
783				(unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
784			tmpbuf2[i][row]=&_tmpbuf2_aligned[
785				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
786		}
787		cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
788		ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
789		outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
790		if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
791		for(row=0; row<ch[i]; row++)
792		{
793			outbuf[i][row]=ptr;
794			ptr+=PAD(cw[i], 4);
795		}
796	}
797	if(yuvsize!=(unsigned long)(ptr-dstBuf))
798		_throw("tjEncodeYUV2(): Generated image is not the correct size");
799
800	for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
801	{
802		(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
803			cinfo->max_v_samp_factor);
804		(cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
805		for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
806			jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
807				row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
808				compptr->v_samp_factor, cw[i]);
809	}
810	cinfo->next_scanline+=height;
811	jpeg_abort_compress(cinfo);
812
813	bailout:
814	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
815	#ifndef JCS_EXTENSIONS
816	if(rgbBuf) free(rgbBuf);
817	#endif
818	if(row_pointer) free(row_pointer);
819	for(i=0; i<MAX_COMPONENTS; i++)
820	{
821		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
822		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
823		if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
824		if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
825		if(outbuf[i]!=NULL) free(outbuf[i]);
826	}
827	return retval;
828}
829
830DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
831	int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
832	int subsamp, int flags)
833{
834	return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
835		getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
836}
837
838
839/* Decompressor */
840
841static tjhandle _tjInitDecompress(tjinstance *this)
842{
843	unsigned char buffer[1];
844
845	/* This is also straight out of example.c */
846	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
847	this->jerr.pub.error_exit=my_error_exit;
848	this->jerr.pub.output_message=my_output_message;
849
850	if(setjmp(this->jerr.setjmp_buffer))
851	{
852		/* If we get here, the JPEG code has signaled an error. */
853		if(this) free(this);  return NULL;
854	}
855
856	jpeg_create_decompress(&this->dinfo);
857	/* Make an initial call so it will create the source manager */
858	jpeg_mem_src_tj(&this->dinfo, buffer, 1);
859
860	this->init|=DECOMPRESS;
861	return (tjhandle)this;
862}
863
864DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
865{
866	tjinstance *this;
867	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
868	{
869		snprintf(errStr, JMSG_LENGTH_MAX,
870			"tjInitDecompress(): Memory allocation failure");
871		return NULL;
872	}
873	MEMZERO(this, sizeof(tjinstance));
874	return _tjInitDecompress(this);
875}
876
877
878DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
879	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
880	int *jpegSubsamp)
881{
882	int retval=0;
883
884	getinstance(handle);
885	if((this->init&DECOMPRESS)==0)
886		_throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
887
888	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
889		|| jpegSubsamp==NULL)
890		_throw("tjDecompressHeader2(): Invalid argument");
891
892	if(setjmp(this->jerr.setjmp_buffer))
893	{
894		/* If we get here, the JPEG code has signaled an error. */
895		return -1;
896	}
897
898	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
899	jpeg_read_header(dinfo, TRUE);
900
901	*width=dinfo->image_width;
902	*height=dinfo->image_height;
903	*jpegSubsamp=getSubsamp(dinfo);
904
905	jpeg_abort_decompress(dinfo);
906
907	if(*jpegSubsamp<0)
908		_throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
909	if(*width<1 || *height<1)
910		_throw("tjDecompressHeader2(): Invalid data returned in header");
911
912	bailout:
913	return retval;
914}
915
916DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
917	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
918{
919	int jpegSubsamp;
920	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
921		&jpegSubsamp);
922}
923
924
925DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
926{
927	if(numscalingfactors==NULL)
928	{
929		snprintf(errStr, JMSG_LENGTH_MAX,
930			"tjGetScalingFactors(): Invalid argument");
931		return NULL;
932	}
933
934	*numscalingfactors=NUMSF;
935	return (tjscalingfactor *)sf;
936}
937
938
939DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
940	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
941	int height, int pixelFormat, int flags)
942{
943	int i, retval=0;  JSAMPROW *row_pointer=NULL;
944	int jpegwidth, jpegheight, scaledw, scaledh;
945	#ifndef JCS_EXTENSIONS
946	unsigned char *rgbBuf=NULL;
947	unsigned char *_dstBuf=NULL;  int _pitch=0;
948	#endif
949
950	getinstance(handle);
951	if((this->init&DECOMPRESS)==0)
952		_throw("tjDecompress2(): Instance has not been initialized for decompression");
953
954	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
955		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
956		_throw("tjDecompress2(): Invalid argument");
957
958	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
959	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
960	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
961
962	if(setjmp(this->jerr.setjmp_buffer))
963	{
964		/* If we get here, the JPEG code has signaled an error. */
965		retval=-1;
966		goto bailout;
967	}
968
969	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
970	jpeg_read_header(dinfo, TRUE);
971	if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
972	{
973		retval=-1;  goto bailout;
974	}
975
976	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
977
978	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
979	if(width==0) width=jpegwidth;
980	if(height==0) height=jpegheight;
981	for(i=0; i<NUMSF; i++)
982	{
983		scaledw=TJSCALED(jpegwidth, sf[i]);
984		scaledh=TJSCALED(jpegheight, sf[i]);
985		if(scaledw<=width && scaledh<=height)
986			break;
987	}
988	if(scaledw>width || scaledh>height)
989		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
990	width=scaledw;  height=scaledh;
991	dinfo->scale_num=sf[i].num;
992	dinfo->scale_denom=sf[i].denom;
993
994	jpeg_start_decompress(dinfo);
995	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
996
997	#ifndef JCS_EXTENSIONS
998	if(pixelFormat!=TJPF_GRAY &&
999		(RGB_RED!=tjRedOffset[pixelFormat] ||
1000			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1001			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1002			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1003	{
1004		rgbBuf=(unsigned char *)malloc(width*height*3);
1005		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1006		_pitch=pitch;  pitch=width*3;
1007		_dstBuf=dstBuf;  dstBuf=rgbBuf;
1008	}
1009	#endif
1010
1011	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1012		*dinfo->output_height))==NULL)
1013		_throw("tjDecompress2(): Memory allocation failure");
1014	for(i=0; i<(int)dinfo->output_height; i++)
1015	{
1016		if(flags&TJFLAG_BOTTOMUP)
1017			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1018		else row_pointer[i]=&dstBuf[i*pitch];
1019	}
1020	while(dinfo->output_scanline<dinfo->output_height)
1021	{
1022		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1023			dinfo->output_height-dinfo->output_scanline);
1024	}
1025	jpeg_finish_decompress(dinfo);
1026
1027	#ifndef JCS_EXTENSIONS
1028	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1029	#endif
1030
1031	bailout:
1032	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1033	#ifndef JCS_EXTENSIONS
1034	if(rgbBuf) free(rgbBuf);
1035	#endif
1036	if(row_pointer) free(row_pointer);
1037	return retval;
1038}
1039
1040DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1041	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1042	int height, int pixelSize, int flags)
1043{
1044	if(flags&TJ_YUV)
1045		return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1046	else
1047		return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1048			height, getPixelFormat(pixelSize, flags), flags);
1049}
1050
1051
1052DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1053	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1054	int flags)
1055{
1056	int i, row, retval=0;  JSAMPROW *outbuf[MAX_COMPONENTS];
1057	int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1058		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1059	JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
1060
1061	getinstance(handle);
1062
1063	for(i=0; i<MAX_COMPONENTS; i++)
1064	{
1065		tmpbuf[i]=NULL;  outbuf[i]=NULL;
1066	}
1067
1068	if((this->init&DECOMPRESS)==0)
1069		_throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
1070
1071	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
1072		_throw("tjDecompressToYUV(): Invalid argument");
1073
1074	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1075	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1076	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1077
1078	if(setjmp(this->jerr.setjmp_buffer))
1079	{
1080		/* If we get here, the JPEG code has signaled an error. */
1081		retval=-1;
1082		goto bailout;
1083	}
1084
1085	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1086	jpeg_read_header(dinfo, TRUE);
1087
1088	for(i=0; i<dinfo->num_components; i++)
1089	{
1090		jpeg_component_info *compptr=&dinfo->comp_info[i];
1091		int ih;
1092		iw[i]=compptr->width_in_blocks*DCTSIZE;
1093		ih=compptr->height_in_blocks*DCTSIZE;
1094		cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
1095			*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1096		ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
1097			*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1098		if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
1099		th[i]=compptr->v_samp_factor*DCTSIZE;
1100		tmpbufsize+=iw[i]*th[i];
1101		if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
1102			_throw("tjDecompressToYUV(): Memory allocation failure");
1103		for(row=0; row<ch[i]; row++)
1104		{
1105			outbuf[i][row]=ptr;
1106			ptr+=PAD(cw[i], 4);
1107		}
1108	}
1109	if(usetmpbuf)
1110	{
1111		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1112			_throw("tjDecompressToYUV(): Memory allocation failure");
1113		ptr=_tmpbuf;
1114		for(i=0; i<dinfo->num_components; i++)
1115		{
1116			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1117				_throw("tjDecompressToYUV(): Memory allocation failure");
1118			for(row=0; row<th[i]; row++)
1119			{
1120				tmpbuf[i][row]=ptr;
1121				ptr+=iw[i];
1122			}
1123		}
1124	}
1125
1126	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1127	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
1128	dinfo->raw_data_out=TRUE;
1129
1130	jpeg_start_decompress(dinfo);
1131	for(row=0; row<(int)dinfo->output_height;
1132		row+=dinfo->max_v_samp_factor*DCTSIZE)
1133	{
1134		JSAMPARRAY yuvptr[MAX_COMPONENTS];
1135		int crow[MAX_COMPONENTS];
1136		for(i=0; i<dinfo->num_components; i++)
1137		{
1138			jpeg_component_info *compptr=&dinfo->comp_info[i];
1139			crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1140			if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1141			else yuvptr[i]=&outbuf[i][crow[i]];
1142		}
1143		jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
1144		if(usetmpbuf)
1145		{
1146			int j;
1147			for(i=0; i<dinfo->num_components; i++)
1148			{
1149				for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
1150				{
1151					memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
1152				}
1153			}
1154		}
1155	}
1156	jpeg_finish_decompress(dinfo);
1157
1158	bailout:
1159	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1160	for(i=0; i<MAX_COMPONENTS; i++)
1161	{
1162		if(tmpbuf[i]) free(tmpbuf[i]);
1163		if(outbuf[i]) free(outbuf[i]);
1164	}
1165	if(_tmpbuf) free(_tmpbuf);
1166	return retval;
1167}
1168
1169
1170/* Transformer */
1171
1172DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1173{
1174	tjinstance *this=NULL;  tjhandle handle=NULL;
1175	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1176	{
1177		snprintf(errStr, JMSG_LENGTH_MAX,
1178			"tjInitTransform(): Memory allocation failure");
1179		return NULL;
1180	}
1181	MEMZERO(this, sizeof(tjinstance));
1182	handle=_tjInitCompress(this);
1183	if(!handle) return NULL;
1184	handle=_tjInitDecompress(this);
1185	return handle;
1186}
1187
1188
1189DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1190	unsigned long jpegSize, int n, unsigned char **dstBufs,
1191	unsigned long *dstSizes, tjtransform *t, int flags)
1192{
1193	jpeg_transform_info *xinfo=NULL;
1194	jvirt_barray_ptr *srccoefs, *dstcoefs;
1195	int retval=0, i, jpegSubsamp;
1196
1197	getinstance(handle);
1198	if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
1199		_throw("tjTransform(): Instance has not been initialized for transformation");
1200
1201	if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1202		|| t==NULL || flags<0)
1203		_throw("tjTransform(): Invalid argument");
1204
1205	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1206	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1207	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1208
1209	if(setjmp(this->jerr.setjmp_buffer))
1210	{
1211		/* If we get here, the JPEG code has signaled an error. */
1212		retval=-1;
1213		goto bailout;
1214	}
1215
1216	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1217
1218	if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1219		==NULL)
1220		_throw("tjTransform(): Memory allocation failure");
1221	MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
1222
1223	for(i=0; i<n; i++)
1224	{
1225		xinfo[i].transform=xformtypes[t[i].op];
1226		xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1227		xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1228		xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1229		xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1230		if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
1231		else xinfo[i].slow_hflip=0;
1232
1233		if(xinfo[i].crop)
1234		{
1235			xinfo[i].crop_xoffset=t[i].r.x;  xinfo[i].crop_xoffset_set=JCROP_POS;
1236			xinfo[i].crop_yoffset=t[i].r.y;  xinfo[i].crop_yoffset_set=JCROP_POS;
1237			if(t[i].r.w!=0)
1238			{
1239				xinfo[i].crop_width=t[i].r.w;  xinfo[i].crop_width_set=JCROP_POS;
1240			}
1241			else xinfo[i].crop_width=JCROP_UNSET;
1242			if(t[i].r.h!=0)
1243			{
1244				xinfo[i].crop_height=t[i].r.h;  xinfo[i].crop_height_set=JCROP_POS;
1245			}
1246			else xinfo[i].crop_height=JCROP_UNSET;
1247		}
1248	}
1249
1250	jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1251	jpeg_read_header(dinfo, TRUE);
1252	jpegSubsamp=getSubsamp(dinfo);
1253	if(jpegSubsamp<0)
1254		_throw("tjTransform(): Could not determine subsampling type for JPEG image");
1255
1256	for(i=0; i<n; i++)
1257	{
1258		if(!jtransform_request_workspace(dinfo, &xinfo[i]))
1259			_throw("tjTransform(): Transform is not perfect");
1260
1261		if(xinfo[i].crop)
1262		{
1263			if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1264				|| (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1265			{
1266				snprintf(errStr, JMSG_LENGTH_MAX,
1267					"To crop this JPEG image, x must be a multiple of %d\n"
1268					"and y must be a multiple of %d.\n",
1269					xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1270				retval=-1;  goto bailout;
1271			}
1272		}
1273	}
1274
1275	srccoefs=jpeg_read_coefficients(dinfo);
1276
1277	for(i=0; i<n; i++)
1278	{
1279		int w, h, alloc=1;
1280		if(!xinfo[i].crop)
1281		{
1282			w=dinfo->image_width;  h=dinfo->image_height;
1283		}
1284		else
1285		{
1286			w=xinfo[i].crop_width;  h=xinfo[i].crop_height;
1287		}
1288		if(flags&TJFLAG_NOREALLOC)
1289		{
1290			alloc=0;  dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
1291		}
1292		if(!(t[i].options&TJXOPT_NOOUTPUT))
1293			jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
1294		jpeg_copy_critical_parameters(dinfo, cinfo);
1295		dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
1296			&xinfo[i]);
1297		if(!(t[i].options&TJXOPT_NOOUTPUT))
1298		{
1299			jpeg_write_coefficients(cinfo, dstcoefs);
1300			jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1301		}
1302		else jinit_c_master_control(cinfo, TRUE);
1303		jtransform_execute_transformation(dinfo, cinfo, srccoefs,
1304			&xinfo[i]);
1305		if(t[i].customFilter)
1306		{
1307			int ci, y;  JDIMENSION by;
1308			for(ci=0; ci<cinfo->num_components; ci++)
1309			{
1310				jpeg_component_info *compptr=&cinfo->comp_info[ci];
1311				tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1312					DCTSIZE};
1313				tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1314					compptr->height_in_blocks*DCTSIZE};
1315				for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1316				{
1317					JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1318						((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1319						TRUE);
1320					for(y=0; y<compptr->v_samp_factor; y++)
1321					{
1322						if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
1323							ci, i, &t[i])==-1)
1324							_throw("tjTransform(): Error in custom filter");
1325						arrayRegion.y+=DCTSIZE;
1326					}
1327				}
1328			}
1329		}
1330		if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
1331	}
1332
1333	jpeg_finish_decompress(dinfo);
1334
1335	bailout:
1336	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1337	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1338	if(xinfo) free(xinfo);
1339	return retval;
1340}
1341