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