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