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