1 /*
2  * Copyright (C)2009-2016 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 <ctype.h>
35 #include <jinclude.h>
36 #define JPEG_INTERNALS
37 #include <jpeglib.h>
38 #include <jerror.h>
39 #include <setjmp.h>
40 #include "./turbojpeg.h"
41 #include "./tjutil.h"
42 #include "transupp.h"
43 #include "./jpegcomp.h"
44 
45 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
46 	unsigned long *, boolean);
47 extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
48 	unsigned long);
49 
50 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
51 #define isPow2(x) (((x)&(x-1))==0)
52 
53 
54 /* Error handling (based on example in example.c) */
55 
56 static char errStr[JMSG_LENGTH_MAX]="No error";
57 
58 struct my_error_mgr
59 {
60 	struct jpeg_error_mgr pub;
61 	jmp_buf setjmp_buffer;
62 	void (*emit_message)(j_common_ptr, int);
63 	boolean warning;
64 };
65 typedef struct my_error_mgr *my_error_ptr;
66 
my_error_exit(j_common_ptr cinfo)67 static void my_error_exit(j_common_ptr cinfo)
68 {
69 	my_error_ptr myerr=(my_error_ptr)cinfo->err;
70 	(*cinfo->err->output_message)(cinfo);
71 	longjmp(myerr->setjmp_buffer, 1);
72 }
73 
74 /* Based on output_message() in jerror.c */
75 
my_output_message(j_common_ptr cinfo)76 static void my_output_message(j_common_ptr cinfo)
77 {
78 	(*cinfo->err->format_message)(cinfo, errStr);
79 }
80 
my_emit_message(j_common_ptr cinfo,int msg_level)81 static void my_emit_message(j_common_ptr cinfo, int msg_level)
82 {
83 	my_error_ptr myerr=(my_error_ptr)cinfo->err;
84 	myerr->emit_message(cinfo, msg_level);
85 	if(msg_level<0) myerr->warning=TRUE;
86 }
87 
88 
89 /* Global structures, macros, etc. */
90 
91 enum {COMPRESS=1, DECOMPRESS=2};
92 
93 typedef struct _tjinstance
94 {
95 	struct jpeg_compress_struct cinfo;
96 	struct jpeg_decompress_struct dinfo;
97 	struct my_error_mgr jerr;
98 	int init, headerRead;
99 } tjinstance;
100 
101 static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3};
102 
103 static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
104 {
105 	JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
106 	JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
107 };
108 
109 #define NUMSF 16
110 static const tjscalingfactor sf[NUMSF]={
111 	{2, 1},
112 	{15, 8},
113 	{7, 4},
114 	{13, 8},
115 	{3, 2},
116 	{11, 8},
117 	{5, 4},
118 	{9, 8},
119 	{1, 1},
120 	{7, 8},
121 	{3, 4},
122 	{5, 8},
123 	{1, 2},
124 	{3, 8},
125 	{1, 4},
126 	{1, 8}
127 };
128 
129 #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
130 	retval=-1;  goto bailout;}
131 #define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
132 	j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
133 	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
134 		return -1;}  \
135 	cinfo=&this->cinfo;  dinfo=&this->dinfo;  \
136 	this->jerr.warning=FALSE;
137 #define getcinstance(handle) tjinstance *this=(tjinstance *)handle;  \
138 	j_compress_ptr cinfo=NULL;  \
139 	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
140 		return -1;}  \
141 	cinfo=&this->cinfo;  \
142 	this->jerr.warning=FALSE;
143 #define getdinstance(handle) tjinstance *this=(tjinstance *)handle;  \
144 	j_decompress_ptr dinfo=NULL;  \
145 	if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
146 		return -1;}  \
147 	dinfo=&this->dinfo;  \
148 	this->jerr.warning=FALSE;
149 
getPixelFormat(int pixelSize,int flags)150 static int getPixelFormat(int pixelSize, int flags)
151 {
152 	if(pixelSize==1) return TJPF_GRAY;
153 	if(pixelSize==3)
154 	{
155 		if(flags&TJ_BGR) return TJPF_BGR;
156 		else return TJPF_RGB;
157 	}
158 	if(pixelSize==4)
159 	{
160 		if(flags&TJ_ALPHAFIRST)
161 		{
162 			if(flags&TJ_BGR) return TJPF_XBGR;
163 			else return TJPF_XRGB;
164 		}
165 		else
166 		{
167 			if(flags&TJ_BGR) return TJPF_BGRX;
168 			else return TJPF_RGBX;
169 		}
170 	}
171 	return -1;
172 }
173 
setCompDefaults(struct jpeg_compress_struct * cinfo,int pixelFormat,int subsamp,int jpegQual,int flags)174 static int setCompDefaults(struct jpeg_compress_struct *cinfo,
175 	int pixelFormat, int subsamp, int jpegQual, int flags)
176 {
177 	int retval=0;
178 	char *env=NULL;
179 
180 	switch(pixelFormat)
181 	{
182 		case TJPF_GRAY:
183 			cinfo->in_color_space=JCS_GRAYSCALE;  break;
184 		#if JCS_EXTENSIONS==1
185 		case TJPF_RGB:
186 			cinfo->in_color_space=JCS_EXT_RGB;  break;
187 		case TJPF_BGR:
188 			cinfo->in_color_space=JCS_EXT_BGR;  break;
189 		case TJPF_RGBX:
190 		case TJPF_RGBA:
191 			cinfo->in_color_space=JCS_EXT_RGBX;  break;
192 		case TJPF_BGRX:
193 		case TJPF_BGRA:
194 			cinfo->in_color_space=JCS_EXT_BGRX;  break;
195 		case TJPF_XRGB:
196 		case TJPF_ARGB:
197 			cinfo->in_color_space=JCS_EXT_XRGB;  break;
198 		case TJPF_XBGR:
199 		case TJPF_ABGR:
200 			cinfo->in_color_space=JCS_EXT_XBGR;  break;
201 		#else
202 		case TJPF_RGB:
203 		case TJPF_BGR:
204 		case TJPF_RGBX:
205 		case TJPF_BGRX:
206 		case TJPF_XRGB:
207 		case TJPF_XBGR:
208 		case TJPF_RGBA:
209 		case TJPF_BGRA:
210 		case TJPF_ARGB:
211 		case TJPF_ABGR:
212 			cinfo->in_color_space=JCS_RGB;  pixelFormat=TJPF_RGB;
213 			break;
214 		#endif
215 		case TJPF_CMYK:
216 			cinfo->in_color_space=JCS_CMYK;  break;
217 	}
218 
219 	cinfo->input_components=tjPixelSize[pixelFormat];
220 	jpeg_set_defaults(cinfo);
221 
222 #ifndef NO_GETENV
223 	if((env=getenv("TJ_OPTIMIZE"))!=NULL && strlen(env)>0 && !strcmp(env, "1"))
224 		cinfo->optimize_coding=TRUE;
225 	if((env=getenv("TJ_ARITHMETIC"))!=NULL && strlen(env)>0	&& !strcmp(env, "1"))
226 		cinfo->arith_code=TRUE;
227 	if((env=getenv("TJ_RESTART"))!=NULL && strlen(env)>0)
228 	{
229 		int temp=-1;  char tempc=0;
230 		if(sscanf(env, "%d%c", &temp, &tempc)>=1 && temp>=0 && temp<=65535)
231 		{
232 			if(toupper(tempc)=='B')
233 			{
234 				cinfo->restart_interval=temp;
235 				cinfo->restart_in_rows=0;
236 			}
237 			else
238 				cinfo->restart_in_rows=temp;
239 		}
240 	}
241 #endif
242 
243 	if(jpegQual>=0)
244 	{
245 		jpeg_set_quality(cinfo, jpegQual, TRUE);
246 		if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
247 		else cinfo->dct_method=JDCT_FASTEST;
248 	}
249 	if(subsamp==TJSAMP_GRAY)
250 		jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
251 	else if(pixelFormat==TJPF_CMYK)
252 		jpeg_set_colorspace(cinfo, JCS_YCCK);
253 	else jpeg_set_colorspace(cinfo, JCS_YCbCr);
254 
255 #ifndef NO_GETENV
256 	if((env=getenv("TJ_PROGRESSIVE"))!=NULL && strlen(env)>0
257 		&& !strcmp(env, "1"))
258 		jpeg_simple_progression(cinfo);
259 #endif
260 
261 	cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
262 	cinfo->comp_info[1].h_samp_factor=1;
263 	cinfo->comp_info[2].h_samp_factor=1;
264 	if(cinfo->num_components>3)
265 		cinfo->comp_info[3].h_samp_factor=tjMCUWidth[subsamp]/8;
266 	cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
267 	cinfo->comp_info[1].v_samp_factor=1;
268 	cinfo->comp_info[2].v_samp_factor=1;
269 	if(cinfo->num_components>3)
270 		cinfo->comp_info[3].v_samp_factor=tjMCUHeight[subsamp]/8;
271 
272 	return retval;
273 }
274 
setDecompDefaults(struct jpeg_decompress_struct * dinfo,int pixelFormat,int flags)275 static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
276 	int pixelFormat, int flags)
277 {
278 	int retval=0;
279 
280 	switch(pixelFormat)
281 	{
282 		case TJPF_GRAY:
283 			dinfo->out_color_space=JCS_GRAYSCALE;  break;
284 		#if JCS_EXTENSIONS==1
285 		case TJPF_RGB:
286 			dinfo->out_color_space=JCS_EXT_RGB;  break;
287 		case TJPF_BGR:
288 			dinfo->out_color_space=JCS_EXT_BGR;  break;
289 		case TJPF_RGBX:
290 			dinfo->out_color_space=JCS_EXT_RGBX;  break;
291 		case TJPF_BGRX:
292 			dinfo->out_color_space=JCS_EXT_BGRX;  break;
293 		case TJPF_XRGB:
294 			dinfo->out_color_space=JCS_EXT_XRGB;  break;
295 		case TJPF_XBGR:
296 			dinfo->out_color_space=JCS_EXT_XBGR;  break;
297 		#if JCS_ALPHA_EXTENSIONS==1
298 		case TJPF_RGBA:
299 			dinfo->out_color_space=JCS_EXT_RGBA;  break;
300 		case TJPF_BGRA:
301 			dinfo->out_color_space=JCS_EXT_BGRA;  break;
302 		case TJPF_ARGB:
303 			dinfo->out_color_space=JCS_EXT_ARGB;  break;
304 		case TJPF_ABGR:
305 			dinfo->out_color_space=JCS_EXT_ABGR;  break;
306 		#endif
307 		#else
308 		case TJPF_RGB:
309 		case TJPF_BGR:
310 		case TJPF_RGBX:
311 		case TJPF_BGRX:
312 		case TJPF_XRGB:
313 		case TJPF_XBGR:
314 		case TJPF_RGBA:
315 		case TJPF_BGRA:
316 		case TJPF_ARGB:
317 		case TJPF_ABGR:
318 			dinfo->out_color_space=JCS_RGB;  break;
319 		#endif
320 		case TJPF_CMYK:
321 			dinfo->out_color_space=JCS_CMYK;  break;
322 		default:
323 			_throw("Unsupported pixel format");
324 	}
325 
326 	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
327 
328 	bailout:
329 	return retval;
330 }
331 
332 
getSubsamp(j_decompress_ptr dinfo)333 static int getSubsamp(j_decompress_ptr dinfo)
334 {
335 	int retval=-1, i, k;
336 
337 	/* The sampling factors actually have no meaning with grayscale JPEG files,
338 	   and in fact it's possible to generate grayscale JPEGs with sampling
339 	   factors > 1 (even though those sampling factors are ignored by the
340 	   decompressor.)  Thus, we need to treat grayscale as a special case. */
341 	if(dinfo->num_components==1 && dinfo->jpeg_color_space==JCS_GRAYSCALE)
342 		return TJSAMP_GRAY;
343 
344 	for(i=0; i<NUMSUBOPT; i++)
345 	{
346 		if(dinfo->num_components==pixelsize[i]
347 			|| ((dinfo->jpeg_color_space==JCS_YCCK
348 				|| dinfo->jpeg_color_space==JCS_CMYK)
349 					&& pixelsize[i]==3 && dinfo->num_components==4))
350 		{
351 			if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
352 				&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
353 			{
354 				int match=0;
355 				for(k=1; k<dinfo->num_components; k++)
356 				{
357 					int href=1, vref=1;
358 					if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
359 					{
360 						href=tjMCUWidth[i]/8;  vref=tjMCUHeight[i]/8;
361 					}
362 					if(dinfo->comp_info[k].h_samp_factor==href
363 						&& dinfo->comp_info[k].v_samp_factor==vref)
364 						match++;
365 				}
366 				if(match==dinfo->num_components-1)
367 				{
368 					retval=i;  break;
369 				}
370 			}
371 			/* Handle 4:2:2 and 4:4:0 images whose sampling factors are specified
372 			   in non-standard ways. */
373 			if(dinfo->comp_info[0].h_samp_factor==2 &&
374 				dinfo->comp_info[0].v_samp_factor==2 &&
375 				(i==TJSAMP_422 || i==TJSAMP_440))
376 			{
377 				int match=0;
378 				for(k=1; k<dinfo->num_components; k++)
379 				{
380 					int href=tjMCUHeight[i]/8, vref=tjMCUWidth[i]/8;
381 					if(dinfo->jpeg_color_space==JCS_YCCK && k==3)
382 					{
383 						href=vref=2;
384 					}
385 					if(dinfo->comp_info[k].h_samp_factor==href
386 						&& dinfo->comp_info[k].v_samp_factor==vref)
387 						match++;
388 				}
389 				if(match==dinfo->num_components-1)
390 				{
391 					retval=i;  break;
392 				}
393 			}
394 		}
395 	}
396 	return retval;
397 }
398 
399 
400 #ifndef JCS_EXTENSIONS
401 
402 /* Conversion functions to emulate the colorspace extensions.  This allows the
403    TurboJPEG wrapper to be used with libjpeg */
404 
405 #define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
406 	int rowPad=pitch-width*PS;  \
407 	while(height--)  \
408 	{  \
409 		unsigned char *endOfRow=src+width*PS;  \
410 		while(src<endOfRow)  \
411 		{  \
412 			dst[RGB_RED]=src[ROFFSET];  \
413 			dst[RGB_GREEN]=src[GOFFSET];  \
414 			dst[RGB_BLUE]=src[BOFFSET];  \
415 			dst+=RGB_PIXELSIZE;  src+=PS;  \
416 		}  \
417 		src+=rowPad;  \
418 	}  \
419 }
420 
toRGB(unsigned char * src,int width,int pitch,int height,int pixelFormat,unsigned char * dst)421 static unsigned char *toRGB(unsigned char *src, int width, int pitch,
422 	int height, int pixelFormat, unsigned char *dst)
423 {
424 	unsigned char *retval=src;
425 	switch(pixelFormat)
426 	{
427 		case TJPF_RGB:
428 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
429 			retval=dst;  TORGB(3, 0, 1, 2);
430 			#endif
431 			break;
432 		case TJPF_BGR:
433 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
434 			retval=dst;  TORGB(3, 2, 1, 0);
435 			#endif
436 			break;
437 		case TJPF_RGBX:
438 		case TJPF_RGBA:
439 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
440 			retval=dst;  TORGB(4, 0, 1, 2);
441 			#endif
442 			break;
443 		case TJPF_BGRX:
444 		case TJPF_BGRA:
445 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
446 			retval=dst;  TORGB(4, 2, 1, 0);
447 			#endif
448 			break;
449 		case TJPF_XRGB:
450 		case TJPF_ARGB:
451 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
452 			retval=dst;  TORGB(4, 1, 2, 3);
453 			#endif
454 			break;
455 		case TJPF_XBGR:
456 		case TJPF_ABGR:
457 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
458 			retval=dst;  TORGB(4, 3, 2, 1);
459 			#endif
460 			break;
461 	}
462 	return retval;
463 }
464 
465 #define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) {  \
466 	int rowPad=pitch-width*PS;  \
467 	while(height--)  \
468 	{  \
469 		unsigned char *endOfRow=dst+width*PS;  \
470 		while(dst<endOfRow)  \
471 		{  \
472 			dst[ROFFSET]=src[RGB_RED];  \
473 			dst[GOFFSET]=src[RGB_GREEN];  \
474 			dst[BOFFSET]=src[RGB_BLUE];  \
475 			SETALPHA  \
476 			dst+=PS;  src+=RGB_PIXELSIZE;  \
477 		}  \
478 		dst+=rowPad;  \
479 	}  \
480 }
481 
fromRGB(unsigned char * src,unsigned char * dst,int width,int pitch,int height,int pixelFormat)482 static void fromRGB(unsigned char *src, unsigned char *dst, int width,
483 	int pitch, int height, int pixelFormat)
484 {
485 	switch(pixelFormat)
486 	{
487 		case TJPF_RGB:
488 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
489 			FROMRGB(3, 0, 1, 2,);
490 			#endif
491 			break;
492 		case TJPF_BGR:
493 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
494 			FROMRGB(3, 2, 1, 0,);
495 			#endif
496 			break;
497 		case TJPF_RGBX:
498 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
499 			FROMRGB(4, 0, 1, 2,);
500 			#endif
501 			break;
502 		case TJPF_RGBA:
503 			#if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
504 			FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
505 			#endif
506 			break;
507 		case TJPF_BGRX:
508 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
509 			FROMRGB(4, 2, 1, 0,);
510 			#endif
511 			break;
512 		case TJPF_BGRA:
513 			#if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
514 			FROMRGB(4, 2, 1, 0, dst[3]=0xFF;);  return;
515 			#endif
516 			break;
517 		case TJPF_XRGB:
518 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
519 			FROMRGB(4, 1, 2, 3,);  return;
520 			#endif
521 			break;
522 		case TJPF_ARGB:
523 			#if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
524 			FROMRGB(4, 1, 2, 3, dst[0]=0xFF;);  return;
525 			#endif
526 			break;
527 		case TJPF_XBGR:
528 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
529 			FROMRGB(4, 3, 2, 1,);  return;
530 			#endif
531 			break;
532 		case TJPF_ABGR:
533 			#if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
534 			FROMRGB(4, 3, 2, 1, dst[0]=0xFF;);  return;
535 			#endif
536 			break;
537 	}
538 }
539 
540 #endif
541 
542 
543 /* General API functions */
544 
tjGetErrorStr(void)545 DLLEXPORT char* DLLCALL tjGetErrorStr(void)
546 {
547 	return errStr;
548 }
549 
550 
tjDestroy(tjhandle handle)551 DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
552 {
553 	getinstance(handle);
554 	if(setjmp(this->jerr.setjmp_buffer)) return -1;
555 	if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
556 	if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
557 	free(this);
558 	return 0;
559 }
560 
561 
562 /* These are exposed mainly because Windows can't malloc() and free() across
563    DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
564    with turbojpeg.dll for compatibility reasons.  However, these functions
565    can potentially be used for other purposes by different implementations. */
566 
tjFree(unsigned char * buf)567 DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
568 {
569 	if(buf) free(buf);
570 }
571 
572 
tjAlloc(int bytes)573 DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
574 {
575 	return (unsigned char *)malloc(bytes);
576 }
577 
578 
579 /* Compressor  */
580 
_tjInitCompress(tjinstance * this)581 static tjhandle _tjInitCompress(tjinstance *this)
582 {
583 	static unsigned char buffer[1];
584 	unsigned char *buf=buffer;  unsigned long size=1;
585 
586 	/* This is also straight out of example.c */
587 	this->cinfo.err=jpeg_std_error(&this->jerr.pub);
588 	this->jerr.pub.error_exit=my_error_exit;
589 	this->jerr.pub.output_message=my_output_message;
590 	this->jerr.emit_message=this->jerr.pub.emit_message;
591 	this->jerr.pub.emit_message=my_emit_message;
592 
593 	if(setjmp(this->jerr.setjmp_buffer))
594 	{
595 		/* If we get here, the JPEG code has signaled an error. */
596 		if(this) free(this);
597 		return NULL;
598 	}
599 
600 	jpeg_create_compress(&this->cinfo);
601 	/* Make an initial call so it will create the destination manager */
602 	jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
603 
604 	this->init|=COMPRESS;
605 	return (tjhandle)this;
606 }
607 
tjInitCompress(void)608 DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
609 {
610 	tjinstance *this=NULL;
611 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
612 	{
613 		snprintf(errStr, JMSG_LENGTH_MAX,
614 			"tjInitCompress(): Memory allocation failure");
615 		return NULL;
616 	}
617 	MEMZERO(this, sizeof(tjinstance));
618 	return _tjInitCompress(this);
619 }
620 
621 
tjBufSize(int width,int height,int jpegSubsamp)622 DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
623 	int jpegSubsamp)
624 {
625 	unsigned long retval=0;  int mcuw, mcuh, chromasf;
626 	if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
627 		_throw("tjBufSize(): Invalid argument");
628 
629 	/* This allows for rare corner cases in which a JPEG image can actually be
630 	   larger than the uncompressed input (we wouldn't mention it if it hadn't
631 	   happened before.) */
632 	mcuw=tjMCUWidth[jpegSubsamp];
633 	mcuh=tjMCUHeight[jpegSubsamp];
634 	chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
635 	retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
636 
637 	bailout:
638 	return retval;
639 }
640 
TJBUFSIZE(int width,int height)641 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
642 {
643 	unsigned long retval=0;
644 	if(width<1 || height<1)
645 		_throw("TJBUFSIZE(): Invalid argument");
646 
647 	/* This allows for rare corner cases in which a JPEG image can actually be
648 	   larger than the uncompressed input (we wouldn't mention it if it hadn't
649 	   happened before.) */
650 	retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
651 
652 	bailout:
653 	return retval;
654 }
655 
656 
tjBufSizeYUV2(int width,int pad,int height,int subsamp)657 DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height,
658 	int subsamp)
659 {
660 	int retval=0, nc, i;
661 
662 	if(subsamp<0 || subsamp>=NUMSUBOPT)
663 		_throw("tjBufSizeYUV2(): Invalid argument");
664 
665 	nc=(subsamp==TJSAMP_GRAY? 1:3);
666 	for(i=0; i<nc; i++)
667 	{
668 		int pw=tjPlaneWidth(i, width, subsamp);
669 		int stride=PAD(pw, pad);
670 		int ph=tjPlaneHeight(i, height, subsamp);
671 		if(pw<0 || ph<0) return -1;
672 		else retval+=stride*ph;
673 	}
674 
675 	bailout:
676 	return retval;
677 }
678 
tjBufSizeYUV(int width,int height,int subsamp)679 DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
680 	int subsamp)
681 {
682 	return tjBufSizeYUV2(width, 4, height, subsamp);
683 }
684 
TJBUFSIZEYUV(int width,int height,int subsamp)685 DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
686 	int subsamp)
687 {
688 	return tjBufSizeYUV(width, height, subsamp);
689 }
690 
691 
tjPlaneWidth(int componentID,int width,int subsamp)692 DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
693 {
694 	int pw, nc, retval=0;
695 
696 	if(width<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
697 		_throw("tjPlaneWidth(): Invalid argument");
698 	nc=(subsamp==TJSAMP_GRAY? 1:3);
699 	if(componentID<0 || componentID>=nc)
700 		_throw("tjPlaneWidth(): Invalid argument");
701 
702 	pw=PAD(width, tjMCUWidth[subsamp]/8);
703 	if(componentID==0)
704 		retval=pw;
705 	else
706 		retval=pw*8/tjMCUWidth[subsamp];
707 
708 	bailout:
709 	return retval;
710 }
711 
712 
tjPlaneHeight(int componentID,int height,int subsamp)713 DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
714 {
715 	int ph, nc, retval=0;
716 
717 	if(height<1 || subsamp<0 || subsamp>=TJ_NUMSAMP)
718 		_throw("tjPlaneHeight(): Invalid argument");
719 	nc=(subsamp==TJSAMP_GRAY? 1:3);
720 	if(componentID<0 || componentID>=nc)
721 		_throw("tjPlaneHeight(): Invalid argument");
722 
723 	ph=PAD(height, tjMCUHeight[subsamp]/8);
724 	if(componentID==0)
725 		retval=ph;
726 	else
727 		retval=ph*8/tjMCUHeight[subsamp];
728 
729 	bailout:
730 	return retval;
731 }
732 
733 
tjPlaneSizeYUV(int componentID,int width,int stride,int height,int subsamp)734 DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width,
735 	int stride, int height, int subsamp)
736 {
737 	unsigned long retval=0;
738 	int pw, ph;
739 
740 	if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
741 		_throw("tjPlaneSizeYUV(): Invalid argument");
742 
743 	pw=tjPlaneWidth(componentID, width, subsamp);
744 	ph=tjPlaneHeight(componentID, height, subsamp);
745 	if(pw<0 || ph<0) return -1;
746 
747 	if(stride==0) stride=pw;
748 	else stride=abs(stride);
749 
750 	retval=stride*(ph-1)+pw;
751 
752 	bailout:
753 	return retval;
754 }
755 
756 
tjCompress2(tjhandle handle,const unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char ** jpegBuf,unsigned long * jpegSize,int jpegSubsamp,int jpegQual,int flags)757 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, const unsigned char *srcBuf,
758 	int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
759 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
760 {
761 	int i, retval=0, alloc=1;  JSAMPROW *row_pointer=NULL;
762 	#ifndef JCS_EXTENSIONS
763 	unsigned char *rgbBuf=NULL;
764 	#endif
765 
766 	getcinstance(handle)
767 	if((this->init&COMPRESS)==0)
768 		_throw("tjCompress2(): Instance has not been initialized for compression");
769 
770 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
771 		|| pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
772 		|| jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
773 		_throw("tjCompress2(): Invalid argument");
774 
775 	if(setjmp(this->jerr.setjmp_buffer))
776 	{
777 		/* If we get here, the JPEG code has signaled an error. */
778 		retval=-1;
779 		goto bailout;
780 	}
781 
782 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
783 
784 	#ifndef JCS_EXTENSIONS
785 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
786 	{
787 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
788 		if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
789 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
790 		pitch=width*RGB_PIXELSIZE;
791 	}
792 	#endif
793 
794 	cinfo->image_width=width;
795 	cinfo->image_height=height;
796 
797 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
798 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
799 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
800 
801 	if(flags&TJFLAG_NOREALLOC)
802 	{
803 		alloc=0;  *jpegSize=tjBufSize(width, height, jpegSubsamp);
804 	}
805 	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
806 	if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
807 		return -1;
808 
809 	jpeg_start_compress(cinfo, TRUE);
810 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
811 		_throw("tjCompress2(): Memory allocation failure");
812 	for(i=0; i<height; i++)
813 	{
814 		if(flags&TJFLAG_BOTTOMUP)
815 			row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
816 		else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
817 	}
818 	while(cinfo->next_scanline<cinfo->image_height)
819 	{
820 		jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
821 			cinfo->image_height-cinfo->next_scanline);
822 	}
823 	jpeg_finish_compress(cinfo);
824 
825 	bailout:
826 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
827 	#ifndef JCS_EXTENSIONS
828 	if(rgbBuf) free(rgbBuf);
829 	#endif
830 	if(row_pointer) free(row_pointer);
831 	if(this->jerr.warning) retval=-1;
832 	return retval;
833 }
834 
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)835 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
836 	int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
837 	unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
838 {
839 	int retval=0;  unsigned long size;
840 	if(flags&TJ_YUV)
841 	{
842 		size=tjBufSizeYUV(width, height, jpegSubsamp);
843 		retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
844 			getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
845 	}
846 	else
847 	{
848 		retval=tjCompress2(handle, srcBuf, width, pitch, height,
849 			getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
850 			flags|TJFLAG_NOREALLOC);
851 	}
852 	*jpegSize=size;
853 	return retval;
854 }
855 
856 
tjEncodeYUVPlanes(tjhandle handle,const unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char ** dstPlanes,int * strides,int subsamp,int flags)857 DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
858 	const unsigned char *srcBuf, int width, int pitch, int height,
859 	int pixelFormat, unsigned char **dstPlanes, int *strides, int subsamp,
860 	int flags)
861 {
862 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
863 	JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
864 	JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
865 	JSAMPROW *outbuf[MAX_COMPONENTS];
866 	int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
867 	JSAMPLE *ptr;
868 	jpeg_component_info *compptr;
869 	#ifndef JCS_EXTENSIONS
870 	unsigned char *rgbBuf=NULL;
871 	#endif
872 
873 	getcinstance(handle);
874 
875 	for(i=0; i<MAX_COMPONENTS; i++)
876 	{
877 		tmpbuf[i]=NULL;  _tmpbuf[i]=NULL;
878 		tmpbuf2[i]=NULL;  _tmpbuf2[i]=NULL;  outbuf[i]=NULL;
879 	}
880 
881 	if((this->init&COMPRESS)==0)
882 		_throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
883 
884 	if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
885 		|| pixelFormat>=TJ_NUMPF || !dstPlanes || !dstPlanes[0] || subsamp<0
886 		|| subsamp>=NUMSUBOPT)
887 		_throw("tjEncodeYUVPlanes(): Invalid argument");
888 	if(subsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
889 		_throw("tjEncodeYUVPlanes(): Invalid argument");
890 
891 	if(setjmp(this->jerr.setjmp_buffer))
892 	{
893 		/* If we get here, the JPEG code has signaled an error. */
894 		retval=-1;
895 		goto bailout;
896 	}
897 
898 	if(pixelFormat==TJPF_CMYK)
899 		_throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
900 
901 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
902 
903 	#ifndef JCS_EXTENSIONS
904 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
905 	{
906 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
907 		if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
908 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
909 		pitch=width*RGB_PIXELSIZE;
910 	}
911 	#endif
912 
913 	cinfo->image_width=width;
914 	cinfo->image_height=height;
915 
916 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
917 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
918 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
919 
920 	if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
921 
922 	/* Execute only the parts of jpeg_start_compress() that we need.  If we
923 	   were to call the whole jpeg_start_compress() function, then it would try
924 	   to write the file headers, which could overflow the output buffer if the
925 	   YUV image were very small. */
926 	if(cinfo->global_state!=CSTATE_START)
927 		_throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
928 	(*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
929 	jinit_c_master_control(cinfo, FALSE);
930 	jinit_color_converter(cinfo);
931 	jinit_downsampler(cinfo);
932 	(*cinfo->cconvert->start_pass)(cinfo);
933 
934 	pw0=PAD(width, cinfo->max_h_samp_factor);
935 	ph0=PAD(height, cinfo->max_v_samp_factor);
936 
937 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
938 		_throw("tjEncodeYUVPlanes(): Memory allocation failure");
939 	for(i=0; i<height; i++)
940 	{
941 		if(flags&TJFLAG_BOTTOMUP)
942 			row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
943 		else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
944 	}
945 	if(height<ph0)
946 		for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
947 
948 	for(i=0; i<cinfo->num_components; i++)
949 	{
950 		compptr=&cinfo->comp_info[i];
951 		_tmpbuf[i]=(JSAMPLE *)malloc(
952 			PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
953 				/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
954 		if(!_tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
955 		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
956 		if(!tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
957 		for(row=0; row<cinfo->max_v_samp_factor; row++)
958 		{
959 			unsigned char *_tmpbuf_aligned=
960 				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
961 			tmpbuf[i][row]=&_tmpbuf_aligned[
962 				PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
963 					/compptr->h_samp_factor, 16) * row];
964 		}
965 		_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
966 			* compptr->v_samp_factor + 16);
967 		if(!_tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
968 		tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
969 		if(!tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
970 		for(row=0; row<compptr->v_samp_factor; row++)
971 		{
972 			unsigned char *_tmpbuf2_aligned=
973 				(unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
974 			tmpbuf2[i][row]=&_tmpbuf2_aligned[
975 				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
976 		}
977 		pw[i]=pw0*compptr->h_samp_factor/cinfo->max_h_samp_factor;
978 		ph[i]=ph0*compptr->v_samp_factor/cinfo->max_v_samp_factor;
979 		outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
980 		if(!outbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
981 		ptr=dstPlanes[i];
982 		for(row=0; row<ph[i]; row++)
983 		{
984 			outbuf[i][row]=ptr;
985 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
986 		}
987 	}
988 
989 	for(row=0; row<ph0; row+=cinfo->max_v_samp_factor)
990 	{
991 		(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
992 			cinfo->max_v_samp_factor);
993 		(cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
994 		for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
995 			jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
996 				row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
997 				compptr->v_samp_factor, pw[i]);
998 	}
999 	cinfo->next_scanline+=height;
1000 	jpeg_abort_compress(cinfo);
1001 
1002 	bailout:
1003 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1004 	#ifndef JCS_EXTENSIONS
1005 	if(rgbBuf) free(rgbBuf);
1006 	#endif
1007 	if(row_pointer) free(row_pointer);
1008 	for(i=0; i<MAX_COMPONENTS; i++)
1009 	{
1010 		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
1011 		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
1012 		if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
1013 		if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
1014 		if(outbuf[i]!=NULL) free(outbuf[i]);
1015 	}
1016 	if(this->jerr.warning) retval=-1;
1017 	return retval;
1018 }
1019 
tjEncodeYUV3(tjhandle handle,const unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char * dstBuf,int pad,int subsamp,int flags)1020 DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle,
1021 	const unsigned char *srcBuf, int width, int pitch, int height,
1022 	int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags)
1023 {
1024 	unsigned char *dstPlanes[3];
1025 	int pw0, ph0, strides[3], retval=-1;
1026 
1027 	if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad)
1028 		|| subsamp<0 || subsamp>=NUMSUBOPT)
1029 		_throw("tjEncodeYUV3(): Invalid argument");
1030 
1031 	pw0=tjPlaneWidth(0, width, subsamp);
1032 	ph0=tjPlaneHeight(0, height, subsamp);
1033 	dstPlanes[0]=dstBuf;
1034 	strides[0]=PAD(pw0, pad);
1035 	if(subsamp==TJSAMP_GRAY)
1036 	{
1037 		strides[1]=strides[2]=0;
1038 		dstPlanes[1]=dstPlanes[2]=NULL;
1039 	}
1040 	else
1041 	{
1042 		int pw1=tjPlaneWidth(1, width, subsamp);
1043 		int ph1=tjPlaneHeight(1, height, subsamp);
1044 		strides[1]=strides[2]=PAD(pw1, pad);
1045 		dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1046 		dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1047 	}
1048 
1049 	return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
1050 		dstPlanes, strides, subsamp, flags);
1051 
1052 	bailout:
1053 	return retval;
1054 }
1055 
tjEncodeYUV2(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char * dstBuf,int subsamp,int flags)1056 DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
1057 	int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
1058 	int subsamp, int flags)
1059 {
1060 	return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1061 		dstBuf, 4, subsamp, flags);
1062 }
1063 
tjEncodeYUV(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelSize,unsigned char * dstBuf,int subsamp,int flags)1064 DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
1065 	int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
1066 	int subsamp, int flags)
1067 {
1068 	return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1069 		getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
1070 }
1071 
1072 
tjCompressFromYUVPlanes(tjhandle handle,const unsigned char ** srcPlanes,int width,const int * strides,int height,int subsamp,unsigned char ** jpegBuf,unsigned long * jpegSize,int jpegQual,int flags)1073 DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
1074 	const unsigned char **srcPlanes, int width, const int *strides, int height,
1075 	int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual,
1076 	int flags)
1077 {
1078 	int i, row, retval=0, alloc=1;  JSAMPROW *inbuf[MAX_COMPONENTS];
1079 	int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1080 		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1081 	JSAMPLE *_tmpbuf=NULL, *ptr;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
1082 
1083 	getcinstance(handle)
1084 
1085 	for(i=0; i<MAX_COMPONENTS; i++)
1086 	{
1087 		tmpbuf[i]=NULL;  inbuf[i]=NULL;
1088 	}
1089 
1090 	if((this->init&COMPRESS)==0)
1091 		_throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
1092 
1093 	if(!srcPlanes || !srcPlanes[0] || width<=0 || height<=0 || subsamp<0
1094 		|| subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
1095 		|| jpegQual>100)
1096 		_throw("tjCompressFromYUVPlanes(): Invalid argument");
1097 	if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1098 		_throw("tjCompressFromYUVPlanes(): Invalid argument");
1099 
1100 	if(setjmp(this->jerr.setjmp_buffer))
1101 	{
1102 		/* If we get here, the JPEG code has signaled an error. */
1103 		retval=-1;
1104 		goto bailout;
1105 	}
1106 
1107 	cinfo->image_width=width;
1108 	cinfo->image_height=height;
1109 
1110 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1111 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1112 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1113 
1114 	if(flags&TJFLAG_NOREALLOC)
1115 	{
1116 		alloc=0;  *jpegSize=tjBufSize(width, height, subsamp);
1117 	}
1118 	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1119 	if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
1120 		return -1;
1121 	cinfo->raw_data_in=TRUE;
1122 
1123 	jpeg_start_compress(cinfo, TRUE);
1124 	for(i=0; i<cinfo->num_components; i++)
1125 	{
1126 		jpeg_component_info *compptr=&cinfo->comp_info[i];
1127 		int ih;
1128 		iw[i]=compptr->width_in_blocks*DCTSIZE;
1129 		ih=compptr->height_in_blocks*DCTSIZE;
1130 		pw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
1131 			*compptr->h_samp_factor/cinfo->max_h_samp_factor;
1132 		ph[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
1133 			*compptr->v_samp_factor/cinfo->max_v_samp_factor;
1134 		if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
1135 		th[i]=compptr->v_samp_factor*DCTSIZE;
1136 		tmpbufsize+=iw[i]*th[i];
1137 		if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
1138 			_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1139 		ptr=(JSAMPLE *)srcPlanes[i];
1140 		for(row=0; row<ph[i]; row++)
1141 		{
1142 			inbuf[i][row]=ptr;
1143 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
1144 		}
1145 	}
1146 	if(usetmpbuf)
1147 	{
1148 		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1149 			_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1150 		ptr=_tmpbuf;
1151 		for(i=0; i<cinfo->num_components; i++)
1152 		{
1153 			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1154 				_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1155 			for(row=0; row<th[i]; row++)
1156 			{
1157 				tmpbuf[i][row]=ptr;
1158 				ptr+=iw[i];
1159 			}
1160 		}
1161 	}
1162 
1163 	for(row=0; row<(int)cinfo->image_height;
1164 		row+=cinfo->max_v_samp_factor*DCTSIZE)
1165 	{
1166 		JSAMPARRAY yuvptr[MAX_COMPONENTS];
1167 		int crow[MAX_COMPONENTS];
1168 		for(i=0; i<cinfo->num_components; i++)
1169 		{
1170 			jpeg_component_info *compptr=&cinfo->comp_info[i];
1171 			crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
1172 			if(usetmpbuf)
1173 			{
1174 				int j, k;
1175 				for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
1176 				{
1177 					memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], pw[i]);
1178 					/* Duplicate last sample in row to fill out MCU */
1179 					for(k=pw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][pw[i]-1];
1180 				}
1181 				/* Duplicate last row to fill out MCU */
1182 				for(j=ph[i]-crow[i]; j<th[i]; j++)
1183 					memcpy(tmpbuf[i][j], tmpbuf[i][ph[i]-crow[i]-1], iw[i]);
1184 				yuvptr[i]=tmpbuf[i];
1185 			}
1186 			else
1187 				yuvptr[i]=&inbuf[i][crow[i]];
1188 		}
1189 		jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
1190 	}
1191 	jpeg_finish_compress(cinfo);
1192 
1193 	bailout:
1194 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1195 	for(i=0; i<MAX_COMPONENTS; i++)
1196 	{
1197 		if(tmpbuf[i]) free(tmpbuf[i]);
1198 		if(inbuf[i]) free(inbuf[i]);
1199 	}
1200 	if(_tmpbuf) free(_tmpbuf);
1201 	if(this->jerr.warning) retval=-1;
1202 	return retval;
1203 }
1204 
tjCompressFromYUV(tjhandle handle,const unsigned char * srcBuf,int width,int pad,int height,int subsamp,unsigned char ** jpegBuf,unsigned long * jpegSize,int jpegQual,int flags)1205 DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle,
1206 	const unsigned char *srcBuf, int width, int pad, int height, int subsamp,
1207 	unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)
1208 {
1209 	const unsigned char *srcPlanes[3];
1210 	int pw0, ph0, strides[3], retval=-1;
1211 
1212 	if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
1213 		|| subsamp>=NUMSUBOPT)
1214 		_throw("tjCompressFromYUV(): Invalid argument");
1215 
1216 	pw0=tjPlaneWidth(0, width, subsamp);
1217 	ph0=tjPlaneHeight(0, height, subsamp);
1218 	srcPlanes[0]=srcBuf;
1219 	strides[0]=PAD(pw0, pad);
1220 	if(subsamp==TJSAMP_GRAY)
1221 	{
1222 		strides[1]=strides[2]=0;
1223 		srcPlanes[1]=srcPlanes[2]=NULL;
1224 	}
1225 	else
1226 	{
1227 		int pw1=tjPlaneWidth(1, width, subsamp);
1228 		int ph1=tjPlaneHeight(1, height, subsamp);
1229 		strides[1]=strides[2]=PAD(pw1, pad);
1230 		srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1231 		srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1232 	}
1233 
1234 	return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1235 		subsamp, jpegBuf, jpegSize, jpegQual, flags);
1236 
1237 	bailout:
1238 	return retval;
1239 }
1240 
1241 
1242 /* Decompressor */
1243 
_tjInitDecompress(tjinstance * this)1244 static tjhandle _tjInitDecompress(tjinstance *this)
1245 {
1246 	static unsigned char buffer[1];
1247 
1248 	/* This is also straight out of example.c */
1249 	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
1250 	this->jerr.pub.error_exit=my_error_exit;
1251 	this->jerr.pub.output_message=my_output_message;
1252 	this->jerr.emit_message=this->jerr.pub.emit_message;
1253 	this->jerr.pub.emit_message=my_emit_message;
1254 
1255 	if(setjmp(this->jerr.setjmp_buffer))
1256 	{
1257 		/* If we get here, the JPEG code has signaled an error. */
1258 		if(this) free(this);
1259 		return NULL;
1260 	}
1261 
1262 	jpeg_create_decompress(&this->dinfo);
1263 	/* Make an initial call so it will create the source manager */
1264 	jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1265 
1266 	this->init|=DECOMPRESS;
1267 	return (tjhandle)this;
1268 }
1269 
tjInitDecompress(void)1270 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
1271 {
1272 	tjinstance *this;
1273 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1274 	{
1275 		snprintf(errStr, JMSG_LENGTH_MAX,
1276 			"tjInitDecompress(): Memory allocation failure");
1277 		return NULL;
1278 	}
1279 	MEMZERO(this, sizeof(tjinstance));
1280 	return _tjInitDecompress(this);
1281 }
1282 
1283 
tjDecompressHeader3(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height,int * jpegSubsamp,int * jpegColorspace)1284 DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
1285 	const unsigned char *jpegBuf, unsigned long jpegSize, int *width,
1286 	int *height, int *jpegSubsamp, int *jpegColorspace)
1287 {
1288 	int retval=0;
1289 
1290 	getdinstance(handle);
1291 	if((this->init&DECOMPRESS)==0)
1292 		_throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
1293 
1294 	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
1295 		|| jpegSubsamp==NULL || jpegColorspace==NULL)
1296 		_throw("tjDecompressHeader3(): Invalid argument");
1297 
1298 	if(setjmp(this->jerr.setjmp_buffer))
1299 	{
1300 		/* If we get here, the JPEG code has signaled an error. */
1301 		return -1;
1302 	}
1303 
1304 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1305 	jpeg_read_header(dinfo, TRUE);
1306 
1307 	*width=dinfo->image_width;
1308 	*height=dinfo->image_height;
1309 	*jpegSubsamp=getSubsamp(dinfo);
1310 	switch(dinfo->jpeg_color_space)
1311 	{
1312 		case JCS_GRAYSCALE:  *jpegColorspace=TJCS_GRAY;  break;
1313 		case JCS_RGB:        *jpegColorspace=TJCS_RGB;  break;
1314 		case JCS_YCbCr:      *jpegColorspace=TJCS_YCbCr;  break;
1315 		case JCS_CMYK:       *jpegColorspace=TJCS_CMYK;  break;
1316 		case JCS_YCCK:       *jpegColorspace=TJCS_YCCK;  break;
1317 		default:             *jpegColorspace=-1;  break;
1318 	}
1319 
1320 	jpeg_abort_decompress(dinfo);
1321 
1322 	if(*jpegSubsamp<0)
1323 		_throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1324 	if(*jpegColorspace<0)
1325 		_throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1326 	if(*width<1 || *height<1)
1327 		_throw("tjDecompressHeader3(): Invalid data returned in header");
1328 
1329 	bailout:
1330 	if(this->jerr.warning) retval=-1;
1331 	return retval;
1332 }
1333 
tjDecompressHeader2(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height,int * jpegSubsamp)1334 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
1335 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
1336 	int *jpegSubsamp)
1337 {
1338 	int jpegColorspace;
1339 	return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1340 		jpegSubsamp, &jpegColorspace);
1341 }
1342 
tjDecompressHeader(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height)1343 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
1344 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
1345 {
1346 	int jpegSubsamp;
1347 	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1348 		&jpegSubsamp);
1349 }
1350 
1351 
tjGetScalingFactors(int * numscalingfactors)1352 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
1353 {
1354 	if(numscalingfactors==NULL)
1355 	{
1356 		snprintf(errStr, JMSG_LENGTH_MAX,
1357 			"tjGetScalingFactors(): Invalid argument");
1358 		return NULL;
1359 	}
1360 
1361 	*numscalingfactors=NUMSF;
1362 	return (tjscalingfactor *)sf;
1363 }
1364 
1365 
tjDecompress2(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)1366 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
1367 	const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1368 	int width, int pitch, int height, int pixelFormat, int flags)
1369 {
1370 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
1371 	int jpegwidth, jpegheight, scaledw, scaledh;
1372 	#ifndef JCS_EXTENSIONS
1373 	unsigned char *rgbBuf=NULL;
1374 	unsigned char *_dstBuf=NULL;  int _pitch=0;
1375 	#endif
1376 
1377 	getdinstance(handle);
1378 	if((this->init&DECOMPRESS)==0)
1379 		_throw("tjDecompress2(): Instance has not been initialized for decompression");
1380 
1381 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
1382 		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
1383 		_throw("tjDecompress2(): Invalid argument");
1384 
1385 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1386 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1387 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1388 
1389 	if(setjmp(this->jerr.setjmp_buffer))
1390 	{
1391 		/* If we get here, the JPEG code has signaled an error. */
1392 		retval=-1;
1393 		goto bailout;
1394 	}
1395 
1396 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1397 	jpeg_read_header(dinfo, TRUE);
1398 	if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
1399 	{
1400 		retval=-1;  goto bailout;
1401 	}
1402 
1403 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1404 
1405 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
1406 	if(width==0) width=jpegwidth;
1407 	if(height==0) height=jpegheight;
1408 	for(i=0; i<NUMSF; i++)
1409 	{
1410 		scaledw=TJSCALED(jpegwidth, sf[i]);
1411 		scaledh=TJSCALED(jpegheight, sf[i]);
1412 		if(scaledw<=width && scaledh<=height)
1413 			break;
1414 	}
1415 	if(i>=NUMSF)
1416 		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
1417 	width=scaledw;  height=scaledh;
1418 	dinfo->scale_num=sf[i].num;
1419 	dinfo->scale_denom=sf[i].denom;
1420 
1421 	jpeg_start_decompress(dinfo);
1422 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1423 
1424 	#ifndef JCS_EXTENSIONS
1425 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
1426 		(RGB_RED!=tjRedOffset[pixelFormat] ||
1427 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1428 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1429 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1430 	{
1431 		rgbBuf=(unsigned char *)malloc(width*height*3);
1432 		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1433 		_pitch=pitch;  pitch=width*3;
1434 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
1435 	}
1436 	#endif
1437 
1438 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1439 		*dinfo->output_height))==NULL)
1440 		_throw("tjDecompress2(): Memory allocation failure");
1441 	for(i=0; i<(int)dinfo->output_height; i++)
1442 	{
1443 		if(flags&TJFLAG_BOTTOMUP)
1444 			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1445 		else row_pointer[i]=&dstBuf[i*pitch];
1446 	}
1447 	while(dinfo->output_scanline<dinfo->output_height)
1448 	{
1449 		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1450 			dinfo->output_height-dinfo->output_scanline);
1451 	}
1452 	jpeg_finish_decompress(dinfo);
1453 
1454 	#ifndef JCS_EXTENSIONS
1455 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1456 	#endif
1457 
1458 	bailout:
1459 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1460 	#ifndef JCS_EXTENSIONS
1461 	if(rgbBuf) free(rgbBuf);
1462 	#endif
1463 	if(row_pointer) free(row_pointer);
1464 	if(this->jerr.warning) retval=-1;
1465 	return retval;
1466 }
1467 
tjDecompress(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelSize,int flags)1468 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1469 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1470 	int height, int pixelSize, int flags)
1471 {
1472 	if(flags&TJ_YUV)
1473 		return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1474 	else
1475 		return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1476 			height, getPixelFormat(pixelSize, flags), flags);
1477 }
1478 
1479 
setDecodeDefaults(struct jpeg_decompress_struct * dinfo,int pixelFormat,int subsamp,int flags)1480 static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1481 	int pixelFormat, int subsamp, int flags)
1482 {
1483 	int i;
1484 
1485 	dinfo->scale_num=dinfo->scale_denom=1;
1486 
1487 	if(subsamp==TJSAMP_GRAY)
1488 	{
1489 		dinfo->num_components=dinfo->comps_in_scan=1;
1490 		dinfo->jpeg_color_space=JCS_GRAYSCALE;
1491 	}
1492 	else
1493 	{
1494 		dinfo->num_components=dinfo->comps_in_scan=3;
1495 		dinfo->jpeg_color_space=JCS_YCbCr;
1496 	}
1497 
1498 	dinfo->comp_info=(jpeg_component_info *)
1499 		(*dinfo->mem->alloc_small)((j_common_ptr)dinfo, JPOOL_IMAGE,
1500 			dinfo->num_components*sizeof(jpeg_component_info));
1501 
1502 	for(i=0; i<dinfo->num_components; i++)
1503 	{
1504 		jpeg_component_info *compptr=&dinfo->comp_info[i];
1505 		compptr->h_samp_factor=(i==0)? tjMCUWidth[subsamp]/8:1;
1506 		compptr->v_samp_factor=(i==0)? tjMCUHeight[subsamp]/8:1;
1507 		compptr->component_index=i;
1508 		compptr->component_id=i+1;
1509 		compptr->quant_tbl_no=compptr->dc_tbl_no=compptr->ac_tbl_no=
1510 			(i==0)? 0:1;
1511 		dinfo->cur_comp_info[i]=compptr;
1512 	}
1513 	dinfo->data_precision=8;
1514 	for(i=0; i<2; i++)
1515 	{
1516 		if(dinfo->quant_tbl_ptrs[i]==NULL)
1517 			dinfo->quant_tbl_ptrs[i]=jpeg_alloc_quant_table((j_common_ptr)dinfo);
1518 	}
1519 
1520 	return 0;
1521 }
1522 
1523 
my_read_markers(j_decompress_ptr dinfo)1524 int my_read_markers(j_decompress_ptr dinfo)
1525 {
1526 	return JPEG_REACHED_SOS;
1527 }
1528 
my_reset_marker_reader(j_decompress_ptr dinfo)1529 void my_reset_marker_reader(j_decompress_ptr dinfo)
1530 {
1531 }
1532 
tjDecodeYUVPlanes(tjhandle handle,const unsigned char ** srcPlanes,const int * strides,int subsamp,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)1533 DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
1534 	const unsigned char **srcPlanes, const int *strides, int subsamp,
1535 	unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat,
1536 	int flags)
1537 {
1538 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
1539 	JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1540 	JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
1541 	int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1542 	JSAMPLE *ptr;
1543 	jpeg_component_info *compptr;
1544 	#ifndef JCS_EXTENSIONS
1545 	unsigned char *rgbBuf=NULL;
1546 	unsigned char *_dstBuf=NULL;  int _pitch=0;
1547 	#endif
1548 	int (*old_read_markers)(j_decompress_ptr);
1549 	void (*old_reset_marker_reader)(j_decompress_ptr);
1550 
1551 	getdinstance(handle);
1552 
1553 	for(i=0; i<MAX_COMPONENTS; i++)
1554 	{
1555 		tmpbuf[i]=NULL;  _tmpbuf[i]=NULL;  inbuf[i]=NULL;
1556 	}
1557 
1558 	if((this->init&DECOMPRESS)==0)
1559 		_throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
1560 
1561 	if(!srcPlanes || !srcPlanes[0] || subsamp<0 || subsamp>=NUMSUBOPT
1562 		|| dstBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
1563 		|| pixelFormat>=TJ_NUMPF)
1564 		_throw("tjDecodeYUVPlanes(): Invalid argument");
1565 	if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1566 		_throw("tjDecodeYUVPlanes(): Invalid argument");
1567 
1568 	if(setjmp(this->jerr.setjmp_buffer))
1569 	{
1570 		/* If we get here, the JPEG code has signaled an error. */
1571 		retval=-1;
1572 		goto bailout;
1573 	}
1574 
1575 	if(pixelFormat==TJPF_CMYK)
1576 		_throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
1577 
1578 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
1579 	dinfo->image_width=width;
1580 	dinfo->image_height=height;
1581 
1582 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1583 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1584 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1585 
1586 	if(setDecodeDefaults(dinfo, pixelFormat, subsamp, flags)==-1)
1587 	{
1588 		retval=-1;  goto bailout;
1589 	}
1590 	old_read_markers=dinfo->marker->read_markers;
1591 	dinfo->marker->read_markers=my_read_markers;
1592 	old_reset_marker_reader=dinfo->marker->reset_marker_reader;
1593 	dinfo->marker->reset_marker_reader=my_reset_marker_reader;
1594 	jpeg_read_header(dinfo, TRUE);
1595 	dinfo->marker->read_markers=old_read_markers;
1596 	dinfo->marker->reset_marker_reader=old_reset_marker_reader;
1597 
1598 	if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
1599 	{
1600 		retval=-1;  goto bailout;
1601 	}
1602 	dinfo->do_fancy_upsampling=FALSE;
1603 	dinfo->Se=DCTSIZE2-1;
1604 	jinit_master_decompress(dinfo);
1605 	(*dinfo->upsample->start_pass)(dinfo);
1606 
1607 	pw0=PAD(width, dinfo->max_h_samp_factor);
1608 	ph0=PAD(height, dinfo->max_v_samp_factor);
1609 
1610 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1611 
1612 	#ifndef JCS_EXTENSIONS
1613 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
1614 		(RGB_RED!=tjRedOffset[pixelFormat] ||
1615 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1616 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1617 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1618 	{
1619 		rgbBuf=(unsigned char *)malloc(width*height*3);
1620 		if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1621 		_pitch=pitch;  pitch=width*3;
1622 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
1623 	}
1624 	#endif
1625 
1626 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
1627 		_throw("tjDecodeYUVPlanes(): Memory allocation failure");
1628 	for(i=0; i<height; i++)
1629 	{
1630 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch];
1631 		else row_pointer[i]=&dstBuf[i*pitch];
1632 	}
1633 	if(height<ph0)
1634 		for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
1635 
1636 	for(i=0; i<dinfo->num_components; i++)
1637 	{
1638 		compptr=&dinfo->comp_info[i];
1639 		_tmpbuf[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
1640 			* compptr->v_samp_factor + 16);
1641 		if(!_tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1642 		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
1643 		if(!tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1644 		for(row=0; row<compptr->v_samp_factor; row++)
1645 		{
1646 			unsigned char *_tmpbuf_aligned=
1647 				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
1648 			tmpbuf[i][row]=&_tmpbuf_aligned[
1649 				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
1650 		}
1651 		pw[i]=pw0*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1652 		ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1653 		inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
1654 		if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1655 		ptr=(JSAMPLE *)srcPlanes[i];
1656 		for(row=0; row<ph[i]; row++)
1657 		{
1658 			inbuf[i][row]=ptr;
1659 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
1660 		}
1661 	}
1662 
1663 	for(row=0; row<ph0; row+=dinfo->max_v_samp_factor)
1664 	{
1665 		JDIMENSION inrow=0, outrow=0;
1666 		for(i=0, compptr=dinfo->comp_info; i<dinfo->num_components; i++, compptr++)
1667 			jcopy_sample_rows(inbuf[i],
1668 				row*compptr->v_samp_factor/dinfo->max_v_samp_factor, tmpbuf[i], 0,
1669 				compptr->v_samp_factor, pw[i]);
1670 		(dinfo->upsample->upsample)(dinfo, tmpbuf, &inrow,
1671 			dinfo->max_v_samp_factor, &row_pointer[row], &outrow,
1672 			dinfo->max_v_samp_factor);
1673 	}
1674 	jpeg_abort_decompress(dinfo);
1675 
1676 	#ifndef JCS_EXTENSIONS
1677 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1678 	#endif
1679 
1680 	bailout:
1681 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1682 	#ifndef JCS_EXTENSIONS
1683 	if(rgbBuf) free(rgbBuf);
1684 	#endif
1685 	if(row_pointer) free(row_pointer);
1686 	for(i=0; i<MAX_COMPONENTS; i++)
1687 	{
1688 		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
1689 		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
1690 		if(inbuf[i]!=NULL) free(inbuf[i]);
1691 	}
1692 	if(this->jerr.warning) retval=-1;
1693 	return retval;
1694 }
1695 
tjDecodeYUV(tjhandle handle,const unsigned char * srcBuf,int pad,int subsamp,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)1696 DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
1697 	int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
1698 	int height, int pixelFormat, int flags)
1699 {
1700 	const unsigned char *srcPlanes[3];
1701 	int pw0, ph0, strides[3], retval=-1;
1702 
1703 	if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
1704 		|| width<=0 || height<=0)
1705 		_throw("tjDecodeYUV(): Invalid argument");
1706 
1707 	pw0=tjPlaneWidth(0, width, subsamp);
1708 	ph0=tjPlaneHeight(0, height, subsamp);
1709 	srcPlanes[0]=srcBuf;
1710 	strides[0]=PAD(pw0, pad);
1711 	if(subsamp==TJSAMP_GRAY)
1712 	{
1713 		strides[1]=strides[2]=0;
1714 		srcPlanes[1]=srcPlanes[2]=NULL;
1715 	}
1716 	else
1717 	{
1718 		int pw1=tjPlaneWidth(1, width, subsamp);
1719 		int ph1=tjPlaneHeight(1, height, subsamp);
1720 		strides[1]=strides[2]=PAD(pw1, pad);
1721 		srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1722 		srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1723 	}
1724 
1725 	return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1726 		pitch, height, pixelFormat, flags);
1727 
1728 	bailout:
1729 	return retval;
1730 }
1731 
tjDecompressToYUVPlanes(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,unsigned char ** dstPlanes,int width,int * strides,int height,int flags)1732 DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
1733 	const unsigned char *jpegBuf, unsigned long jpegSize,
1734 	unsigned char **dstPlanes, int width, int *strides, int height, int flags)
1735 {
1736 	int i, sfi, row, retval=0;  JSAMPROW *outbuf[MAX_COMPONENTS];
1737 	int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
1738 	int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1739 		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1740 	JSAMPLE *_tmpbuf=NULL, *ptr;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
1741 	int dctsize;
1742 
1743 	getdinstance(handle);
1744 
1745 	for(i=0; i<MAX_COMPONENTS; i++)
1746 	{
1747 		tmpbuf[i]=NULL;  outbuf[i]=NULL;
1748 	}
1749 
1750 	if((this->init&DECOMPRESS)==0)
1751 		_throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
1752 
1753 	if(jpegBuf==NULL || jpegSize<=0 || !dstPlanes || !dstPlanes[0] || width<0
1754 		|| height<0)
1755 		_throw("tjDecompressToYUVPlanes(): Invalid argument");
1756 
1757 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1758 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1759 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1760 
1761 	if(setjmp(this->jerr.setjmp_buffer))
1762 	{
1763 		/* If we get here, the JPEG code has signaled an error. */
1764 		retval=-1;
1765 		goto bailout;
1766 	}
1767 
1768 	if(!this->headerRead)
1769 	{
1770 		jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1771 		jpeg_read_header(dinfo, TRUE);
1772 	}
1773 	this->headerRead=0;
1774 	jpegSubsamp=getSubsamp(dinfo);
1775 	if(jpegSubsamp<0)
1776 		_throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1777 
1778 	if(jpegSubsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1779 		_throw("tjDecompressToYUVPlanes(): Invalid argument");
1780 
1781 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
1782 	if(width==0) width=jpegwidth;
1783 	if(height==0) height=jpegheight;
1784 	for(i=0; i<NUMSF; i++)
1785 	{
1786 		scaledw=TJSCALED(jpegwidth, sf[i]);
1787 		scaledh=TJSCALED(jpegheight, sf[i]);
1788 		if(scaledw<=width && scaledh<=height)
1789 			break;
1790 	}
1791 	if(i>=NUMSF)
1792 		_throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
1793 	if(dinfo->num_components>3)
1794 		_throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
1795 
1796 	width=scaledw;  height=scaledh;
1797 	dinfo->scale_num=sf[i].num;
1798 	dinfo->scale_denom=sf[i].denom;
1799 	sfi=i;
1800 	jpeg_calc_output_dimensions(dinfo);
1801 
1802 	dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
1803 
1804 	for(i=0; i<dinfo->num_components; i++)
1805 	{
1806 		jpeg_component_info *compptr=&dinfo->comp_info[i];
1807 		int ih;
1808 		iw[i]=compptr->width_in_blocks*dctsize;
1809 		ih=compptr->height_in_blocks*dctsize;
1810 		pw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
1811 			*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1812 		ph[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
1813 			*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1814 		if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
1815 		th[i]=compptr->v_samp_factor*dctsize;
1816 		tmpbufsize+=iw[i]*th[i];
1817 		if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
1818 			_throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1819 		ptr=dstPlanes[i];
1820 		for(row=0; row<ph[i]; row++)
1821 		{
1822 			outbuf[i][row]=ptr;
1823 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
1824 		}
1825 	}
1826 	if(usetmpbuf)
1827 	{
1828 		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1829 			_throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1830 		ptr=_tmpbuf;
1831 		for(i=0; i<dinfo->num_components; i++)
1832 		{
1833 			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1834 				_throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1835 			for(row=0; row<th[i]; row++)
1836 			{
1837 				tmpbuf[i][row]=ptr;
1838 				ptr+=iw[i];
1839 			}
1840 		}
1841 	}
1842 
1843 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1844 	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
1845 	dinfo->raw_data_out=TRUE;
1846 
1847 	jpeg_start_decompress(dinfo);
1848 	for(row=0; row<(int)dinfo->output_height;
1849 		row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
1850 	{
1851 		JSAMPARRAY yuvptr[MAX_COMPONENTS];
1852 		int crow[MAX_COMPONENTS];
1853 		for(i=0; i<dinfo->num_components; i++)
1854 		{
1855 			jpeg_component_info *compptr=&dinfo->comp_info[i];
1856 			if(jpegSubsamp==TJ_420)
1857 			{
1858 				/* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1859 				   to be clever and use the IDCT to perform upsampling on the U and V
1860 				   planes.  For instance, if the output image is to be scaled by 1/2
1861 				   relative to the JPEG image, then the scaling factor and upsampling
1862 				   effectively cancel each other, so a normal 8x8 IDCT can be used.
1863 				   However, this is not desirable when using the decompress-to-YUV
1864 				   functionality in TurboJPEG, since we want to output the U and V
1865 				   planes in their subsampled form.  Thus, we have to override some
1866 				   internal libjpeg parameters to force it to use the "scaled" IDCT
1867 				   functions on the U and V planes. */
1868 				compptr->_DCT_scaled_size=dctsize;
1869 				compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1870 					sf[sfi].num/sf[sfi].denom*
1871 					compptr->v_samp_factor/dinfo->max_v_samp_factor;
1872 				dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1873 			}
1874 			crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1875 			if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1876 			else yuvptr[i]=&outbuf[i][crow[i]];
1877 		}
1878 		jpeg_read_raw_data(dinfo, yuvptr,
1879 			dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
1880 		if(usetmpbuf)
1881 		{
1882 			int j;
1883 			for(i=0; i<dinfo->num_components; i++)
1884 			{
1885 				for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
1886 				{
1887 					memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], pw[i]);
1888 				}
1889 			}
1890 		}
1891 	}
1892 	jpeg_finish_decompress(dinfo);
1893 
1894 	bailout:
1895 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1896 	for(i=0; i<MAX_COMPONENTS; i++)
1897 	{
1898 		if(tmpbuf[i]) free(tmpbuf[i]);
1899 		if(outbuf[i]) free(outbuf[i]);
1900 	}
1901 	if(_tmpbuf) free(_tmpbuf);
1902 	if(this->jerr.warning) retval=-1;
1903 	return retval;
1904 }
1905 
tjDecompressToYUV2(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pad,int height,int flags)1906 DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
1907 	const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1908 	int width, int pad, int height, int flags)
1909 {
1910 	unsigned char *dstPlanes[3];
1911 	int pw0, ph0, strides[3], retval=-1, jpegSubsamp=-1;
1912 	int i, jpegwidth, jpegheight, scaledw, scaledh;
1913 
1914 	getdinstance(handle);
1915 
1916 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1917 		|| !isPow2(pad) || height<0)
1918 		_throw("tjDecompressToYUV2(): Invalid argument");
1919 
1920 	if(setjmp(this->jerr.setjmp_buffer))
1921 	{
1922 		/* If we get here, the JPEG code has signaled an error. */
1923 		return -1;
1924 	}
1925 
1926 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1927 	jpeg_read_header(dinfo, TRUE);
1928 	jpegSubsamp=getSubsamp(dinfo);
1929 	if(jpegSubsamp<0)
1930 		_throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1931 
1932 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
1933 	if(width==0) width=jpegwidth;
1934 	if(height==0) height=jpegheight;
1935 
1936 	for(i=0; i<NUMSF; i++)
1937 	{
1938 		scaledw=TJSCALED(jpegwidth, sf[i]);
1939 		scaledh=TJSCALED(jpegheight, sf[i]);
1940 		if(scaledw<=width && scaledh<=height)
1941 			break;
1942 	}
1943 	if(i>=NUMSF)
1944 		_throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1945 
1946 	pw0=tjPlaneWidth(0, width, jpegSubsamp);
1947 	ph0=tjPlaneHeight(0, height, jpegSubsamp);
1948 	dstPlanes[0]=dstBuf;
1949 	strides[0]=PAD(pw0, pad);
1950 	if(jpegSubsamp==TJSAMP_GRAY)
1951 	{
1952 		strides[1]=strides[2]=0;
1953 		dstPlanes[1]=dstPlanes[2]=NULL;
1954 	}
1955 	else
1956 	{
1957 		int pw1=tjPlaneWidth(1, width, jpegSubsamp);
1958 		int ph1=tjPlaneHeight(1, height, jpegSubsamp);
1959 		strides[1]=strides[2]=PAD(pw1, pad);
1960 		dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1961 		dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1962 	}
1963 
1964 	this->headerRead=1;
1965 	return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1966 		strides, height, flags);
1967 
1968 	bailout:
1969 	return retval;
1970 
1971 }
1972 
tjDecompressToYUV(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int flags)1973 DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1974 	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1975 	int flags)
1976 {
1977 	return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
1978 }
1979 
1980 
1981 /* Transformer */
1982 
tjInitTransform(void)1983 DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1984 {
1985 	tjinstance *this=NULL;  tjhandle handle=NULL;
1986 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1987 	{
1988 		snprintf(errStr, JMSG_LENGTH_MAX,
1989 			"tjInitTransform(): Memory allocation failure");
1990 		return NULL;
1991 	}
1992 	MEMZERO(this, sizeof(tjinstance));
1993 	handle=_tjInitCompress(this);
1994 	if(!handle) return NULL;
1995 	handle=_tjInitDecompress(this);
1996 	return handle;
1997 }
1998 
1999 
tjTransform(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,int n,unsigned char ** dstBufs,unsigned long * dstSizes,tjtransform * t,int flags)2000 DLLEXPORT int DLLCALL tjTransform(tjhandle handle,
2001 	const unsigned char *jpegBuf, unsigned long jpegSize, int n,
2002 	unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *t, int flags)
2003 {
2004 	jpeg_transform_info *xinfo=NULL;
2005 	jvirt_barray_ptr *srccoefs, *dstcoefs;
2006 	int retval=0, i, jpegSubsamp;
2007 
2008 	getinstance(handle);
2009 	if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
2010 		_throw("tjTransform(): Instance has not been initialized for transformation");
2011 
2012 	if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
2013 		|| t==NULL || flags<0)
2014 		_throw("tjTransform(): Invalid argument");
2015 
2016 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
2017 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
2018 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
2019 
2020 	if(setjmp(this->jerr.setjmp_buffer))
2021 	{
2022 		/* If we get here, the JPEG code has signaled an error. */
2023 		retval=-1;
2024 		goto bailout;
2025 	}
2026 
2027 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2028 
2029 	if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
2030 		==NULL)
2031 		_throw("tjTransform(): Memory allocation failure");
2032 	MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
2033 
2034 	for(i=0; i<n; i++)
2035 	{
2036 		xinfo[i].transform=xformtypes[t[i].op];
2037 		xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
2038 		xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
2039 		xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
2040 		xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
2041 		if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
2042 		else xinfo[i].slow_hflip=0;
2043 
2044 		if(xinfo[i].crop)
2045 		{
2046 			xinfo[i].crop_xoffset=t[i].r.x;  xinfo[i].crop_xoffset_set=JCROP_POS;
2047 			xinfo[i].crop_yoffset=t[i].r.y;  xinfo[i].crop_yoffset_set=JCROP_POS;
2048 			if(t[i].r.w!=0)
2049 			{
2050 				xinfo[i].crop_width=t[i].r.w;  xinfo[i].crop_width_set=JCROP_POS;
2051 			}
2052 			else xinfo[i].crop_width=JCROP_UNSET;
2053 			if(t[i].r.h!=0)
2054 			{
2055 				xinfo[i].crop_height=t[i].r.h;  xinfo[i].crop_height_set=JCROP_POS;
2056 			}
2057 			else xinfo[i].crop_height=JCROP_UNSET;
2058 		}
2059 	}
2060 
2061 	jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
2062 	jpeg_read_header(dinfo, TRUE);
2063 	jpegSubsamp=getSubsamp(dinfo);
2064 	if(jpegSubsamp<0)
2065 		_throw("tjTransform(): Could not determine subsampling type for JPEG image");
2066 
2067 	for(i=0; i<n; i++)
2068 	{
2069 		if(!jtransform_request_workspace(dinfo, &xinfo[i]))
2070 			_throw("tjTransform(): Transform is not perfect");
2071 
2072 		if(xinfo[i].crop)
2073 		{
2074 			if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
2075 				|| (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
2076 			{
2077 				snprintf(errStr, JMSG_LENGTH_MAX,
2078 					"To crop this JPEG image, x must be a multiple of %d\n"
2079 					"and y must be a multiple of %d.\n",
2080 					xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
2081 				retval=-1;  goto bailout;
2082 			}
2083 		}
2084 	}
2085 
2086 	srccoefs=jpeg_read_coefficients(dinfo);
2087 
2088 	for(i=0; i<n; i++)
2089 	{
2090 		int w, h, alloc=1;
2091 		if(!xinfo[i].crop)
2092 		{
2093 			w=dinfo->image_width;  h=dinfo->image_height;
2094 		}
2095 		else
2096 		{
2097 			w=xinfo[i].crop_width;  h=xinfo[i].crop_height;
2098 		}
2099 		if(flags&TJFLAG_NOREALLOC)
2100 		{
2101 			alloc=0;  dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
2102 		}
2103 		if(!(t[i].options&TJXOPT_NOOUTPUT))
2104 			jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2105 		jpeg_copy_critical_parameters(dinfo, cinfo);
2106 		dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
2107 			&xinfo[i]);
2108 		if(!(t[i].options&TJXOPT_NOOUTPUT))
2109 		{
2110 			jpeg_write_coefficients(cinfo, dstcoefs);
2111 			jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
2112 		}
2113 		else jinit_c_master_control(cinfo, TRUE);
2114 		jtransform_execute_transformation(dinfo, cinfo, srccoefs,
2115 			&xinfo[i]);
2116 		if(t[i].customFilter)
2117 		{
2118 			int ci, y;  JDIMENSION by;
2119 			for(ci=0; ci<cinfo->num_components; ci++)
2120 			{
2121 				jpeg_component_info *compptr=&cinfo->comp_info[ci];
2122 				tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2123 					DCTSIZE};
2124 				tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2125 					compptr->height_in_blocks*DCTSIZE};
2126 				for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
2127 				{
2128 					JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
2129 						((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2130 						TRUE);
2131 					for(y=0; y<compptr->v_samp_factor; y++)
2132 					{
2133 						if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
2134 							ci, i, &t[i])==-1)
2135 							_throw("tjTransform(): Error in custom filter");
2136 						arrayRegion.y+=DCTSIZE;
2137 					}
2138 				}
2139 			}
2140 		}
2141 		if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2142 	}
2143 
2144 	jpeg_finish_decompress(dinfo);
2145 
2146 	bailout:
2147 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
2148 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
2149 	if(xinfo) free(xinfo);
2150 	if(this->jerr.warning) retval=-1;
2151 	return retval;
2152 }
2153