1 /*
2  * Copyright (C)2009-2012 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 <string.h>
34 #ifndef JCS_EXTENSIONS
35 #define JPEG_INTERNAL_OPTIONS
36 #endif
37 #include <jpeglib.h>
38 #include <jerror.h>
39 #include <setjmp.h>
40 #include "./turbojpeg.h"
41 
42 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
43 
44 #define CSTATE_START 100
45 #define DSTATE_START 200
46 #define MEMZERO(ptr, size) memset(ptr, 0, size)
47 
48 #ifndef min
49  #define min(a,b) ((a)<(b)?(a):(b))
50 #endif
51 
52 #ifndef max
53  #define max(a,b) ((a)>(b)?(a):(b))
54 #endif
55 
56 
57 /* Error handling (based on example in example.c) */
58 
59 static char errStr[JMSG_LENGTH_MAX]="No error";
60 
61 struct my_error_mgr
62 {
63 	struct jpeg_error_mgr pub;
64 	jmp_buf setjmp_buffer;
65 };
66 typedef struct my_error_mgr *my_error_ptr;
67 
my_error_exit(j_common_ptr cinfo)68 static void my_error_exit(j_common_ptr cinfo)
69 {
70 	my_error_ptr myerr=(my_error_ptr)cinfo->err;
71 	(*cinfo->err->output_message)(cinfo);
72 	longjmp(myerr->setjmp_buffer, 1);
73 }
74 
75 /* Based on output_message() in jerror.c */
76 
my_output_message(j_common_ptr cinfo)77 static void my_output_message(j_common_ptr cinfo)
78 {
79 	(*cinfo->err->format_message)(cinfo, errStr);
80 }
81 
82 
83 /* Global structures, macros, etc. */
84 
85 enum {COMPRESS=1, DECOMPRESS=2};
86 
87 typedef struct _tjinstance
88 {
89 	struct jpeg_compress_struct cinfo;
90 	struct jpeg_decompress_struct dinfo;
91 	struct jpeg_destination_mgr jdst;
92 	struct jpeg_source_mgr jsrc;
93 	struct my_error_mgr jerr;
94 	int init;
95 } tjinstance;
96 
97 static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
98 
99 #define NUMSF 4
100 static const tjscalingfactor sf[NUMSF]={
101 	{1, 1},
102 	{1, 2},
103 	{1, 4},
104 	{1, 8}
105 };
106 
107 #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
108 	retval=-1;  goto bailout;}
109 #define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
110 	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
111 	(void) cinfo; (void) dinfo; /* silence warnings */ \
112 	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
113 		return -1;}  \
114 	cinfo=&this->cinfo;  dinfo=&this->dinfo;
115 
getPixelFormat(int pixelSize,int flags)116 static int getPixelFormat(int pixelSize, int flags)
117 {
118 	if(pixelSize==1) return TJPF_GRAY;
119 	if(pixelSize==3)
120 	{
121 		if(flags&TJ_BGR) return TJPF_BGR;
122 		else return TJPF_RGB;
123 	}
124 	if(pixelSize==4)
125 	{
126 		if(flags&TJ_ALPHAFIRST)
127 		{
128 			if(flags&TJ_BGR) return TJPF_XBGR;
129 			else return TJPF_XRGB;
130 		}
131 		else
132 		{
133 			if(flags&TJ_BGR) return TJPF_BGRX;
134 			else return TJPF_RGBX;
135 		}
136 	}
137 	return -1;
138 }
139 
setCompDefaults(struct jpeg_compress_struct * cinfo,int pixelFormat,int subsamp,int jpegQual)140 static int setCompDefaults(struct jpeg_compress_struct *cinfo,
141 	int pixelFormat, int subsamp, int jpegQual)
142 {
143 	int retval=0;
144 
145 	switch(pixelFormat)
146 	{
147 		case TJPF_GRAY:
148 			cinfo->in_color_space=JCS_GRAYSCALE;  break;
149 		#if JCS_EXTENSIONS==1
150 		case TJPF_RGB:
151 			cinfo->in_color_space=JCS_EXT_RGB;  break;
152 		case TJPF_BGR:
153 			cinfo->in_color_space=JCS_EXT_BGR;  break;
154 		case TJPF_RGBX:
155 		case TJPF_RGBA:
156 			cinfo->in_color_space=JCS_EXT_RGBX;  break;
157 		case TJPF_BGRX:
158 		case TJPF_BGRA:
159 			cinfo->in_color_space=JCS_EXT_BGRX;  break;
160 		case TJPF_XRGB:
161 		case TJPF_ARGB:
162 			cinfo->in_color_space=JCS_EXT_XRGB;  break;
163 		case TJPF_XBGR:
164 		case TJPF_ABGR:
165 			cinfo->in_color_space=JCS_EXT_XBGR;  break;
166 		#else
167 		case TJPF_RGB:
168 		case TJPF_BGR:
169 		case TJPF_RGBX:
170 		case TJPF_BGRX:
171 		case TJPF_XRGB:
172 		case TJPF_XBGR:
173 		case TJPF_RGBA:
174 		case TJPF_BGRA:
175 		case TJPF_ARGB:
176 		case TJPF_ABGR:
177 			cinfo->in_color_space=JCS_RGB;  pixelFormat=TJPF_RGB;
178 			break;
179 		#endif
180 	}
181 
182 	cinfo->input_components=tjPixelSize[pixelFormat];
183 	jpeg_set_defaults(cinfo);
184 	if(jpegQual>=0)
185 	{
186 		jpeg_set_quality(cinfo, jpegQual, TRUE);
187 		if(jpegQual>=96) cinfo->dct_method=JDCT_ISLOW;
188 		else cinfo->dct_method=JDCT_FASTEST;
189 	}
190 	if(subsamp==TJSAMP_GRAY)
191 		jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
192 	else
193 		jpeg_set_colorspace(cinfo, JCS_YCbCr);
194 
195 	cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
196 	cinfo->comp_info[1].h_samp_factor=1;
197 	cinfo->comp_info[2].h_samp_factor=1;
198 	cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
199 	cinfo->comp_info[1].v_samp_factor=1;
200 	cinfo->comp_info[2].v_samp_factor=1;
201 
202 	return retval;
203 }
204 
setDecompDefaults(struct jpeg_decompress_struct * dinfo,int pixelFormat)205 static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
206 	int pixelFormat)
207 {
208 	int retval=0;
209 
210 	switch(pixelFormat)
211 	{
212 		case TJPF_GRAY:
213 			dinfo->out_color_space=JCS_GRAYSCALE;  break;
214 		#if JCS_EXTENSIONS==1
215 		case TJPF_RGB:
216 			dinfo->out_color_space=JCS_EXT_RGB;  break;
217 		case TJPF_BGR:
218 			dinfo->out_color_space=JCS_EXT_BGR;  break;
219 		case TJPF_RGBX:
220 			dinfo->out_color_space=JCS_EXT_RGBX;  break;
221 		case TJPF_BGRX:
222 			dinfo->out_color_space=JCS_EXT_BGRX;  break;
223 		case TJPF_XRGB:
224 			dinfo->out_color_space=JCS_EXT_XRGB;  break;
225 		case TJPF_XBGR:
226 			dinfo->out_color_space=JCS_EXT_XBGR;  break;
227 		#if JCS_ALPHA_EXTENSIONS==1
228 		case TJPF_RGBA:
229 			dinfo->out_color_space=JCS_EXT_RGBA;  break;
230 		case TJPF_BGRA:
231 			dinfo->out_color_space=JCS_EXT_BGRA;  break;
232 		case TJPF_ARGB:
233 			dinfo->out_color_space=JCS_EXT_ARGB;  break;
234 		case TJPF_ABGR:
235 			dinfo->out_color_space=JCS_EXT_ABGR;  break;
236 		#endif
237 		#else
238 		case TJPF_RGB:
239 		case TJPF_BGR:
240 		case TJPF_RGBX:
241 		case TJPF_BGRX:
242 		case TJPF_XRGB:
243 		case TJPF_XBGR:
244 		case TJPF_RGBA:
245 		case TJPF_BGRA:
246 		case TJPF_ARGB:
247 		case TJPF_ABGR:
248 			dinfo->out_color_space=JCS_RGB;  break;
249 		#endif
250 		default:
251 			_throw("Unsupported pixel format");
252 	}
253 
254 	bailout:
255 	return retval;
256 }
257 
258 
getSubsamp(j_decompress_ptr dinfo)259 static int getSubsamp(j_decompress_ptr dinfo)
260 {
261 	int retval=-1, i, k;
262 	for(i=0; i<NUMSUBOPT; i++)
263 	{
264 		if(dinfo->num_components==pixelsize[i])
265 		{
266 			if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
267 				&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
268 			{
269 				int match=0;
270 				for(k=1; k<dinfo->num_components; k++)
271 				{
272 					if(dinfo->comp_info[k].h_samp_factor==1
273 						&& dinfo->comp_info[k].v_samp_factor==1)
274 						match++;
275 				}
276 				if(match==dinfo->num_components-1)
277 				{
278 					retval=i;  break;
279 				}
280 			}
281 		}
282 	}
283 	return retval;
284 }
285 
286 
287 #ifndef JCS_EXTENSIONS
288 
289 /* Conversion functions to emulate the colorspace extensions.  This allows the
290    TurboJPEG wrapper to be used with libjpeg */
291 
292 #define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
293 	int rowPad=pitch-width*PS;  \
294 	while(height--)  \
295 	{  \
296 		unsigned char *endOfRow=src+width*PS;  \
297 		while(src<endOfRow)  \
298 		{  \
299 			dst[RGB_RED]=src[ROFFSET];  \
300 			dst[RGB_GREEN]=src[GOFFSET];  \
301 			dst[RGB_BLUE]=src[BOFFSET];  \
302 			dst+=RGB_PIXELSIZE;  src+=PS;  \
303 		}  \
304 		src+=rowPad;  \
305 	}  \
306 }
307 
toRGB(unsigned char * src,int width,int pitch,int height,int pixelFormat,unsigned char * dst)308 static unsigned char *toRGB(unsigned char *src, int width, int pitch,
309 	int height, int pixelFormat, unsigned char *dst)
310 {
311 	unsigned char *retval=src;
312 	switch(pixelFormat)
313 	{
314 		case TJPF_RGB:
315 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
316 			retval=dst;  TORGB(3, 0, 1, 2);
317 			#endif
318 			break;
319 		case TJPF_BGR:
320 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
321 			retval=dst;  TORGB(3, 2, 1, 0);
322 			#endif
323 			break;
324 		case TJPF_RGBX:
325 		case TJPF_RGBA:
326 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
327 			retval=dst;  TORGB(4, 0, 1, 2);
328 			#endif
329 			break;
330 		case TJPF_BGRX:
331 		case TJPF_BGRA:
332 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
333 			retval=dst;  TORGB(4, 2, 1, 0);
334 			#endif
335 			break;
336 		case TJPF_XRGB:
337 		case TJPF_ARGB:
338 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
339 			retval=dst;  TORGB(4, 1, 2, 3);
340 			#endif
341 			break;
342 		case TJPF_XBGR:
343 		case TJPF_ABGR:
344 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
345 			retval=dst;  TORGB(4, 3, 2, 1);
346 			#endif
347 			break;
348 	}
349 	return retval;
350 }
351 
352 #define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) {  \
353 	int rowPad=pitch-width*PS;  \
354 	while(height--)  \
355 	{  \
356 		unsigned char *endOfRow=dst+width*PS;  \
357 		while(dst<endOfRow)  \
358 		{  \
359 			dst[ROFFSET]=src[RGB_RED];  \
360 			dst[GOFFSET]=src[RGB_GREEN];  \
361 			dst[BOFFSET]=src[RGB_BLUE];  \
362 			SETALPHA  \
363 			dst+=PS;  src+=RGB_PIXELSIZE;  \
364 		}  \
365 		dst+=rowPad;  \
366 	}  \
367 }
368 
fromRGB(unsigned char * src,unsigned char * dst,int width,int pitch,int height,int pixelFormat)369 static void fromRGB(unsigned char *src, unsigned char *dst, int width,
370 	int pitch, int height, int pixelFormat)
371 {
372 	switch(pixelFormat)
373 	{
374 		case TJPF_RGB:
375 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
376 			FROMRGB(3, 0, 1, 2,);
377 			#endif
378 			break;
379 		case TJPF_BGR:
380 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
381 			FROMRGB(3, 2, 1, 0,);
382 			#endif
383 			break;
384 		case TJPF_RGBX:
385 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
386 			FROMRGB(4, 0, 1, 2,);
387 			#endif
388 			break;
389 		case TJPF_RGBA:
390 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
391 			FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
392 			#endif
393 			break;
394 		case TJPF_BGRX:
395 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
396 			FROMRGB(4, 2, 1, 0,);
397 			#endif
398 			break;
399 		case TJPF_BGRA:
400 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
401 			FROMRGB(4, 2, 1, 0, dst[3]=0xFF;);  return;
402 			#endif
403 			break;
404 		case TJPF_XRGB:
405 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
406 			FROMRGB(4, 1, 2, 3,);  return;
407 			#endif
408 			break;
409 		case TJPF_ARGB:
410 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
411 			FROMRGB(4, 1, 2, 3, dst[0]=0xFF;);  return;
412 			#endif
413 			break;
414 		case TJPF_XBGR:
415 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
416 			FROMRGB(4, 3, 2, 1,);  return;
417 			#endif
418 			break;
419 		case TJPF_ABGR:
420 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
421 			FROMRGB(4, 3, 2, 1, dst[0]=0xFF;);  return;
422 			#endif
423 			break;
424 	}
425 }
426 
427 #endif
428 
429 
430 /* General API functions */
431 
tjGetErrorStr(void)432 DLLEXPORT char* DLLCALL tjGetErrorStr(void)
433 {
434 	return errStr;
435 }
436 
437 
tjDestroy(tjhandle handle)438 DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
439 {
440 	getinstance(handle);
441 	if(setjmp(this->jerr.setjmp_buffer)) return -1;
442 	if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
443 	if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
444 	free(this);
445 	return 0;
446 }
447 
448 
449 /* Compressor  */
450 
empty_output_buffer(j_compress_ptr cinfo)451 static boolean empty_output_buffer(j_compress_ptr cinfo)
452 {
453 	ERREXIT(cinfo, JERR_BUFFER_SIZE);
454 	return TRUE;
455 }
456 
dst_noop(j_compress_ptr cinfo)457 static void dst_noop(j_compress_ptr cinfo)
458 {
459 }
460 
_tjInitCompress(tjinstance * this)461 static tjhandle _tjInitCompress(tjinstance *this)
462 {
463 	/* This is also straight out of example.c */
464 	this->cinfo.err=jpeg_std_error(&this->jerr.pub);
465 	this->jerr.pub.error_exit=my_error_exit;
466 	this->jerr.pub.output_message=my_output_message;
467 
468 	if(setjmp(this->jerr.setjmp_buffer))
469 	{
470 		/* If we get here, the JPEG code has signaled an error. */
471 		if(this) free(this);  return NULL;
472 	}
473 
474 	jpeg_create_compress(&this->cinfo);
475 	this->cinfo.dest=&this->jdst;
476 	this->jdst.init_destination=dst_noop;
477 	this->jdst.empty_output_buffer=empty_output_buffer;
478 	this->jdst.term_destination=dst_noop;
479 
480 	this->init|=COMPRESS;
481 	return (tjhandle)this;
482 }
483 
tjInitCompress(void)484 DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
485 {
486 	tjinstance *this=NULL;
487 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
488 	{
489 		snprintf(errStr, JMSG_LENGTH_MAX,
490 			"tjInitCompress(): Memory allocation failure");
491 		return NULL;
492 	}
493 	MEMZERO(this, sizeof(tjinstance));
494 	return _tjInitCompress(this);
495 }
496 
497 
tjBufSize(int width,int height,int jpegSubsamp)498 DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
499 	int jpegSubsamp)
500 {
501 	unsigned long retval=0;  int mcuw, mcuh, chromasf;
502 	if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
503 		_throw("tjBufSize(): Invalid argument");
504 
505 	// This allows for rare corner cases in which a JPEG image can actually be
506 	// larger than the uncompressed input (we wouldn't mention it if it hadn't
507 	// happened before.)
508 	mcuw=tjMCUWidth[jpegSubsamp];
509 	mcuh=tjMCUHeight[jpegSubsamp];
510 	chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
511 	retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
512 
513 	bailout:
514 	return retval;
515 }
516 
517 
TJBUFSIZE(int width,int height)518 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
519 {
520 	unsigned long retval=0;
521 	if(width<1 || height<1)
522 		_throw("TJBUFSIZE(): Invalid argument");
523 
524 	// This allows for rare corner cases in which a JPEG image can actually be
525 	// larger than the uncompressed input (we wouldn't mention it if it hadn't
526 	// happened before.)
527 	retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
528 
529 	bailout:
530 	return retval;
531 }
532 
533 
tjCompress2(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char ** jpegBuf,unsigned long * jpegSize,int jpegSubsamp,int jpegQual,int flags)534 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
535 	int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
536 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
537 {
538 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
539 	#ifndef JCS_EXTENSIONS
540 	unsigned char *rgbBuf=NULL;
541 	#endif
542 
543 	getinstance(handle)
544 	if((this->init&COMPRESS)==0)
545 		_throw("tjCompress2(): Instance has not been initialized for compression");
546 
547 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
548 		|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
549 		|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
550 		_throw("tjCompress2(): Invalid argument");
551 
552 	if(setjmp(this->jerr.setjmp_buffer))
553 	{
554 		/* If we get here, the JPEG code has signaled an error. */
555 		retval=-1;
556 		goto bailout;
557 	}
558 
559 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
560 
561 	#ifndef JCS_EXTENSIONS
562 	if(pixelFormat!=TJPF_GRAY)
563 	{
564 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
565 		if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
566 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
567 		pitch=width*RGB_PIXELSIZE;
568 	}
569 	#endif
570 
571 	cinfo->image_width=width;
572 	cinfo->image_height=height;
573 
574 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
575 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
576 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
577 
578 	if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1)
579 		return -1;
580 
581 	this->jdst.next_output_byte=*jpegBuf;
582 	this->jdst.free_in_buffer=tjBufSize(width, height, jpegSubsamp);
583 
584 	jpeg_start_compress(cinfo, TRUE);
585 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
586 		_throw("tjCompress2(): Memory allocation failure");
587 	for(i=0; i<height; i++)
588 	{
589 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
590 		else row_pointer[i]=&srcBuf[i*pitch];
591 	}
592 	while(cinfo->next_scanline<cinfo->image_height)
593 	{
594 		jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
595 			cinfo->image_height-cinfo->next_scanline);
596 	}
597 	jpeg_finish_compress(cinfo);
598  	*jpegSize=tjBufSize(width, height, jpegSubsamp)
599 		-(unsigned long)(this->jdst.free_in_buffer);
600 
601 	bailout:
602 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
603 	#ifndef JCS_EXTENSIONS
604 	if(rgbBuf) free(rgbBuf);
605 	#endif
606 	if(row_pointer) free(row_pointer);
607 	return retval;
608 }
609 
tjCompress(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelSize,unsigned char * jpegBuf,unsigned long * jpegSize,int jpegSubsamp,int jpegQual,int flags)610 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
611 	int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
612 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
613 {
614 	int retval=0;  unsigned long size;
615 	retval=tjCompress2(handle, srcBuf, width, pitch, height,
616 		getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
617 		flags);
618 	*jpegSize=size;
619 	return retval;
620 }
621 
622 
623 /* Decompressor */
624 
fill_input_buffer(j_decompress_ptr dinfo)625 static boolean fill_input_buffer(j_decompress_ptr dinfo)
626 {
627 	ERREXIT(dinfo, JERR_BUFFER_SIZE);
628 	return TRUE;
629 }
630 
skip_input_data(j_decompress_ptr dinfo,long num_bytes)631 static void skip_input_data(j_decompress_ptr dinfo, long num_bytes)
632 {
633 	dinfo->src->next_input_byte += (size_t) num_bytes;
634 	dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
635 }
636 
src_noop(j_decompress_ptr dinfo)637 static void src_noop(j_decompress_ptr dinfo)
638 {
639 }
640 
_tjInitDecompress(tjinstance * this)641 static tjhandle _tjInitDecompress(tjinstance *this)
642 {
643 	/* This is also straight out of example.c */
644 	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
645 	this->jerr.pub.error_exit=my_error_exit;
646 	this->jerr.pub.output_message=my_output_message;
647 
648 	if(setjmp(this->jerr.setjmp_buffer))
649 	{
650 		/* If we get here, the JPEG code has signaled an error. */
651 		if(this) free(this);  return NULL;
652 	}
653 
654 	jpeg_create_decompress(&this->dinfo);
655 	this->dinfo.src=&this->jsrc;
656 	this->jsrc.init_source=src_noop;
657 	this->jsrc.fill_input_buffer=fill_input_buffer;
658 	this->jsrc.skip_input_data=skip_input_data;
659 	this->jsrc.resync_to_restart=jpeg_resync_to_restart;
660 	this->jsrc.term_source=src_noop;
661 
662 	this->init|=DECOMPRESS;
663 	return (tjhandle)this;
664 }
665 
tjInitDecompress(void)666 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
667 {
668 	tjinstance *this;
669 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
670 	{
671 		snprintf(errStr, JMSG_LENGTH_MAX,
672 			"tjInitDecompress(): Memory allocation failure");
673 		return NULL;
674 	}
675 	MEMZERO(this, sizeof(tjinstance));
676 	return _tjInitDecompress(this);
677 }
678 
679 
tjDecompressHeader2(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height,int * jpegSubsamp)680 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
681 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
682 	int *jpegSubsamp)
683 {
684 	int retval=0;
685 
686 	getinstance(handle);
687 	if((this->init&DECOMPRESS)==0)
688 		_throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
689 
690 	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
691 		|| jpegSubsamp==NULL)
692 		_throw("tjDecompressHeader2(): Invalid argument");
693 
694 	if(setjmp(this->jerr.setjmp_buffer))
695 	{
696 		/* If we get here, the JPEG code has signaled an error. */
697 		return -1;
698 	}
699 
700 	this->jsrc.bytes_in_buffer=jpegSize;
701 	this->jsrc.next_input_byte=jpegBuf;
702 	jpeg_read_header(dinfo, TRUE);
703 
704 	*width=dinfo->image_width;
705 	*height=dinfo->image_height;
706 	*jpegSubsamp=getSubsamp(dinfo);
707 
708 	jpeg_abort_decompress(dinfo);
709 
710 	if(*jpegSubsamp<0)
711 		_throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
712 	if(*width<1 || *height<1)
713 		_throw("tjDecompressHeader2(): Invalid data returned in header");
714 
715 	bailout:
716 	return retval;
717 }
718 
tjDecompressHeader(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height)719 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
720 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
721 {
722 	int jpegSubsamp;
723 	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
724 		&jpegSubsamp);
725 }
726 
727 
tjGetScalingFactors(int * numscalingfactors)728 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
729 {
730 	if(numscalingfactors==NULL)
731 	{
732 		snprintf(errStr, JMSG_LENGTH_MAX,
733 			"tjGetScalingFactors(): Invalid argument");
734 		return NULL;
735 	}
736 
737 	*numscalingfactors=NUMSF;
738 	return (tjscalingfactor *)sf;
739 }
740 
741 
tjDecompress2(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)742 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
743 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
744 	int height, int pixelFormat, int flags)
745 {
746 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
747 	int jpegwidth, jpegheight, scaledw, scaledh;
748 	#ifndef JCS_EXTENSIONS
749 	unsigned char *rgbBuf=NULL;
750 	unsigned char *_dstBuf=NULL;  int _pitch=0;
751 	#endif
752 
753 	getinstance(handle);
754 	if((this->init&DECOMPRESS)==0)
755 		_throw("tjDecompress2(): Instance has not been initialized for decompression");
756 
757 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
758 		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
759 		_throw("tjDecompress2(): Invalid argument");
760 
761 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
762 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
763 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
764 
765 	if(setjmp(this->jerr.setjmp_buffer))
766 	{
767 		/* If we get here, the JPEG code has signaled an error. */
768 		retval=-1;
769 		goto bailout;
770 	}
771 
772 	this->jsrc.bytes_in_buffer=jpegSize;
773 	this->jsrc.next_input_byte=jpegBuf;
774 	jpeg_read_header(dinfo, TRUE);
775 	if(setDecompDefaults(dinfo, pixelFormat)==-1)
776 	{
777 		retval=-1;  goto bailout;
778 	}
779 
780 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
781 
782 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
783 	if(width==0) width=jpegwidth;
784 	if(height==0) height=jpegheight;
785 	for(i=0; i<NUMSF; i++)
786 	{
787 		scaledw=TJSCALED(jpegwidth, sf[i]);
788 		scaledh=TJSCALED(jpegheight, sf[i]);
789 		if(scaledw<=width && scaledh<=height)
790 				break;
791 	}
792 	if(scaledw>width || scaledh>height)
793 		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
794 	width=scaledw;  height=scaledh;
795 	dinfo->scale_num=sf[i].num;
796 	dinfo->scale_denom=sf[i].denom;
797 
798 	jpeg_start_decompress(dinfo);
799 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
800 
801 	#ifndef JCS_EXTENSIONS
802 	if(pixelFormat!=TJPF_GRAY &&
803 		(RGB_RED!=tjRedOffset[pixelFormat] ||
804 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
805 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
806 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
807 	{
808 		rgbBuf=(unsigned char *)malloc(width*height*3);
809 		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
810 		_pitch=pitch;  pitch=width*3;
811 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
812 	}
813 	#endif
814 
815 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
816 		*dinfo->output_height))==NULL)
817 		_throw("tjDecompress2(): Memory allocation failure");
818 	for(i=0; i<(int)dinfo->output_height; i++)
819 	{
820 		if(flags&TJFLAG_BOTTOMUP)
821 			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
822 		else row_pointer[i]=&dstBuf[i*pitch];
823 	}
824 	while(dinfo->output_scanline<dinfo->output_height)
825 	{
826 		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
827 			dinfo->output_height-dinfo->output_scanline);
828 	}
829 	jpeg_finish_decompress(dinfo);
830 
831 	#ifndef JCS_EXTENSIONS
832 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
833 	#endif
834 
835 	bailout:
836 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
837 	#ifndef JCS_EXTENSIONS
838 	if(rgbBuf) free(rgbBuf);
839 	#endif
840 	if(row_pointer) free(row_pointer);
841 	return retval;
842 }
843 
tjDecompress(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelSize,int flags)844 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
845 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
846 	int height, int pixelSize, int flags)
847 {
848 	return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
849 		height, getPixelFormat(pixelSize, flags), flags);
850 }
851