1 /*
2  * Copyright (C)2009-2017 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(pitch==0) pitch=width*tjPixelSize[pixelFormat];
776 
777 	#ifndef JCS_EXTENSIONS
778 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
779 	{
780 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
781 		if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
782 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
783 		pitch=width*RGB_PIXELSIZE;
784 	}
785 	#endif
786 
787 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
788 		_throw("tjCompress2(): Memory allocation failure");
789 
790 	if(setjmp(this->jerr.setjmp_buffer))
791 	{
792 		/* If we get here, the JPEG code has signaled an error. */
793 		retval=-1;  goto bailout;
794 	}
795 
796 	cinfo->image_width=width;
797 	cinfo->image_height=height;
798 
799 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
800 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
801 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
802 
803 	if(flags&TJFLAG_NOREALLOC)
804 	{
805 		alloc=0;  *jpegSize=tjBufSize(width, height, jpegSubsamp);
806 	}
807 	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
808 	if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
809 		return -1;
810 
811 	jpeg_start_compress(cinfo, TRUE);
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(pixelFormat==TJPF_CMYK)
892 		_throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
893 
894 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
895 
896 	#ifndef JCS_EXTENSIONS
897 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK)
898 	{
899 		rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
900 		if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
901 		srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
902 		pitch=width*RGB_PIXELSIZE;
903 	}
904 	#endif
905 
906 	if(setjmp(this->jerr.setjmp_buffer))
907 	{
908 		/* If we get here, the JPEG code has signaled an error. */
909 		retval=-1;  goto bailout;
910 	}
911 
912 	cinfo->image_width=width;
913 	cinfo->image_height=height;
914 
915 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
916 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
917 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
918 
919 	if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
920 
921 	/* Execute only the parts of jpeg_start_compress() that we need.  If we
922 	   were to call the whole jpeg_start_compress() function, then it would try
923 	   to write the file headers, which could overflow the output buffer if the
924 	   YUV image were very small. */
925 	if(cinfo->global_state!=CSTATE_START)
926 		_throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
927 	(*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
928 	jinit_c_master_control(cinfo, FALSE);
929 	jinit_color_converter(cinfo);
930 	jinit_downsampler(cinfo);
931 	(*cinfo->cconvert->start_pass)(cinfo);
932 
933 	pw0=PAD(width, cinfo->max_h_samp_factor);
934 	ph0=PAD(height, cinfo->max_v_samp_factor);
935 
936 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
937 		_throw("tjEncodeYUVPlanes(): Memory allocation failure");
938 	for(i=0; i<height; i++)
939 	{
940 		if(flags&TJFLAG_BOTTOMUP)
941 			row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
942 		else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
943 	}
944 	if(height<ph0)
945 		for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
946 
947 	for(i=0; i<cinfo->num_components; i++)
948 	{
949 		compptr=&cinfo->comp_info[i];
950 		_tmpbuf[i]=(JSAMPLE *)malloc(
951 			PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
952 				/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
953 		if(!_tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
954 		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
955 		if(!tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
956 		for(row=0; row<cinfo->max_v_samp_factor; row++)
957 		{
958 			unsigned char *_tmpbuf_aligned=
959 				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
960 			tmpbuf[i][row]=&_tmpbuf_aligned[
961 				PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
962 					/compptr->h_samp_factor, 16) * row];
963 		}
964 		_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
965 			* compptr->v_samp_factor + 16);
966 		if(!_tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
967 		tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
968 		if(!tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
969 		for(row=0; row<compptr->v_samp_factor; row++)
970 		{
971 			unsigned char *_tmpbuf2_aligned=
972 				(unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
973 			tmpbuf2[i][row]=&_tmpbuf2_aligned[
974 				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
975 		}
976 		pw[i]=pw0*compptr->h_samp_factor/cinfo->max_h_samp_factor;
977 		ph[i]=ph0*compptr->v_samp_factor/cinfo->max_v_samp_factor;
978 		outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
979 		if(!outbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure");
980 		ptr=dstPlanes[i];
981 		for(row=0; row<ph[i]; row++)
982 		{
983 			outbuf[i][row]=ptr;
984 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
985 		}
986 	}
987 
988 	if(setjmp(this->jerr.setjmp_buffer))
989 	{
990 		/* If we get here, the JPEG code has signaled an error. */
991 		retval=-1;  goto bailout;
992 	}
993 
994 	for(row=0; row<ph0; row+=cinfo->max_v_samp_factor)
995 	{
996 		(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
997 			cinfo->max_v_samp_factor);
998 		(cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
999 		for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
1000 			jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
1001 				row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
1002 				compptr->v_samp_factor, pw[i]);
1003 	}
1004 	cinfo->next_scanline+=height;
1005 	jpeg_abort_compress(cinfo);
1006 
1007 	bailout:
1008 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1009 	#ifndef JCS_EXTENSIONS
1010 	if(rgbBuf) free(rgbBuf);
1011 	#endif
1012 	if(row_pointer) free(row_pointer);
1013 	for(i=0; i<MAX_COMPONENTS; i++)
1014 	{
1015 		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
1016 		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
1017 		if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
1018 		if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
1019 		if(outbuf[i]!=NULL) free(outbuf[i]);
1020 	}
1021 	if(this->jerr.warning) retval=-1;
1022 	return retval;
1023 }
1024 
tjEncodeYUV3(tjhandle handle,const unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char * dstBuf,int pad,int subsamp,int flags)1025 DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle,
1026 	const unsigned char *srcBuf, int width, int pitch, int height,
1027 	int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags)
1028 {
1029 	unsigned char *dstPlanes[3];
1030 	int pw0, ph0, strides[3], retval=-1;
1031 
1032 	if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad)
1033 		|| subsamp<0 || subsamp>=NUMSUBOPT)
1034 		_throw("tjEncodeYUV3(): Invalid argument");
1035 
1036 	pw0=tjPlaneWidth(0, width, subsamp);
1037 	ph0=tjPlaneHeight(0, height, subsamp);
1038 	dstPlanes[0]=dstBuf;
1039 	strides[0]=PAD(pw0, pad);
1040 	if(subsamp==TJSAMP_GRAY)
1041 	{
1042 		strides[1]=strides[2]=0;
1043 		dstPlanes[1]=dstPlanes[2]=NULL;
1044 	}
1045 	else
1046 	{
1047 		int pw1=tjPlaneWidth(1, width, subsamp);
1048 		int ph1=tjPlaneHeight(1, height, subsamp);
1049 		strides[1]=strides[2]=PAD(pw1, pad);
1050 		dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1051 		dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1052 	}
1053 
1054 	return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
1055 		dstPlanes, strides, subsamp, flags);
1056 
1057 	bailout:
1058 	return retval;
1059 }
1060 
tjEncodeYUV2(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelFormat,unsigned char * dstBuf,int subsamp,int flags)1061 DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
1062 	int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
1063 	int subsamp, int flags)
1064 {
1065 	return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
1066 		dstBuf, 4, subsamp, flags);
1067 }
1068 
tjEncodeYUV(tjhandle handle,unsigned char * srcBuf,int width,int pitch,int height,int pixelSize,unsigned char * dstBuf,int subsamp,int flags)1069 DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
1070 	int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
1071 	int subsamp, int flags)
1072 {
1073 	return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
1074 		getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
1075 }
1076 
1077 
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)1078 DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
1079 	const unsigned char **srcPlanes, int width, const int *strides, int height,
1080 	int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual,
1081 	int flags)
1082 {
1083 	int i, row, retval=0, alloc=1;  JSAMPROW *inbuf[MAX_COMPONENTS];
1084 	int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1085 		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1086 	JSAMPLE *_tmpbuf=NULL, *ptr;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
1087 
1088 	getcinstance(handle)
1089 
1090 	for(i=0; i<MAX_COMPONENTS; i++)
1091 	{
1092 		tmpbuf[i]=NULL;  inbuf[i]=NULL;
1093 	}
1094 
1095 	if((this->init&COMPRESS)==0)
1096 		_throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
1097 
1098 	if(!srcPlanes || !srcPlanes[0] || width<=0 || height<=0 || subsamp<0
1099 		|| subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
1100 		|| jpegQual>100)
1101 		_throw("tjCompressFromYUVPlanes(): Invalid argument");
1102 	if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1103 		_throw("tjCompressFromYUVPlanes(): Invalid argument");
1104 
1105 	if(setjmp(this->jerr.setjmp_buffer))
1106 	{
1107 		/* If we get here, the JPEG code has signaled an error. */
1108 		retval=-1;  goto bailout;
1109 	}
1110 
1111 	cinfo->image_width=width;
1112 	cinfo->image_height=height;
1113 
1114 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1115 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1116 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1117 
1118 	if(flags&TJFLAG_NOREALLOC)
1119 	{
1120 		alloc=0;  *jpegSize=tjBufSize(width, height, subsamp);
1121 	}
1122 	jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
1123 	if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
1124 		return -1;
1125 	cinfo->raw_data_in=TRUE;
1126 
1127 	jpeg_start_compress(cinfo, TRUE);
1128 	for(i=0; i<cinfo->num_components; i++)
1129 	{
1130 		jpeg_component_info *compptr=&cinfo->comp_info[i];
1131 		int ih;
1132 		iw[i]=compptr->width_in_blocks*DCTSIZE;
1133 		ih=compptr->height_in_blocks*DCTSIZE;
1134 		pw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
1135 			*compptr->h_samp_factor/cinfo->max_h_samp_factor;
1136 		ph[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
1137 			*compptr->v_samp_factor/cinfo->max_v_samp_factor;
1138 		if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
1139 		th[i]=compptr->v_samp_factor*DCTSIZE;
1140 		tmpbufsize+=iw[i]*th[i];
1141 		if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
1142 			_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1143 		ptr=(JSAMPLE *)srcPlanes[i];
1144 		for(row=0; row<ph[i]; row++)
1145 		{
1146 			inbuf[i][row]=ptr;
1147 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
1148 		}
1149 	}
1150 	if(usetmpbuf)
1151 	{
1152 		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1153 			_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1154 		ptr=_tmpbuf;
1155 		for(i=0; i<cinfo->num_components; i++)
1156 		{
1157 			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1158 				_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
1159 			for(row=0; row<th[i]; row++)
1160 			{
1161 				tmpbuf[i][row]=ptr;
1162 				ptr+=iw[i];
1163 			}
1164 		}
1165 	}
1166 
1167 	if(setjmp(this->jerr.setjmp_buffer))
1168 	{
1169 		/* If we get here, the JPEG code has signaled an error. */
1170 		retval=-1;  goto bailout;
1171 	}
1172 
1173 	for(row=0; row<(int)cinfo->image_height;
1174 		row+=cinfo->max_v_samp_factor*DCTSIZE)
1175 	{
1176 		JSAMPARRAY yuvptr[MAX_COMPONENTS];
1177 		int crow[MAX_COMPONENTS];
1178 		for(i=0; i<cinfo->num_components; i++)
1179 		{
1180 			jpeg_component_info *compptr=&cinfo->comp_info[i];
1181 			crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
1182 			if(usetmpbuf)
1183 			{
1184 				int j, k;
1185 				for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
1186 				{
1187 					memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], pw[i]);
1188 					/* Duplicate last sample in row to fill out MCU */
1189 					for(k=pw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][pw[i]-1];
1190 				}
1191 				/* Duplicate last row to fill out MCU */
1192 				for(j=ph[i]-crow[i]; j<th[i]; j++)
1193 					memcpy(tmpbuf[i][j], tmpbuf[i][ph[i]-crow[i]-1], iw[i]);
1194 				yuvptr[i]=tmpbuf[i];
1195 			}
1196 			else
1197 				yuvptr[i]=&inbuf[i][crow[i]];
1198 		}
1199 		jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
1200 	}
1201 	jpeg_finish_compress(cinfo);
1202 
1203 	bailout:
1204 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1205 	for(i=0; i<MAX_COMPONENTS; i++)
1206 	{
1207 		if(tmpbuf[i]) free(tmpbuf[i]);
1208 		if(inbuf[i]) free(inbuf[i]);
1209 	}
1210 	if(_tmpbuf) free(_tmpbuf);
1211 	if(this->jerr.warning) retval=-1;
1212 	return retval;
1213 }
1214 
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)1215 DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle,
1216 	const unsigned char *srcBuf, int width, int pad, int height, int subsamp,
1217 	unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)
1218 {
1219 	const unsigned char *srcPlanes[3];
1220 	int pw0, ph0, strides[3], retval=-1;
1221 
1222 	if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
1223 		|| subsamp>=NUMSUBOPT)
1224 		_throw("tjCompressFromYUV(): Invalid argument");
1225 
1226 	pw0=tjPlaneWidth(0, width, subsamp);
1227 	ph0=tjPlaneHeight(0, height, subsamp);
1228 	srcPlanes[0]=srcBuf;
1229 	strides[0]=PAD(pw0, pad);
1230 	if(subsamp==TJSAMP_GRAY)
1231 	{
1232 		strides[1]=strides[2]=0;
1233 		srcPlanes[1]=srcPlanes[2]=NULL;
1234 	}
1235 	else
1236 	{
1237 		int pw1=tjPlaneWidth(1, width, subsamp);
1238 		int ph1=tjPlaneHeight(1, height, subsamp);
1239 		strides[1]=strides[2]=PAD(pw1, pad);
1240 		srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1241 		srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1242 	}
1243 
1244 	return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
1245 		subsamp, jpegBuf, jpegSize, jpegQual, flags);
1246 
1247 	bailout:
1248 	return retval;
1249 }
1250 
1251 
1252 /* Decompressor */
1253 
_tjInitDecompress(tjinstance * this)1254 static tjhandle _tjInitDecompress(tjinstance *this)
1255 {
1256 	static unsigned char buffer[1];
1257 
1258 	/* This is also straight out of example.c */
1259 	this->dinfo.err=jpeg_std_error(&this->jerr.pub);
1260 	this->jerr.pub.error_exit=my_error_exit;
1261 	this->jerr.pub.output_message=my_output_message;
1262 	this->jerr.emit_message=this->jerr.pub.emit_message;
1263 	this->jerr.pub.emit_message=my_emit_message;
1264 
1265 	if(setjmp(this->jerr.setjmp_buffer))
1266 	{
1267 		/* If we get here, the JPEG code has signaled an error. */
1268 		if(this) free(this);
1269 		return NULL;
1270 	}
1271 
1272 	jpeg_create_decompress(&this->dinfo);
1273 	/* Make an initial call so it will create the source manager */
1274 	jpeg_mem_src_tj(&this->dinfo, buffer, 1);
1275 
1276 	this->init|=DECOMPRESS;
1277 	return (tjhandle)this;
1278 }
1279 
tjInitDecompress(void)1280 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
1281 {
1282 	tjinstance *this;
1283 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1284 	{
1285 		snprintf(errStr, JMSG_LENGTH_MAX,
1286 			"tjInitDecompress(): Memory allocation failure");
1287 		return NULL;
1288 	}
1289 	MEMZERO(this, sizeof(tjinstance));
1290 	return _tjInitDecompress(this);
1291 }
1292 
1293 
tjDecompressHeader3(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height,int * jpegSubsamp,int * jpegColorspace)1294 DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
1295 	const unsigned char *jpegBuf, unsigned long jpegSize, int *width,
1296 	int *height, int *jpegSubsamp, int *jpegColorspace)
1297 {
1298 	int retval=0;
1299 
1300 	getdinstance(handle);
1301 	if((this->init&DECOMPRESS)==0)
1302 		_throw("tjDecompressHeader3(): Instance has not been initialized for decompression");
1303 
1304 	if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
1305 		|| jpegSubsamp==NULL || jpegColorspace==NULL)
1306 		_throw("tjDecompressHeader3(): Invalid argument");
1307 
1308 	if(setjmp(this->jerr.setjmp_buffer))
1309 	{
1310 		/* If we get here, the JPEG code has signaled an error. */
1311 		return -1;
1312 	}
1313 
1314 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1315 	jpeg_read_header(dinfo, TRUE);
1316 
1317 	*width=dinfo->image_width;
1318 	*height=dinfo->image_height;
1319 	*jpegSubsamp=getSubsamp(dinfo);
1320 	switch(dinfo->jpeg_color_space)
1321 	{
1322 		case JCS_GRAYSCALE:  *jpegColorspace=TJCS_GRAY;  break;
1323 		case JCS_RGB:        *jpegColorspace=TJCS_RGB;  break;
1324 		case JCS_YCbCr:      *jpegColorspace=TJCS_YCbCr;  break;
1325 		case JCS_CMYK:       *jpegColorspace=TJCS_CMYK;  break;
1326 		case JCS_YCCK:       *jpegColorspace=TJCS_YCCK;  break;
1327 		default:             *jpegColorspace=-1;  break;
1328 	}
1329 
1330 	jpeg_abort_decompress(dinfo);
1331 
1332 	if(*jpegSubsamp<0)
1333 		_throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image");
1334 	if(*jpegColorspace<0)
1335 		_throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image");
1336 	if(*width<1 || *height<1)
1337 		_throw("tjDecompressHeader3(): Invalid data returned in header");
1338 
1339 	bailout:
1340 	if(this->jerr.warning) retval=-1;
1341 	return retval;
1342 }
1343 
tjDecompressHeader2(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height,int * jpegSubsamp)1344 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
1345 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
1346 	int *jpegSubsamp)
1347 {
1348 	int jpegColorspace;
1349 	return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height,
1350 		jpegSubsamp, &jpegColorspace);
1351 }
1352 
tjDecompressHeader(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,int * width,int * height)1353 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
1354 	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
1355 {
1356 	int jpegSubsamp;
1357 	return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
1358 		&jpegSubsamp);
1359 }
1360 
1361 
tjGetScalingFactors(int * numscalingfactors)1362 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
1363 {
1364 	if(numscalingfactors==NULL)
1365 	{
1366 		snprintf(errStr, JMSG_LENGTH_MAX,
1367 			"tjGetScalingFactors(): Invalid argument");
1368 		return NULL;
1369 	}
1370 
1371 	*numscalingfactors=NUMSF;
1372 	return (tjscalingfactor *)sf;
1373 }
1374 
1375 
tjDecompress2(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)1376 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
1377 	const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1378 	int width, int pitch, int height, int pixelFormat, int flags)
1379 {
1380 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
1381 	int jpegwidth, jpegheight, scaledw, scaledh;
1382 	#ifndef JCS_EXTENSIONS
1383 	unsigned char *rgbBuf=NULL;
1384 	unsigned char *_dstBuf=NULL;  int _pitch=0;
1385 	#endif
1386 
1387 	getdinstance(handle);
1388 	if((this->init&DECOMPRESS)==0)
1389 		_throw("tjDecompress2(): Instance has not been initialized for decompression");
1390 
1391 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
1392 		|| height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
1393 		_throw("tjDecompress2(): Invalid argument");
1394 
1395 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1396 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1397 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1398 
1399 	if(setjmp(this->jerr.setjmp_buffer))
1400 	{
1401 		/* If we get here, the JPEG code has signaled an error. */
1402 		retval=-1;  goto bailout;
1403 	}
1404 
1405 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1406 	jpeg_read_header(dinfo, TRUE);
1407 	if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
1408 	{
1409 		retval=-1;  goto bailout;
1410 	}
1411 
1412 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1413 
1414 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
1415 	if(width==0) width=jpegwidth;
1416 	if(height==0) height=jpegheight;
1417 	for(i=0; i<NUMSF; i++)
1418 	{
1419 		scaledw=TJSCALED(jpegwidth, sf[i]);
1420 		scaledh=TJSCALED(jpegheight, sf[i]);
1421 		if(scaledw<=width && scaledh<=height)
1422 			break;
1423 	}
1424 	if(i>=NUMSF)
1425 		_throw("tjDecompress2(): Could not scale down to desired image dimensions");
1426 	width=scaledw;  height=scaledh;
1427 	dinfo->scale_num=sf[i].num;
1428 	dinfo->scale_denom=sf[i].denom;
1429 
1430 	jpeg_start_decompress(dinfo);
1431 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1432 
1433 	#ifndef JCS_EXTENSIONS
1434 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
1435 		(RGB_RED!=tjRedOffset[pixelFormat] ||
1436 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1437 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1438 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1439 	{
1440 		rgbBuf=(unsigned char *)malloc(width*height*3);
1441 		if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1442 		_pitch=pitch;  pitch=width*3;
1443 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
1444 	}
1445 	#endif
1446 
1447 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1448 		*dinfo->output_height))==NULL)
1449 		_throw("tjDecompress2(): Memory allocation failure");
1450 	if(setjmp(this->jerr.setjmp_buffer))
1451 	{
1452 		/* If we get here, the JPEG code has signaled an error. */
1453 		retval=-1;  goto bailout;
1454 	}
1455 	for(i=0; i<(int)dinfo->output_height; i++)
1456 	{
1457 		if(flags&TJFLAG_BOTTOMUP)
1458 			row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1459 		else row_pointer[i]=&dstBuf[i*pitch];
1460 	}
1461 	while(dinfo->output_scanline<dinfo->output_height)
1462 	{
1463 		jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1464 			dinfo->output_height-dinfo->output_scanline);
1465 	}
1466 	jpeg_finish_decompress(dinfo);
1467 
1468 	#ifndef JCS_EXTENSIONS
1469 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1470 	#endif
1471 
1472 	bailout:
1473 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1474 	#ifndef JCS_EXTENSIONS
1475 	if(rgbBuf) free(rgbBuf);
1476 	#endif
1477 	if(row_pointer) free(row_pointer);
1478 	if(this->jerr.warning) retval=-1;
1479 	return retval;
1480 }
1481 
tjDecompress(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pitch,int height,int pixelSize,int flags)1482 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1483 	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1484 	int height, int pixelSize, int flags)
1485 {
1486 	if(flags&TJ_YUV)
1487 		return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1488 	else
1489 		return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1490 			height, getPixelFormat(pixelSize, flags), flags);
1491 }
1492 
1493 
setDecodeDefaults(struct jpeg_decompress_struct * dinfo,int pixelFormat,int subsamp,int flags)1494 static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
1495 	int pixelFormat, int subsamp, int flags)
1496 {
1497 	int i;
1498 
1499 	dinfo->scale_num=dinfo->scale_denom=1;
1500 
1501 	if(subsamp==TJSAMP_GRAY)
1502 	{
1503 		dinfo->num_components=dinfo->comps_in_scan=1;
1504 		dinfo->jpeg_color_space=JCS_GRAYSCALE;
1505 	}
1506 	else
1507 	{
1508 		dinfo->num_components=dinfo->comps_in_scan=3;
1509 		dinfo->jpeg_color_space=JCS_YCbCr;
1510 	}
1511 
1512 	dinfo->comp_info=(jpeg_component_info *)
1513 		(*dinfo->mem->alloc_small)((j_common_ptr)dinfo, JPOOL_IMAGE,
1514 			dinfo->num_components*sizeof(jpeg_component_info));
1515 
1516 	for(i=0; i<dinfo->num_components; i++)
1517 	{
1518 		jpeg_component_info *compptr=&dinfo->comp_info[i];
1519 		compptr->h_samp_factor=(i==0)? tjMCUWidth[subsamp]/8:1;
1520 		compptr->v_samp_factor=(i==0)? tjMCUHeight[subsamp]/8:1;
1521 		compptr->component_index=i;
1522 		compptr->component_id=i+1;
1523 		compptr->quant_tbl_no=compptr->dc_tbl_no=compptr->ac_tbl_no=
1524 			(i==0)? 0:1;
1525 		dinfo->cur_comp_info[i]=compptr;
1526 	}
1527 	dinfo->data_precision=8;
1528 	for(i=0; i<2; i++)
1529 	{
1530 		if(dinfo->quant_tbl_ptrs[i]==NULL)
1531 			dinfo->quant_tbl_ptrs[i]=jpeg_alloc_quant_table((j_common_ptr)dinfo);
1532 	}
1533 
1534 	return 0;
1535 }
1536 
1537 
my_read_markers(j_decompress_ptr dinfo)1538 int my_read_markers(j_decompress_ptr dinfo)
1539 {
1540 	return JPEG_REACHED_SOS;
1541 }
1542 
my_reset_marker_reader(j_decompress_ptr dinfo)1543 void my_reset_marker_reader(j_decompress_ptr dinfo)
1544 {
1545 }
1546 
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)1547 DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
1548 	const unsigned char **srcPlanes, const int *strides, int subsamp,
1549 	unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat,
1550 	int flags)
1551 {
1552 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
1553 	JSAMPLE *_tmpbuf[MAX_COMPONENTS];
1554 	JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS];
1555 	int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS];
1556 	JSAMPLE *ptr;
1557 	jpeg_component_info *compptr;
1558 	#ifndef JCS_EXTENSIONS
1559 	unsigned char *rgbBuf=NULL;
1560 	unsigned char *_dstBuf=NULL;  int _pitch=0;
1561 	#endif
1562 	int (*old_read_markers)(j_decompress_ptr);
1563 	void (*old_reset_marker_reader)(j_decompress_ptr);
1564 
1565 	getdinstance(handle);
1566 
1567 	for(i=0; i<MAX_COMPONENTS; i++)
1568 	{
1569 		tmpbuf[i]=NULL;  _tmpbuf[i]=NULL;  inbuf[i]=NULL;
1570 	}
1571 
1572 	if((this->init&DECOMPRESS)==0)
1573 		_throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
1574 
1575 	if(!srcPlanes || !srcPlanes[0] || subsamp<0 || subsamp>=NUMSUBOPT
1576 		|| dstBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
1577 		|| pixelFormat>=TJ_NUMPF)
1578 		_throw("tjDecodeYUVPlanes(): Invalid argument");
1579 	if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
1580 		_throw("tjDecodeYUVPlanes(): Invalid argument");
1581 
1582 	if(setjmp(this->jerr.setjmp_buffer))
1583 	{
1584 		/* If we get here, the JPEG code has signaled an error. */
1585 		retval=-1;  goto bailout;
1586 	}
1587 
1588 	if(pixelFormat==TJPF_CMYK)
1589 		_throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
1590 
1591 	if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
1592 	dinfo->image_width=width;
1593 	dinfo->image_height=height;
1594 
1595 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1596 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1597 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1598 
1599 	if(setDecodeDefaults(dinfo, pixelFormat, subsamp, flags)==-1)
1600 	{
1601 		retval=-1;  goto bailout;
1602 	}
1603 	old_read_markers=dinfo->marker->read_markers;
1604 	dinfo->marker->read_markers=my_read_markers;
1605 	old_reset_marker_reader=dinfo->marker->reset_marker_reader;
1606 	dinfo->marker->reset_marker_reader=my_reset_marker_reader;
1607 	jpeg_read_header(dinfo, TRUE);
1608 	dinfo->marker->read_markers=old_read_markers;
1609 	dinfo->marker->reset_marker_reader=old_reset_marker_reader;
1610 
1611 	if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
1612 	{
1613 		retval=-1;  goto bailout;
1614 	}
1615 	dinfo->do_fancy_upsampling=FALSE;
1616 	dinfo->Se=DCTSIZE2-1;
1617 	jinit_master_decompress(dinfo);
1618 	(*dinfo->upsample->start_pass)(dinfo);
1619 
1620 	pw0=PAD(width, dinfo->max_h_samp_factor);
1621 	ph0=PAD(height, dinfo->max_v_samp_factor);
1622 
1623 	if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
1624 
1625 	#ifndef JCS_EXTENSIONS
1626 	if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK &&
1627 		(RGB_RED!=tjRedOffset[pixelFormat] ||
1628 			RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1629 			RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1630 			RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1631 	{
1632 		rgbBuf=(unsigned char *)malloc(width*height*3);
1633 		if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1634 		_pitch=pitch;  pitch=width*3;
1635 		_dstBuf=dstBuf;  dstBuf=rgbBuf;
1636 	}
1637 	#endif
1638 
1639 	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL)
1640 		_throw("tjDecodeYUVPlanes(): Memory allocation failure");
1641 	for(i=0; i<height; i++)
1642 	{
1643 		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch];
1644 		else row_pointer[i]=&dstBuf[i*pitch];
1645 	}
1646 	if(height<ph0)
1647 		for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
1648 
1649 	for(i=0; i<dinfo->num_components; i++)
1650 	{
1651 		compptr=&dinfo->comp_info[i];
1652 		_tmpbuf[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
1653 			* compptr->v_samp_factor + 16);
1654 		if(!_tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1655 		tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
1656 		if(!tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1657 		for(row=0; row<compptr->v_samp_factor; row++)
1658 		{
1659 			unsigned char *_tmpbuf_aligned=
1660 				(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
1661 			tmpbuf[i][row]=&_tmpbuf_aligned[
1662 				PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
1663 		}
1664 		pw[i]=pw0*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1665 		ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1666 		inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
1667 		if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
1668 		ptr=(JSAMPLE *)srcPlanes[i];
1669 		for(row=0; row<ph[i]; row++)
1670 		{
1671 			inbuf[i][row]=ptr;
1672 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
1673 		}
1674 	}
1675 
1676 	if(setjmp(this->jerr.setjmp_buffer))
1677 	{
1678 		/* If we get here, the JPEG code has signaled an error. */
1679 		retval=-1;  goto bailout;
1680 	}
1681 
1682 	for(row=0; row<ph0; row+=dinfo->max_v_samp_factor)
1683 	{
1684 		JDIMENSION inrow=0, outrow=0;
1685 		for(i=0, compptr=dinfo->comp_info; i<dinfo->num_components; i++, compptr++)
1686 			jcopy_sample_rows(inbuf[i],
1687 				row*compptr->v_samp_factor/dinfo->max_v_samp_factor, tmpbuf[i], 0,
1688 				compptr->v_samp_factor, pw[i]);
1689 		(dinfo->upsample->upsample)(dinfo, tmpbuf, &inrow,
1690 			dinfo->max_v_samp_factor, &row_pointer[row], &outrow,
1691 			dinfo->max_v_samp_factor);
1692 	}
1693 	jpeg_abort_decompress(dinfo);
1694 
1695 	#ifndef JCS_EXTENSIONS
1696 	fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1697 	#endif
1698 
1699 	bailout:
1700 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1701 	#ifndef JCS_EXTENSIONS
1702 	if(rgbBuf) free(rgbBuf);
1703 	#endif
1704 	if(row_pointer) free(row_pointer);
1705 	for(i=0; i<MAX_COMPONENTS; i++)
1706 	{
1707 		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
1708 		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
1709 		if(inbuf[i]!=NULL) free(inbuf[i]);
1710 	}
1711 	if(this->jerr.warning) retval=-1;
1712 	return retval;
1713 }
1714 
tjDecodeYUV(tjhandle handle,const unsigned char * srcBuf,int pad,int subsamp,unsigned char * dstBuf,int width,int pitch,int height,int pixelFormat,int flags)1715 DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
1716 	int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
1717 	int height, int pixelFormat, int flags)
1718 {
1719 	const unsigned char *srcPlanes[3];
1720 	int pw0, ph0, strides[3], retval=-1;
1721 
1722 	if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
1723 		|| width<=0 || height<=0)
1724 		_throw("tjDecodeYUV(): Invalid argument");
1725 
1726 	pw0=tjPlaneWidth(0, width, subsamp);
1727 	ph0=tjPlaneHeight(0, height, subsamp);
1728 	srcPlanes[0]=srcBuf;
1729 	strides[0]=PAD(pw0, pad);
1730 	if(subsamp==TJSAMP_GRAY)
1731 	{
1732 		strides[1]=strides[2]=0;
1733 		srcPlanes[1]=srcPlanes[2]=NULL;
1734 	}
1735 	else
1736 	{
1737 		int pw1=tjPlaneWidth(1, width, subsamp);
1738 		int ph1=tjPlaneHeight(1, height, subsamp);
1739 		strides[1]=strides[2]=PAD(pw1, pad);
1740 		srcPlanes[1]=srcPlanes[0]+strides[0]*ph0;
1741 		srcPlanes[2]=srcPlanes[1]+strides[1]*ph1;
1742 	}
1743 
1744 	return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
1745 		pitch, height, pixelFormat, flags);
1746 
1747 	bailout:
1748 	return retval;
1749 }
1750 
tjDecompressToYUVPlanes(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,unsigned char ** dstPlanes,int width,int * strides,int height,int flags)1751 DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
1752 	const unsigned char *jpegBuf, unsigned long jpegSize,
1753 	unsigned char **dstPlanes, int width, int *strides, int height, int flags)
1754 {
1755 	int i, sfi, row, retval=0;  JSAMPROW *outbuf[MAX_COMPONENTS];
1756 	int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
1757 	int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1758 		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1759 	JSAMPLE *_tmpbuf=NULL, *ptr;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
1760 	int dctsize;
1761 
1762 	getdinstance(handle);
1763 
1764 	for(i=0; i<MAX_COMPONENTS; i++)
1765 	{
1766 		tmpbuf[i]=NULL;  outbuf[i]=NULL;
1767 	}
1768 
1769 	if((this->init&DECOMPRESS)==0)
1770 		_throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression");
1771 
1772 	if(jpegBuf==NULL || jpegSize<=0 || !dstPlanes || !dstPlanes[0] || width<0
1773 		|| height<0)
1774 		_throw("tjDecompressToYUVPlanes(): Invalid argument");
1775 
1776 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1777 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1778 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1779 
1780 	if(setjmp(this->jerr.setjmp_buffer))
1781 	{
1782 		/* If we get here, the JPEG code has signaled an error. */
1783 		retval=-1;  goto bailout;
1784 	}
1785 
1786 	if(!this->headerRead)
1787 	{
1788 		jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1789 		jpeg_read_header(dinfo, TRUE);
1790 	}
1791 	this->headerRead=0;
1792 	jpegSubsamp=getSubsamp(dinfo);
1793 	if(jpegSubsamp<0)
1794 		_throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image");
1795 
1796 	if(jpegSubsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
1797 		_throw("tjDecompressToYUVPlanes(): Invalid argument");
1798 
1799 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
1800 	if(width==0) width=jpegwidth;
1801 	if(height==0) height=jpegheight;
1802 	for(i=0; i<NUMSF; i++)
1803 	{
1804 		scaledw=TJSCALED(jpegwidth, sf[i]);
1805 		scaledh=TJSCALED(jpegheight, sf[i]);
1806 		if(scaledw<=width && scaledh<=height)
1807 			break;
1808 	}
1809 	if(i>=NUMSF)
1810 		_throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions");
1811 	if(dinfo->num_components>3)
1812 		_throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components");
1813 
1814 	width=scaledw;  height=scaledh;
1815 	dinfo->scale_num=sf[i].num;
1816 	dinfo->scale_denom=sf[i].denom;
1817 	sfi=i;
1818 	jpeg_calc_output_dimensions(dinfo);
1819 
1820 	dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom;
1821 
1822 	for(i=0; i<dinfo->num_components; i++)
1823 	{
1824 		jpeg_component_info *compptr=&dinfo->comp_info[i];
1825 		int ih;
1826 		iw[i]=compptr->width_in_blocks*dctsize;
1827 		ih=compptr->height_in_blocks*dctsize;
1828 		pw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor)
1829 			*compptr->h_samp_factor/dinfo->max_h_samp_factor;
1830 		ph[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor)
1831 			*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1832 		if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1;
1833 		th[i]=compptr->v_samp_factor*dctsize;
1834 		tmpbufsize+=iw[i]*th[i];
1835 		if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
1836 			_throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1837 		ptr=dstPlanes[i];
1838 		for(row=0; row<ph[i]; row++)
1839 		{
1840 			outbuf[i][row]=ptr;
1841 			ptr+=(strides && strides[i]!=0)? strides[i]:pw[i];
1842 		}
1843 	}
1844 	if(usetmpbuf)
1845 	{
1846 		if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1847 			_throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1848 		ptr=_tmpbuf;
1849 		for(i=0; i<dinfo->num_components; i++)
1850 		{
1851 			if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1852 				_throw("tjDecompressToYUVPlanes(): Memory allocation failure");
1853 			for(row=0; row<th[i]; row++)
1854 			{
1855 				tmpbuf[i][row]=ptr;
1856 				ptr+=iw[i];
1857 			}
1858 		}
1859 	}
1860 
1861 	if(setjmp(this->jerr.setjmp_buffer))
1862 	{
1863 		/* If we get here, the JPEG code has signaled an error. */
1864 		retval=-1;  goto bailout;
1865 	}
1866 
1867 	if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1868 	if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
1869 	dinfo->raw_data_out=TRUE;
1870 
1871 	jpeg_start_decompress(dinfo);
1872 	for(row=0; row<(int)dinfo->output_height;
1873 		row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size)
1874 	{
1875 		JSAMPARRAY yuvptr[MAX_COMPONENTS];
1876 		int crow[MAX_COMPONENTS];
1877 		for(i=0; i<dinfo->num_components; i++)
1878 		{
1879 			jpeg_component_info *compptr=&dinfo->comp_info[i];
1880 			if(jpegSubsamp==TJ_420)
1881 			{
1882 				/* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
1883 				   to be clever and use the IDCT to perform upsampling on the U and V
1884 				   planes.  For instance, if the output image is to be scaled by 1/2
1885 				   relative to the JPEG image, then the scaling factor and upsampling
1886 				   effectively cancel each other, so a normal 8x8 IDCT can be used.
1887 				   However, this is not desirable when using the decompress-to-YUV
1888 				   functionality in TurboJPEG, since we want to output the U and V
1889 				   planes in their subsampled form.  Thus, we have to override some
1890 				   internal libjpeg parameters to force it to use the "scaled" IDCT
1891 				   functions on the U and V planes. */
1892 				compptr->_DCT_scaled_size=dctsize;
1893 				compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]*
1894 					sf[sfi].num/sf[sfi].denom*
1895 					compptr->v_samp_factor/dinfo->max_v_samp_factor;
1896 				dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0];
1897 			}
1898 			crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1899 			if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1900 			else yuvptr[i]=&outbuf[i][crow[i]];
1901 		}
1902 		jpeg_read_raw_data(dinfo, yuvptr,
1903 			dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size);
1904 		if(usetmpbuf)
1905 		{
1906 			int j;
1907 			for(i=0; i<dinfo->num_components; i++)
1908 			{
1909 				for(j=0; j<min(th[i], ph[i]-crow[i]); j++)
1910 				{
1911 					memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], pw[i]);
1912 				}
1913 			}
1914 		}
1915 	}
1916 	jpeg_finish_decompress(dinfo);
1917 
1918 	bailout:
1919 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1920 	for(i=0; i<MAX_COMPONENTS; i++)
1921 	{
1922 		if(tmpbuf[i]) free(tmpbuf[i]);
1923 		if(outbuf[i]) free(outbuf[i]);
1924 	}
1925 	if(_tmpbuf) free(_tmpbuf);
1926 	if(this->jerr.warning) retval=-1;
1927 	return retval;
1928 }
1929 
tjDecompressToYUV2(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int width,int pad,int height,int flags)1930 DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
1931 	const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1932 	int width, int pad, int height, int flags)
1933 {
1934 	unsigned char *dstPlanes[3];
1935 	int pw0, ph0, strides[3], retval=-1, jpegSubsamp=-1;
1936 	int i, jpegwidth, jpegheight, scaledw, scaledh;
1937 
1938 	getdinstance(handle);
1939 
1940 	if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1
1941 		|| !isPow2(pad) || height<0)
1942 		_throw("tjDecompressToYUV2(): Invalid argument");
1943 
1944 	if(setjmp(this->jerr.setjmp_buffer))
1945 	{
1946 		/* If we get here, the JPEG code has signaled an error. */
1947 		return -1;
1948 	}
1949 
1950 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1951 	jpeg_read_header(dinfo, TRUE);
1952 	jpegSubsamp=getSubsamp(dinfo);
1953 	if(jpegSubsamp<0)
1954 		_throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
1955 
1956 	jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
1957 	if(width==0) width=jpegwidth;
1958 	if(height==0) height=jpegheight;
1959 
1960 	for(i=0; i<NUMSF; i++)
1961 	{
1962 		scaledw=TJSCALED(jpegwidth, sf[i]);
1963 		scaledh=TJSCALED(jpegheight, sf[i]);
1964 		if(scaledw<=width && scaledh<=height)
1965 			break;
1966 	}
1967 	if(i>=NUMSF)
1968 		_throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
1969 
1970 	pw0=tjPlaneWidth(0, width, jpegSubsamp);
1971 	ph0=tjPlaneHeight(0, height, jpegSubsamp);
1972 	dstPlanes[0]=dstBuf;
1973 	strides[0]=PAD(pw0, pad);
1974 	if(jpegSubsamp==TJSAMP_GRAY)
1975 	{
1976 		strides[1]=strides[2]=0;
1977 		dstPlanes[1]=dstPlanes[2]=NULL;
1978 	}
1979 	else
1980 	{
1981 		int pw1=tjPlaneWidth(1, width, jpegSubsamp);
1982 		int ph1=tjPlaneHeight(1, height, jpegSubsamp);
1983 		strides[1]=strides[2]=PAD(pw1, pad);
1984 		dstPlanes[1]=dstPlanes[0]+strides[0]*ph0;
1985 		dstPlanes[2]=dstPlanes[1]+strides[1]*ph1;
1986 	}
1987 
1988 	this->headerRead=1;
1989 	return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
1990 		strides, height, flags);
1991 
1992 	bailout:
1993 	return retval;
1994 
1995 }
1996 
tjDecompressToYUV(tjhandle handle,unsigned char * jpegBuf,unsigned long jpegSize,unsigned char * dstBuf,int flags)1997 DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1998 	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1999 	int flags)
2000 {
2001 	return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags);
2002 }
2003 
2004 
2005 /* Transformer */
2006 
tjInitTransform(void)2007 DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
2008 {
2009 	tjinstance *this=NULL;  tjhandle handle=NULL;
2010 	if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
2011 	{
2012 		snprintf(errStr, JMSG_LENGTH_MAX,
2013 			"tjInitTransform(): Memory allocation failure");
2014 		return NULL;
2015 	}
2016 	MEMZERO(this, sizeof(tjinstance));
2017 	handle=_tjInitCompress(this);
2018 	if(!handle) return NULL;
2019 	handle=_tjInitDecompress(this);
2020 	return handle;
2021 }
2022 
2023 
tjTransform(tjhandle handle,const unsigned char * jpegBuf,unsigned long jpegSize,int n,unsigned char ** dstBufs,unsigned long * dstSizes,tjtransform * t,int flags)2024 DLLEXPORT int DLLCALL tjTransform(tjhandle handle,
2025 	const unsigned char *jpegBuf, unsigned long jpegSize, int n,
2026 	unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *t, int flags)
2027 {
2028 	jpeg_transform_info *xinfo=NULL;
2029 	jvirt_barray_ptr *srccoefs, *dstcoefs;
2030 	int retval=0, i, jpegSubsamp;
2031 
2032 	getinstance(handle);
2033 	if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
2034 		_throw("tjTransform(): Instance has not been initialized for transformation");
2035 
2036 	if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
2037 		|| t==NULL || flags<0)
2038 		_throw("tjTransform(): Invalid argument");
2039 
2040 	if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
2041 	else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
2042 	else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
2043 
2044 	if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
2045 		==NULL)
2046 		_throw("tjTransform(): Memory allocation failure");
2047 	MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
2048 
2049 	if(setjmp(this->jerr.setjmp_buffer))
2050 	{
2051 		/* If we get here, the JPEG code has signaled an error. */
2052 		retval=-1;  goto bailout;
2053 	}
2054 
2055 	jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
2056 
2057 	for(i=0; i<n; i++)
2058 	{
2059 		xinfo[i].transform=xformtypes[t[i].op];
2060 		xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
2061 		xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
2062 		xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
2063 		xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
2064 		if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
2065 		else xinfo[i].slow_hflip=0;
2066 
2067 		if(xinfo[i].crop)
2068 		{
2069 			xinfo[i].crop_xoffset=t[i].r.x;  xinfo[i].crop_xoffset_set=JCROP_POS;
2070 			xinfo[i].crop_yoffset=t[i].r.y;  xinfo[i].crop_yoffset_set=JCROP_POS;
2071 			if(t[i].r.w!=0)
2072 			{
2073 				xinfo[i].crop_width=t[i].r.w;  xinfo[i].crop_width_set=JCROP_POS;
2074 			}
2075 			else xinfo[i].crop_width=JCROP_UNSET;
2076 			if(t[i].r.h!=0)
2077 			{
2078 				xinfo[i].crop_height=t[i].r.h;  xinfo[i].crop_height_set=JCROP_POS;
2079 			}
2080 			else xinfo[i].crop_height=JCROP_UNSET;
2081 		}
2082 	}
2083 
2084 	jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
2085 	jpeg_read_header(dinfo, TRUE);
2086 	jpegSubsamp=getSubsamp(dinfo);
2087 	if(jpegSubsamp<0)
2088 		_throw("tjTransform(): Could not determine subsampling type for JPEG image");
2089 
2090 	for(i=0; i<n; i++)
2091 	{
2092 		if(!jtransform_request_workspace(dinfo, &xinfo[i]))
2093 			_throw("tjTransform(): Transform is not perfect");
2094 
2095 		if(xinfo[i].crop)
2096 		{
2097 			if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
2098 				|| (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
2099 			{
2100 				snprintf(errStr, JMSG_LENGTH_MAX,
2101 					"To crop this JPEG image, x must be a multiple of %d\n"
2102 					"and y must be a multiple of %d.\n",
2103 					xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
2104 				retval=-1;  goto bailout;
2105 			}
2106 		}
2107 	}
2108 
2109 	srccoefs=jpeg_read_coefficients(dinfo);
2110 
2111 	for(i=0; i<n; i++)
2112 	{
2113 		int w, h, alloc=1;
2114 		if(!xinfo[i].crop)
2115 		{
2116 			w=dinfo->image_width;  h=dinfo->image_height;
2117 		}
2118 		else
2119 		{
2120 			w=xinfo[i].crop_width;  h=xinfo[i].crop_height;
2121 		}
2122 		if(flags&TJFLAG_NOREALLOC)
2123 		{
2124 			alloc=0;  dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
2125 		}
2126 		if(!(t[i].options&TJXOPT_NOOUTPUT))
2127 			jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
2128 		jpeg_copy_critical_parameters(dinfo, cinfo);
2129 		dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
2130 			&xinfo[i]);
2131 		if(!(t[i].options&TJXOPT_NOOUTPUT))
2132 		{
2133 			jpeg_write_coefficients(cinfo, dstcoefs);
2134 			jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
2135 		}
2136 		else jinit_c_master_control(cinfo, TRUE);
2137 		jtransform_execute_transformation(dinfo, cinfo, srccoefs,
2138 			&xinfo[i]);
2139 		if(t[i].customFilter)
2140 		{
2141 			int ci, y;  JDIMENSION by;
2142 			for(ci=0; ci<cinfo->num_components; ci++)
2143 			{
2144 				jpeg_component_info *compptr=&cinfo->comp_info[ci];
2145 				tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2146 					DCTSIZE};
2147 				tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
2148 					compptr->height_in_blocks*DCTSIZE};
2149 				for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
2150 				{
2151 					JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
2152 						((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
2153 						TRUE);
2154 					for(y=0; y<compptr->v_samp_factor; y++)
2155 					{
2156 						if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
2157 							ci, i, &t[i])==-1)
2158 							_throw("tjTransform(): Error in custom filter");
2159 						arrayRegion.y+=DCTSIZE;
2160 					}
2161 				}
2162 			}
2163 		}
2164 		if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
2165 	}
2166 
2167 	jpeg_finish_decompress(dinfo);
2168 
2169 	bailout:
2170 	if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
2171 	if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
2172 	if(xinfo) free(xinfo);
2173 	if(this->jerr.warning) retval=-1;
2174 	return retval;
2175 }
2176