• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
43 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
44 	unsigned long *, boolean);
45 extern 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 
52 static char errStr[JMSG_LENGTH_MAX]="No error";
53 
54 struct my_error_mgr
55 {
56 	struct jpeg_error_mgr pub;
57 	jmp_buf setjmp_buffer;
58 };
59 typedef struct my_error_mgr *my_error_ptr;
60 
my_error_exit(j_common_ptr cinfo)61 static 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 
my_output_message(j_common_ptr cinfo)70 static 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 
78 enum {COMPRESS=1, DECOMPRESS=2};
79 
80 typedef 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 
88 static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
89 
90 static 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
97 static 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 
getPixelFormat(int pixelSize,int flags)124 static 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 
setCompDefaults(struct jpeg_compress_struct * cinfo,int pixelFormat,int subsamp,int jpegQual,int flags)148 static 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 
setDecompDefaults(struct jpeg_decompress_struct * dinfo,int pixelFormat,int flags)213 static 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 
getSubsamp(j_decompress_ptr dinfo)269 static 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 
toRGB(unsigned char * src,int width,int pitch,int height,int pixelFormat,unsigned char * dst)318 static 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 
fromRGB(unsigned char * src,unsigned char * dst,int width,int pitch,int height,int pixelFormat)379 static 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 
tjGetErrorStr(void)442 DLLEXPORT char* DLLCALL tjGetErrorStr(void)
443 {
444 	return errStr;
445 }
446 
447 
tjDestroy(tjhandle handle)448 DLLEXPORT 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 
tjFree(unsigned char * buf)464 DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
465 {
466 	if(buf) free(buf);
467 }
468 
469 
tjAlloc(int bytes)470 DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
471 {
472 	return (unsigned char *)malloc(bytes);
473 }
474 
475 
476 /* Compressor  */
477 
_tjInitCompress(tjinstance * this)478 static 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 
tjInitCompress(void)501 DLLEXPORT 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 
tjBufSize(int width,int height,int jpegSubsamp)515 DLLEXPORT 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 
TJBUFSIZE(int width,int height)534 DLLEXPORT 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 
tjBufSizeYUV(int width,int height,int subsamp)550 DLLEXPORT 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 
TJBUFSIZEYUV(int width,int height,int subsamp)567 DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
568 	int subsamp)
569 {
570 	return tjBufSizeYUV(width, height, subsamp);
571 }
572 
573 
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)574 DLLEXPORT 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 
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)650 DLLEXPORT 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 
tjEncodeYUV2(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char * dstBuf,int subsamp,int flags)672 DLLEXPORT 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 
tjEncodeYUV(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelSize,unsigned char * dstBuf,int subsamp,int flags)830 DLLEXPORT 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 
_tjInitDecompress(tjinstance * this)841 static 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 
tjInitDecompress(void)864 DLLEXPORT 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 
tjDecompressHeader2(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height,int * jpegSubsamp)878 DLLEXPORT 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 
tjDecompressHeader(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height)916 DLLEXPORT 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 
tjGetScalingFactors(int * numscalingfactors)925 DLLEXPORT 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 
tjDecompress2(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)939 DLLEXPORT 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 
tjDecompress(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelSize,int flags)1040 DLLEXPORT 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 
tjDecompressToYUV(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int flags)1052 DLLEXPORT 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 
tjInitTransform(void)1172 DLLEXPORT 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 
tjTransform(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int n,unsigned char ** dstBufs,unsigned long * dstSizes,tjtransform * t,int flags)1189 DLLEXPORT 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