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