• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	/*
506 	 * This allows for rare corner cases in which a JPEG image can actually be
507 	 * larger than the uncompressed input (we wouldn't mention it if it hadn't
508 	 * happened before.)
509 	 */
510 	mcuw=tjMCUWidth[jpegSubsamp];
511 	mcuh=tjMCUHeight[jpegSubsamp];
512 	chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
513 	retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
514 
515 	bailout:
516 	return retval;
517 }
518 
519 
TJBUFSIZE(int width,int height)520 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
521 {
522 	unsigned long retval=0;
523 	if(width<1 || height<1)
524 		_throw("TJBUFSIZE(): Invalid argument");
525 
526 	/*
527 	 * This allows for rare corner cases in which a JPEG image can actually be
528 	 * larger than the uncompressed input (we wouldn't mention it if it hadn't
529 	 * happened before.)
530 	 */
531 	retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
532 
533 	bailout:
534 	return retval;
535 }
536 
537 
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)538 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
539 	int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
540 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
541 {
542 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
543 	#ifndef JCS_EXTENSIONS
544 	unsigned char *rgbBuf=NULL;
545 	#endif
546 
547 	getinstance(handle)
548 	if((this->init&COMPRESS)==0)
549 		_throw("tjCompress2(): Instance has not been initialized for compression");
550 
551 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
552 		|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
553 		|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
554 		_throw("tjCompress2(): Invalid argument");
555 
556 	if(setjmp(this->jerr.setjmp_buffer))
557 	{
558 		/* If we get here, the JPEG code has signaled an error. */
559 		retval=-1;
560 		goto bailout;
561 	}
562 
563 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
564 
565 	#ifndef JCS_EXTENSIONS
566 	if(pixelFormat!=TJPF_GRAY)
567 	{
568 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
569 		if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
570 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
571 		pitch=width*RGB_PIXELSIZE;
572 	}
573 	#endif
574 
575 	cinfo->image_width=width;
576 	cinfo->image_height=height;
577 
578 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
579 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
580 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
581 
582 	if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual)==-1)
583 		return -1;
584 
585 	this->jdst.next_output_byte=*jpegBuf;
586 	this->jdst.free_in_buffer=tjBufSize(width, height, jpegSubsamp);
587 
588 	jpeg_start_compress(cinfo, TRUE);
589 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
590 		_throw("tjCompress2(): Memory allocation failure");
591 	for(i=0; i<height; i++)
592 	{
593 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
594 		else row_pointer[i]=&srcBuf[i*pitch];
595 	}
596 	while(cinfo->next_scanline<cinfo->image_height)
597 	{
598 		jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
599 			cinfo->image_height-cinfo->next_scanline);
600 	}
601 	jpeg_finish_compress(cinfo);
602  	*jpegSize=tjBufSize(width, height, jpegSubsamp)
603 		-(unsigned long)(this->jdst.free_in_buffer);
604 
605 	bailout:
606 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
607 	#ifndef JCS_EXTENSIONS
608 	if(rgbBuf) free(rgbBuf);
609 	#endif
610 	if(row_pointer) free(row_pointer);
611 	return retval;
612 }
613 
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)614 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
615 	int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
616 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
617 {
618 	int retval=0;  unsigned long size;
619 	retval=tjCompress2(handle, srcBuf, width, pitch, height,
620 		getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
621 		flags);
622 	*jpegSize=size;
623 	return retval;
624 }
625 
626 
627 /* Decompressor */
628 
fill_input_buffer(j_decompress_ptr dinfo)629 static boolean fill_input_buffer(j_decompress_ptr dinfo)
630 {
631 	ERREXIT(dinfo, JERR_BUFFER_SIZE);
632 	return TRUE;
633 }
634 
skip_input_data(j_decompress_ptr dinfo,long num_bytes)635 static void skip_input_data(j_decompress_ptr dinfo, long num_bytes)
636 {
637 	dinfo->src->next_input_byte += (size_t) num_bytes;
638 	dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
639 }
640 
src_noop(j_decompress_ptr dinfo)641 static void src_noop(j_decompress_ptr dinfo)
642 {
643 }
644 
_tjInitDecompress(tjinstance * this)645 static tjhandle _tjInitDecompress(tjinstance *this)
646 {
647 	/* This is also straight out of example.c */
648 	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
649 	this->jerr.pub.error_exit=my_error_exit;
650 	this->jerr.pub.output_message=my_output_message;
651 
652 	if(setjmp(this->jerr.setjmp_buffer))
653 	{
654 		/* If we get here, the JPEG code has signaled an error. */
655 		if(this) free(this);  return NULL;
656 	}
657 
658 	jpeg_create_decompress(&this->dinfo);
659 	this->dinfo.src=&this->jsrc;
660 	this->jsrc.init_source=src_noop;
661 	this->jsrc.fill_input_buffer=fill_input_buffer;
662 	this->jsrc.skip_input_data=skip_input_data;
663 	this->jsrc.resync_to_restart=jpeg_resync_to_restart;
664 	this->jsrc.term_source=src_noop;
665 
666 	this->init|=DECOMPRESS;
667 	return (tjhandle)this;
668 }
669 
tjInitDecompress(void)670 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
671 {
672 	tjinstance *this;
673 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
674 	{
675 		snprintf(errStr, JMSG_LENGTH_MAX,
676 			"tjInitDecompress(): Memory allocation failure");
677 		return NULL;
678 	}
679 	MEMZERO(this, sizeof(tjinstance));
680 	return _tjInitDecompress(this);
681 }
682 
683 
tjDecompressHeader2(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height,int * jpegSubsamp)684 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
685 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
686 	int *jpegSubsamp)
687 {
688 	int retval=0;
689 
690 	getinstance(handle);
691 	if((this->init&DECOMPRESS)==0)
692 		_throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
693 
694 	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
695 		|| jpegSubsamp==NULL)
696 		_throw("tjDecompressHeader2(): Invalid argument");
697 
698 	if(setjmp(this->jerr.setjmp_buffer))
699 	{
700 		/* If we get here, the JPEG code has signaled an error. */
701 		return -1;
702 	}
703 
704 	this->jsrc.bytes_in_buffer=jpegSize;
705 	this->jsrc.next_input_byte=jpegBuf;
706 	jpeg_read_header(dinfo, TRUE);
707 
708 	*width=dinfo->image_width;
709 	*height=dinfo->image_height;
710 	*jpegSubsamp=getSubsamp(dinfo);
711 
712 	jpeg_abort_decompress(dinfo);
713 
714 	if(*jpegSubsamp<0)
715 		_throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
716 	if(*width<1 || *height<1)
717 		_throw("tjDecompressHeader2(): Invalid data returned in header");
718 
719 	bailout:
720 	return retval;
721 }
722 
tjDecompressHeader(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height)723 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
724 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
725 {
726 	int jpegSubsamp;
727 	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
728 		&jpegSubsamp);
729 }
730 
731 
tjGetScalingFactors(int * numscalingfactors)732 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
733 {
734 	if(numscalingfactors==NULL)
735 	{
736 		snprintf(errStr, JMSG_LENGTH_MAX,
737 			"tjGetScalingFactors(): Invalid argument");
738 		return NULL;
739 	}
740 
741 	*numscalingfactors=NUMSF;
742 	return (tjscalingfactor *)sf;
743 }
744 
745 
tjDecompress2(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)746 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
747 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
748 	int height, int pixelFormat, int flags)
749 {
750 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
751 	int jpegwidth, jpegheight, scaledw, scaledh;
752 	#ifndef JCS_EXTENSIONS
753 	unsigned char *rgbBuf=NULL;
754 	unsigned char *_dstBuf=NULL;  int _pitch=0;
755 	#endif
756 
757 	getinstance(handle);
758 	if((this->init&DECOMPRESS)==0)
759 		_throw("tjDecompress2(): Instance has not been initialized for decompression");
760 
761 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
762 		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
763 		_throw("tjDecompress2(): Invalid argument");
764 
765 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
766 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
767 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
768 
769 	if(setjmp(this->jerr.setjmp_buffer))
770 	{
771 		/* If we get here, the JPEG code has signaled an error. */
772 		retval=-1;
773 		goto bailout;
774 	}
775 
776 	this->jsrc.bytes_in_buffer=jpegSize;
777 	this->jsrc.next_input_byte=jpegBuf;
778 	jpeg_read_header(dinfo, TRUE);
779 	if(setDecompDefaults(dinfo, pixelFormat)==-1)
780 	{
781 		retval=-1;  goto bailout;
782 	}
783 
784 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
785 
786 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
787 	if(width==0) width=jpegwidth;
788 	if(height==0) height=jpegheight;
789 	for(i=0; i<NUMSF; i++)
790 	{
791 		scaledw=TJSCALED(jpegwidth, sf[i]);
792 		scaledh=TJSCALED(jpegheight, sf[i]);
793 		if(scaledw<=width && scaledh<=height)
794 				break;
795 	}
796 	if(scaledw>width || scaledh>height)
797 		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
798 	width=scaledw;  height=scaledh;
799 	dinfo->scale_num=sf[i].num;
800 	dinfo->scale_denom=sf[i].denom;
801 
802 	jpeg_start_decompress(dinfo);
803 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
804 
805 	#ifndef JCS_EXTENSIONS
806 	if(pixelFormat!=TJPF_GRAY &&
807 		(RGB_RED!=tjRedOffset[pixelFormat] ||
808 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
809 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
810 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
811 	{
812 		rgbBuf=(unsigned char *)malloc(width*height*3);
813 		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
814 		_pitch=pitch;  pitch=width*3;
815 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
816 	}
817 	#endif
818 
819 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
820 		*dinfo->output_height))==NULL)
821 		_throw("tjDecompress2(): Memory allocation failure");
822 	for(i=0; i<(int)dinfo->output_height; i++)
823 	{
824 		if(flags&TJFLAG_BOTTOMUP)
825 			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
826 		else row_pointer[i]=&dstBuf[i*pitch];
827 	}
828 	while(dinfo->output_scanline<dinfo->output_height)
829 	{
830 		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
831 			dinfo->output_height-dinfo->output_scanline);
832 	}
833 	jpeg_finish_decompress(dinfo);
834 
835 	#ifndef JCS_EXTENSIONS
836 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
837 	#endif
838 
839 	bailout:
840 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
841 	#ifndef JCS_EXTENSIONS
842 	if(rgbBuf) free(rgbBuf);
843 	#endif
844 	if(row_pointer) free(row_pointer);
845 	return retval;
846 }
847 
tjDecompress(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelSize,int flags)848 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
849 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
850 	int height, int pixelSize, int flags)
851 {
852 	return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
853 		height, getPixelFormat(pixelSize, flags), flags);
854 }
855