libjpeg-turbo-1.2.1-int32
[platform/upstream/libjpeg-turbo.git] / turbojpeg.c
1 /*
2  * Copyright (C)2009-2012, 2014 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 <jinclude.h>
35 #define JPEG_INTERNALS
36 #include <jpeglib.h>
37 #include <jerror.h>
38 #include <setjmp.h>
39 #include "./turbojpeg.h"
40 #include "./tjutil.h"
41 #include "transupp.h"
42
43 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
44         unsigned long *, boolean);
45 extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
46
47 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
48
49
50 /* Error handling (based on example in example.c) */
51
52 static char errStr[JMSG_LENGTH_MAX]="No error";
53
54 struct my_error_mgr
55 {
56         struct jpeg_error_mgr pub;
57         jmp_buf setjmp_buffer;
58 };
59 typedef struct my_error_mgr *my_error_ptr;
60
61 static void my_error_exit(j_common_ptr cinfo)
62 {
63         my_error_ptr myerr=(my_error_ptr)cinfo->err;
64         (*cinfo->err->output_message)(cinfo);
65         longjmp(myerr->setjmp_buffer, 1);
66 }
67
68 /* Based on output_message() in jerror.c */
69
70 static void my_output_message(j_common_ptr cinfo)
71 {
72         (*cinfo->err->format_message)(cinfo, errStr);
73 }
74
75
76 /* Global structures, macros, etc. */
77
78 enum {COMPRESS=1, DECOMPRESS=2};
79
80 typedef struct _tjinstance
81 {
82         struct jpeg_compress_struct cinfo;
83         struct jpeg_decompress_struct dinfo;
84         struct my_error_mgr jerr;
85         int init;
86 } tjinstance;
87
88 static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3};
89
90 static const JXFORM_CODE xformtypes[TJ_NUMXOP]=
91 {
92         JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
93         JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
94 };
95
96 #define NUMSF 16
97 static const tjscalingfactor sf[NUMSF]={
98         {2, 1},
99         {15, 8},
100         {7, 4},
101         {13, 8},
102         {3, 2},
103         {11, 8},
104         {5, 4},
105         {9, 8},
106         {1, 1},
107         {7, 8},
108         {3, 4},
109         {5, 8},
110         {1, 2},
111         {3, 8},
112         {1, 4},
113         {1, 8}
114 };
115
116 #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m);  \
117         retval=-1;  goto bailout;}
118 #define getinstance(handle) tjinstance *this=(tjinstance *)handle;  \
119         j_compress_ptr cinfo=NULL;  j_decompress_ptr dinfo=NULL;  \
120         if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle");  \
121                 return -1;}  \
122         cinfo=&this->cinfo;  dinfo=&this->dinfo;
123
124 static int getPixelFormat(int pixelSize, int flags)
125 {
126         if(pixelSize==1) return TJPF_GRAY;
127         if(pixelSize==3)
128         {
129                 if(flags&TJ_BGR) return TJPF_BGR;
130                 else return TJPF_RGB;
131         }
132         if(pixelSize==4)
133         {
134                 if(flags&TJ_ALPHAFIRST)
135                 {
136                         if(flags&TJ_BGR) return TJPF_XBGR;
137                         else return TJPF_XRGB;
138                 }
139                 else
140                 {
141                         if(flags&TJ_BGR) return TJPF_BGRX;
142                         else return TJPF_RGBX;
143                 }
144         }
145         return -1;
146 }
147
148 static int setCompDefaults(struct jpeg_compress_struct *cinfo,
149         int pixelFormat, int subsamp, int jpegQual, int flags)
150 {
151         int retval=0;
152
153         switch(pixelFormat)
154         {
155                 case TJPF_GRAY:
156                         cinfo->in_color_space=JCS_GRAYSCALE;  break;
157                 #if JCS_EXTENSIONS==1
158                 case TJPF_RGB:
159                         cinfo->in_color_space=JCS_EXT_RGB;  break;
160                 case TJPF_BGR:
161                         cinfo->in_color_space=JCS_EXT_BGR;  break;
162                 case TJPF_RGBX:
163                 case TJPF_RGBA:
164                         cinfo->in_color_space=JCS_EXT_RGBX;  break;
165                 case TJPF_BGRX:
166                 case TJPF_BGRA:
167                         cinfo->in_color_space=JCS_EXT_BGRX;  break;
168                 case TJPF_XRGB:
169                 case TJPF_ARGB:
170                         cinfo->in_color_space=JCS_EXT_XRGB;  break;
171                 case TJPF_XBGR:
172                 case TJPF_ABGR:
173                         cinfo->in_color_space=JCS_EXT_XBGR;  break;
174                 #else
175                 case TJPF_RGB:
176                 case TJPF_BGR:
177                 case TJPF_RGBX:
178                 case TJPF_BGRX:
179                 case TJPF_XRGB:
180                 case TJPF_XBGR:
181                 case TJPF_RGBA:
182                 case TJPF_BGRA:
183                 case TJPF_ARGB:
184                 case TJPF_ABGR:
185                         cinfo->in_color_space=JCS_RGB;  pixelFormat=TJPF_RGB;
186                         break;
187                 #endif
188         }
189
190         cinfo->input_components=tjPixelSize[pixelFormat];
191         jpeg_set_defaults(cinfo);
192         if(jpegQual>=0)
193         {
194                 jpeg_set_quality(cinfo, jpegQual, TRUE);
195                 if(jpegQual>=96 || flags&TJFLAG_ACCURATEDCT) cinfo->dct_method=JDCT_ISLOW;
196                 else cinfo->dct_method=JDCT_FASTEST;
197         }
198         if(subsamp==TJSAMP_GRAY)
199                 jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
200         else
201                 jpeg_set_colorspace(cinfo, JCS_YCbCr);
202
203         cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8;
204         cinfo->comp_info[1].h_samp_factor=1;
205         cinfo->comp_info[2].h_samp_factor=1;
206         cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8;
207         cinfo->comp_info[1].v_samp_factor=1;
208         cinfo->comp_info[2].v_samp_factor=1;
209
210         return retval;
211 }
212
213 static int setDecompDefaults(struct jpeg_decompress_struct *dinfo,
214         int pixelFormat, int flags)
215 {
216         int retval=0;
217
218         switch(pixelFormat)
219         {
220                 case TJPF_GRAY:
221                         dinfo->out_color_space=JCS_GRAYSCALE;  break;
222                 #if JCS_EXTENSIONS==1
223                 case TJPF_RGB:
224                         dinfo->out_color_space=JCS_EXT_RGB;  break;
225                 case TJPF_BGR:
226                         dinfo->out_color_space=JCS_EXT_BGR;  break;
227                 case TJPF_RGBX:
228                         dinfo->out_color_space=JCS_EXT_RGBX;  break;
229                 case TJPF_BGRX:
230                         dinfo->out_color_space=JCS_EXT_BGRX;  break;
231                 case TJPF_XRGB:
232                         dinfo->out_color_space=JCS_EXT_XRGB;  break;
233                 case TJPF_XBGR:
234                         dinfo->out_color_space=JCS_EXT_XBGR;  break;
235                 #if JCS_ALPHA_EXTENSIONS==1
236                 case TJPF_RGBA:
237                         dinfo->out_color_space=JCS_EXT_RGBA;  break;
238                 case TJPF_BGRA:
239                         dinfo->out_color_space=JCS_EXT_BGRA;  break;
240                 case TJPF_ARGB:
241                         dinfo->out_color_space=JCS_EXT_ARGB;  break;
242                 case TJPF_ABGR:
243                         dinfo->out_color_space=JCS_EXT_ABGR;  break;
244                 #endif
245                 #else
246                 case TJPF_RGB:
247                 case TJPF_BGR:
248                 case TJPF_RGBX:
249                 case TJPF_BGRX:
250                 case TJPF_XRGB:
251                 case TJPF_XBGR:
252                 case TJPF_RGBA:
253                 case TJPF_BGRA:
254                 case TJPF_ARGB:
255                 case TJPF_ABGR:
256                         dinfo->out_color_space=JCS_RGB;  break;
257                 #endif
258                 default:
259                         _throw("Unsupported pixel format");
260         }
261
262         if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
263
264         bailout:
265         return retval;
266 }
267
268
269 static int getSubsamp(j_decompress_ptr dinfo)
270 {
271         int retval=-1, i, k;
272         for(i=0; i<NUMSUBOPT; i++)
273         {
274                 if(dinfo->num_components==pixelsize[i])
275                 {
276                         if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8
277                                 && dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8)
278                         {
279                                 int match=0;
280                                 for(k=1; k<dinfo->num_components; k++)
281                                 {
282                                         if(dinfo->comp_info[k].h_samp_factor==1
283                                                 && dinfo->comp_info[k].v_samp_factor==1)
284                                                 match++;
285                                 }
286                                 if(match==dinfo->num_components-1)
287                                 {
288                                         retval=i;  break;
289                                 }
290                         }
291                 }
292         }
293         return retval;
294 }
295
296
297 #ifndef JCS_EXTENSIONS
298
299 /* Conversion functions to emulate the colorspace extensions.  This allows the
300    TurboJPEG wrapper to be used with libjpeg */
301
302 #define TORGB(PS, ROFFSET, GOFFSET, BOFFSET) {  \
303         int rowPad=pitch-width*PS;  \
304         while(height--)  \
305         {  \
306                 unsigned char *endOfRow=src+width*PS;  \
307                 while(src<endOfRow)  \
308                 {  \
309                         dst[RGB_RED]=src[ROFFSET];  \
310                         dst[RGB_GREEN]=src[GOFFSET];  \
311                         dst[RGB_BLUE]=src[BOFFSET];  \
312                         dst+=RGB_PIXELSIZE;  src+=PS;  \
313                 }  \
314                 src+=rowPad;  \
315         }  \
316 }
317
318 static unsigned char *toRGB(unsigned char *src, int width, int pitch,
319         int height, int pixelFormat, unsigned char *dst)
320 {
321         unsigned char *retval=src;
322         switch(pixelFormat)
323         {
324                 case TJPF_RGB:
325                         #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
326                         retval=dst;  TORGB(3, 0, 1, 2);
327                         #endif
328                         break;
329                 case TJPF_BGR:
330                         #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
331                         retval=dst;  TORGB(3, 2, 1, 0);
332                         #endif
333                         break;
334                 case TJPF_RGBX:
335                 case TJPF_RGBA:
336                         #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
337                         retval=dst;  TORGB(4, 0, 1, 2);
338                         #endif
339                         break;
340                 case TJPF_BGRX:
341                 case TJPF_BGRA:
342                         #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
343                         retval=dst;  TORGB(4, 2, 1, 0);
344                         #endif
345                         break;
346                 case TJPF_XRGB:
347                 case TJPF_ARGB:
348                         #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
349                         retval=dst;  TORGB(4, 1, 2, 3);
350                         #endif
351                         break;
352                 case TJPF_XBGR:
353                 case TJPF_ABGR:
354                         #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
355                         retval=dst;  TORGB(4, 3, 2, 1);
356                         #endif
357                         break;
358         }
359         return retval;
360 }
361
362 #define FROMRGB(PS, ROFFSET, GOFFSET, BOFFSET, SETALPHA) {  \
363         int rowPad=pitch-width*PS;  \
364         while(height--)  \
365         {  \
366                 unsigned char *endOfRow=dst+width*PS;  \
367                 while(dst<endOfRow)  \
368                 {  \
369                         dst[ROFFSET]=src[RGB_RED];  \
370                         dst[GOFFSET]=src[RGB_GREEN];  \
371                         dst[BOFFSET]=src[RGB_BLUE];  \
372                         SETALPHA  \
373                         dst+=PS;  src+=RGB_PIXELSIZE;  \
374                 }  \
375                 dst+=rowPad;  \
376         }  \
377 }
378
379 static void fromRGB(unsigned char *src, unsigned char *dst, int width,
380         int pitch, int height, int pixelFormat)
381 {
382         switch(pixelFormat)
383         {
384                 case TJPF_RGB:
385                         #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=3
386                         FROMRGB(3, 0, 1, 2,);
387                         #endif
388                         break;
389                 case TJPF_BGR:
390                         #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=3
391                         FROMRGB(3, 2, 1, 0,);
392                         #endif
393                         break;
394                 case TJPF_RGBX:
395                         #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
396                         FROMRGB(4, 0, 1, 2,);
397                         #endif
398                         break;
399                 case TJPF_RGBA:
400                         #if RGB_RED!=0 || RGB_GREEN!=1 || RGB_BLUE!=2 || RGB_PIXELSIZE!=4
401                         FROMRGB(4, 0, 1, 2, dst[3]=0xFF;);
402                         #endif
403                         break;
404                 case TJPF_BGRX:
405                         #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
406                         FROMRGB(4, 2, 1, 0,);
407                         #endif
408                         break;
409                 case TJPF_BGRA:
410                         #if RGB_RED!=2 || RGB_GREEN!=1 || RGB_BLUE!=0 || RGB_PIXELSIZE!=4
411                         FROMRGB(4, 2, 1, 0, dst[3]=0xFF;);  return;
412                         #endif
413                         break;
414                 case TJPF_XRGB:
415                         #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
416                         FROMRGB(4, 1, 2, 3,);  return;
417                         #endif
418                         break;
419                 case TJPF_ARGB:
420                         #if RGB_RED!=1 || RGB_GREEN!=2 || RGB_BLUE!=3 || RGB_PIXELSIZE!=4
421                         FROMRGB(4, 1, 2, 3, dst[0]=0xFF;);  return;
422                         #endif
423                         break;
424                 case TJPF_XBGR:
425                         #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
426                         FROMRGB(4, 3, 2, 1,);  return;
427                         #endif
428                         break;
429                 case TJPF_ABGR:
430                         #if RGB_RED!=3 || RGB_GREEN!=2 || RGB_BLUE!=1 || RGB_PIXELSIZE!=4
431                         FROMRGB(4, 3, 2, 1, dst[0]=0xFF;);  return;
432                         #endif
433                         break;
434         }
435 }
436
437 #endif
438
439
440 /* General API functions */
441
442 DLLEXPORT char* DLLCALL tjGetErrorStr(void)
443 {
444         return errStr;
445 }
446
447
448 DLLEXPORT int DLLCALL tjDestroy(tjhandle handle)
449 {
450         getinstance(handle);
451         if(setjmp(this->jerr.setjmp_buffer)) return -1;
452         if(this->init&COMPRESS) jpeg_destroy_compress(cinfo);
453         if(this->init&DECOMPRESS) jpeg_destroy_decompress(dinfo);
454         free(this);
455         return 0;
456 }
457
458
459 /* These are exposed mainly because Windows can't malloc() and free() across
460    DLL boundaries except when the CRT DLL is used, and we don't use the CRT DLL
461    with turbojpeg.dll for compatibility reasons.  However, these functions
462    can potentially be used for other purposes by different implementations. */
463
464 DLLEXPORT void DLLCALL tjFree(unsigned char *buf)
465 {
466         if(buf) free(buf);
467 }
468
469
470 DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes)
471 {
472         return (unsigned char *)malloc(bytes);
473 }
474
475
476 /* Compressor  */
477
478 static tjhandle _tjInitCompress(tjinstance *this)
479 {
480         unsigned char buffer[1], *buf=buffer;  unsigned long size=1;
481
482         /* This is also straight out of example.c */
483         this->cinfo.err=jpeg_std_error(&this->jerr.pub);
484         this->jerr.pub.error_exit=my_error_exit;
485         this->jerr.pub.output_message=my_output_message;
486
487         if(setjmp(this->jerr.setjmp_buffer))
488         {
489                 /* If we get here, the JPEG code has signaled an error. */
490                 if(this) free(this);  return NULL;
491         }
492
493         jpeg_create_compress(&this->cinfo);
494         /* Make an initial call so it will create the destination manager */
495         jpeg_mem_dest_tj(&this->cinfo, &buf, &size, 0);
496
497         this->init|=COMPRESS;
498         return (tjhandle)this;
499 }
500
501 DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
502 {
503         tjinstance *this=NULL;
504         if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
505         {
506                 snprintf(errStr, JMSG_LENGTH_MAX,
507                         "tjInitCompress(): Memory allocation failure");
508                 return NULL;
509         }
510         MEMZERO(this, sizeof(tjinstance));
511         return _tjInitCompress(this);
512 }
513
514
515 DLLEXPORT unsigned long DLLCALL tjBufSize(int width, int height,
516         int jpegSubsamp)
517 {
518         unsigned long retval=0;  int mcuw, mcuh, chromasf;
519         if(width<1 || height<1 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT)
520                 _throw("tjBufSize(): Invalid argument");
521
522         /* This allows for rare corner cases in which a JPEG image can actually be
523            larger than the uncompressed input (we wouldn't mention it if it hadn't
524            happened before.) */
525         mcuw=tjMCUWidth[jpegSubsamp];
526         mcuh=tjMCUHeight[jpegSubsamp];
527         chromasf=jpegSubsamp==TJSAMP_GRAY? 0: 4*64/(mcuw*mcuh);
528         retval=PAD(width, mcuw) * PAD(height, mcuh) * (2 + chromasf) + 2048;
529
530         bailout:
531         return retval;
532 }
533
534 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
535 {
536         unsigned long retval=0;
537         if(width<1 || height<1)
538                 _throw("TJBUFSIZE(): Invalid argument");
539
540         /* This allows for rare corner cases in which a JPEG image can actually be
541            larger than the uncompressed input (we wouldn't mention it if it hadn't
542            happened before.) */
543         retval=PAD(width, 16) * PAD(height, 16) * 6 + 2048;
544
545         bailout:
546         return retval;
547 }
548
549
550 DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height,
551         int subsamp)
552 {
553         unsigned long retval=0;
554         int pw, ph, cw, ch;
555         if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
556                 _throw("tjBufSizeYUV(): Invalid argument");
557         pw=PAD(width, tjMCUWidth[subsamp]/8);
558         ph=PAD(height, tjMCUHeight[subsamp]/8);
559         cw=pw*8/tjMCUWidth[subsamp];  ch=ph*8/tjMCUHeight[subsamp];
560         retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2);
561
562         bailout:
563         return retval;
564 }
565
566
567 DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
568         int subsamp)
569 {
570         return tjBufSizeYUV(width, height, subsamp);
571 }
572
573
574 DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
575         int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf,
576         unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
577 {
578         int i, retval=0, alloc=1;  JSAMPROW *row_pointer=NULL;
579         #ifndef JCS_EXTENSIONS
580         unsigned char *rgbBuf=NULL;
581         #endif
582
583         getinstance(handle)
584         if((this->init&COMPRESS)==0)
585                 _throw("tjCompress2(): Instance has not been initialized for compression");
586
587         if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
588                 || pixelFormat>=TJ_NUMPF || jpegBuf==NULL || jpegSize==NULL
589                 || jpegSubsamp<0 || jpegSubsamp>=NUMSUBOPT || jpegQual<0 || jpegQual>100)
590                 _throw("tjCompress2(): Invalid argument");
591
592         if(setjmp(this->jerr.setjmp_buffer))
593         {
594                 /* If we get here, the JPEG code has signaled an error. */
595                 retval=-1;
596                 goto bailout;
597         }
598
599         if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
600
601         #ifndef JCS_EXTENSIONS
602         if(pixelFormat!=TJPF_GRAY)
603         {
604                 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
605                 if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure");
606                 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
607                 pitch=width*RGB_PIXELSIZE;
608         }
609         #endif
610
611         cinfo->image_width=width;
612         cinfo->image_height=height;
613
614         if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
615         else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
616         else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
617
618         if(flags&TJFLAG_NOREALLOC)
619         {
620                 alloc=0;  *jpegSize=tjBufSize(width, height, jpegSubsamp);
621         }
622         jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
623         if(setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags)==-1)
624                 return -1;
625
626         jpeg_start_compress(cinfo, TRUE);
627         if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
628                 _throw("tjCompress2(): Memory allocation failure");
629         for(i=0; i<height; i++)
630         {
631                 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
632                 else row_pointer[i]=&srcBuf[i*pitch];
633         }
634         while(cinfo->next_scanline<cinfo->image_height)
635         {
636                 jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline],
637                         cinfo->image_height-cinfo->next_scanline);
638         }
639         jpeg_finish_compress(cinfo);
640
641         bailout:
642         if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
643         #ifndef JCS_EXTENSIONS
644         if(rgbBuf) free(rgbBuf);
645         #endif
646         if(row_pointer) free(row_pointer);
647         return retval;
648 }
649
650 DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf,
651         int width, int pitch, int height, int pixelSize, unsigned char *jpegBuf,
652         unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)
653 {
654         int retval=0;  unsigned long size;
655         if(flags&TJ_YUV)
656         {
657                 size=tjBufSizeYUV(width, height, jpegSubsamp);
658                 retval=tjEncodeYUV2(handle, srcBuf, width, pitch, height,
659                         getPixelFormat(pixelSize, flags), jpegBuf, jpegSubsamp, flags);
660         }
661         else
662         {
663                 retval=tjCompress2(handle, srcBuf, width, pitch, height,
664                         getPixelFormat(pixelSize, flags), &jpegBuf, &size, jpegSubsamp, jpegQual,
665                         flags|TJFLAG_NOREALLOC);
666         }
667         *jpegSize=size;
668         return retval;
669 }
670
671
672 DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf,
673         int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
674         int subsamp, int flags)
675 {
676         int i, retval=0;  JSAMPROW *row_pointer=NULL;
677         JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
678         JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
679         JSAMPROW *outbuf[MAX_COMPONENTS];
680         int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
681         JSAMPLE *ptr=dstBuf;
682         unsigned long yuvsize=0;
683         jpeg_component_info *compptr;
684         #ifndef JCS_EXTENSIONS
685         unsigned char *rgbBuf=NULL;
686         #endif
687
688         getinstance(handle);
689
690         for(i=0; i<MAX_COMPONENTS; i++)
691         {
692                 tmpbuf[i]=NULL;  _tmpbuf[i]=NULL;
693                 tmpbuf2[i]=NULL;  _tmpbuf2[i]=NULL;  outbuf[i]=NULL;
694         }
695
696         if((this->init&COMPRESS)==0)
697                 _throw("tjEncodeYUV2(): Instance has not been initialized for compression");
698
699         if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0
700                 || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0
701                 || subsamp>=NUMSUBOPT)
702                 _throw("tjEncodeYUV2(): Invalid argument");
703
704         if(setjmp(this->jerr.setjmp_buffer))
705         {
706                 /* If we get here, the JPEG code has signaled an error. */
707                 retval=-1;
708                 goto bailout;
709         }
710
711         if(pitch==0) pitch=width*tjPixelSize[pixelFormat];
712
713         #ifndef JCS_EXTENSIONS
714         if(pixelFormat!=TJPF_GRAY)
715         {
716                 rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE);
717                 if(!rgbBuf) _throw("tjEncodeYUV2(): Memory allocation failure");
718                 srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf);
719                 pitch=width*RGB_PIXELSIZE;
720         }
721         #endif
722
723         cinfo->image_width=width;
724         cinfo->image_height=height;
725
726         if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
727         else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
728         else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
729
730         yuvsize=tjBufSizeYUV(width, height, subsamp);
731         if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
732
733         /* Execute only the parts of jpeg_start_compress() that we need.  If we
734            were to call the whole jpeg_start_compress() function, then it would try
735            to write the file headers, which could overflow the output buffer if the
736            YUV image were very small. */
737         if(cinfo->global_state!=CSTATE_START)
738                 _throw("tjEncodeYUV3(): libjpeg API is in the wrong state");
739         (*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
740         jinit_c_master_control(cinfo, FALSE);
741         jinit_color_converter(cinfo);
742         jinit_downsampler(cinfo);
743         (*cinfo->cconvert->start_pass)(cinfo);
744
745         pw=PAD(width, cinfo->max_h_samp_factor);
746         ph=PAD(height, cinfo->max_v_samp_factor);
747
748         if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
749                 _throw("tjEncodeYUV2(): Memory allocation failure");
750         for(i=0; i<height; i++)
751         {
752                 if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
753                 else row_pointer[i]=&srcBuf[i*pitch];
754         }
755         if(height<ph)
756                 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
757
758         for(i=0; i<cinfo->num_components; i++)
759         {
760                 compptr=&cinfo->comp_info[i];
761                 _tmpbuf[i]=(JSAMPLE *)malloc(
762                         PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
763                                 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
764                 if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
765                 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
766                 if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
767                 for(row=0; row<cinfo->max_v_samp_factor; row++)
768                 {
769                         unsigned char *_tmpbuf_aligned=
770                                 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
771                         tmpbuf[i][row]=&_tmpbuf_aligned[
772                                 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
773                                         /compptr->h_samp_factor, 16) * row];
774                 }
775                 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
776                         * compptr->v_samp_factor + 16);
777                 if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
778                 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
779                 if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
780                 for(row=0; row<compptr->v_samp_factor; row++)
781                 {
782                         unsigned char *_tmpbuf2_aligned=
783                                 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
784                         tmpbuf2[i][row]=&_tmpbuf2_aligned[
785                                 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
786                 }
787                 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
788                 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
789                 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
790                 if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure");
791                 for(row=0; row<ch[i]; row++)
792                 {
793                         outbuf[i][row]=ptr;
794                         ptr+=PAD(cw[i], 4);
795                 }
796         }
797         if(yuvsize!=(unsigned long)(ptr-dstBuf))
798                 _throw("tjEncodeYUV2(): Generated image is not the correct size");
799
800         for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
801         {
802                 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0,
803                         cinfo->max_v_samp_factor);
804                 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
805                 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++)
806                         jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
807                                 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
808                                 compptr->v_samp_factor, cw[i]);
809         }
810         cinfo->next_scanline+=height;
811         jpeg_abort_compress(cinfo);
812
813         bailout:
814         if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
815         #ifndef JCS_EXTENSIONS
816         if(rgbBuf) free(rgbBuf);
817         #endif
818         if(row_pointer) free(row_pointer);
819         for(i=0; i<MAX_COMPONENTS; i++)
820         {
821                 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
822                 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
823                 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
824                 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
825                 if(outbuf[i]!=NULL) free(outbuf[i]);
826         }
827         return retval;
828 }
829
830 DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
831         int width, int pitch, int height, int pixelSize, unsigned char *dstBuf,
832         int subsamp, int flags)
833 {
834         return tjEncodeYUV2(handle, srcBuf, width, pitch, height,
835                 getPixelFormat(pixelSize, flags), dstBuf, subsamp, flags);
836 }
837
838
839 /* Decompressor */
840
841 static tjhandle _tjInitDecompress(tjinstance *this)
842 {
843         unsigned char buffer[1];
844
845         /* This is also straight out of example.c */
846         this->dinfo.err=jpeg_std_error(&this->jerr.pub);
847         this->jerr.pub.error_exit=my_error_exit;
848         this->jerr.pub.output_message=my_output_message;
849
850         if(setjmp(this->jerr.setjmp_buffer))
851         {
852                 /* If we get here, the JPEG code has signaled an error. */
853                 if(this) free(this);  return NULL;
854         }
855
856         jpeg_create_decompress(&this->dinfo);
857         /* Make an initial call so it will create the source manager */
858         jpeg_mem_src_tj(&this->dinfo, buffer, 1);
859
860         this->init|=DECOMPRESS;
861         return (tjhandle)this;
862 }
863
864 DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
865 {
866         tjinstance *this;
867         if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
868         {
869                 snprintf(errStr, JMSG_LENGTH_MAX,
870                         "tjInitDecompress(): Memory allocation failure");
871                 return NULL;
872         }
873         MEMZERO(this, sizeof(tjinstance));
874         return _tjInitDecompress(this);
875 }
876
877
878 DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle,
879         unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
880         int *jpegSubsamp)
881 {
882         int retval=0;
883
884         getinstance(handle);
885         if((this->init&DECOMPRESS)==0)
886                 _throw("tjDecompressHeader2(): Instance has not been initialized for decompression");
887
888         if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL
889                 || jpegSubsamp==NULL)
890                 _throw("tjDecompressHeader2(): Invalid argument");
891
892         if(setjmp(this->jerr.setjmp_buffer))
893         {
894                 /* If we get here, the JPEG code has signaled an error. */
895                 return -1;
896         }
897
898         jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
899         jpeg_read_header(dinfo, TRUE);
900
901         *width=dinfo->image_width;
902         *height=dinfo->image_height;
903         *jpegSubsamp=getSubsamp(dinfo);
904
905         jpeg_abort_decompress(dinfo);
906
907         if(*jpegSubsamp<0)
908                 _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image");
909         if(*width<1 || *height<1)
910                 _throw("tjDecompressHeader2(): Invalid data returned in header");
911
912         bailout:
913         return retval;
914 }
915
916 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle,
917         unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height)
918 {
919         int jpegSubsamp;
920         return tjDecompressHeader2(handle, jpegBuf, jpegSize, width, height,
921                 &jpegSubsamp);
922 }
923
924
925 DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
926 {
927         if(numscalingfactors==NULL)
928         {
929                 snprintf(errStr, JMSG_LENGTH_MAX,
930                         "tjGetScalingFactors(): Invalid argument");
931                 return NULL;
932         }
933
934         *numscalingfactors=NUMSF;
935         return (tjscalingfactor *)sf;
936 }
937
938
939 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
940         unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
941         int height, int pixelFormat, int flags)
942 {
943         int i, retval=0;  JSAMPROW *row_pointer=NULL;
944         int jpegwidth, jpegheight, scaledw, scaledh;
945         #ifndef JCS_EXTENSIONS
946         unsigned char *rgbBuf=NULL;
947         unsigned char *_dstBuf=NULL;  int _pitch=0;
948         #endif
949
950         getinstance(handle);
951         if((this->init&DECOMPRESS)==0)
952                 _throw("tjDecompress2(): Instance has not been initialized for decompression");
953
954         if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pitch<0
955                 || height<0 || pixelFormat<0 || pixelFormat>=TJ_NUMPF)
956                 _throw("tjDecompress2(): Invalid argument");
957
958         if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
959         else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
960         else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
961
962         if(setjmp(this->jerr.setjmp_buffer))
963         {
964                 /* If we get here, the JPEG code has signaled an error. */
965                 retval=-1;
966                 goto bailout;
967         }
968
969         jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
970         jpeg_read_header(dinfo, TRUE);
971         if(setDecompDefaults(dinfo, pixelFormat, flags)==-1)
972         {
973                 retval=-1;  goto bailout;
974         }
975
976         if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
977
978         jpegwidth=dinfo->image_width;  jpegheight=dinfo->image_height;
979         if(width==0) width=jpegwidth;
980         if(height==0) height=jpegheight;
981         for(i=0; i<NUMSF; i++)
982         {
983                 scaledw=TJSCALED(jpegwidth, sf[i]);
984                 scaledh=TJSCALED(jpegheight, sf[i]);
985                 if(scaledw<=width && scaledh<=height)
986                         break;
987         }
988         if(scaledw>width || scaledh>height)
989                 _throw("tjDecompress2(): Could not scale down to desired image dimensions");
990         width=scaledw;  height=scaledh;
991         dinfo->scale_num=sf[i].num;
992         dinfo->scale_denom=sf[i].denom;
993
994         jpeg_start_decompress(dinfo);
995         if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat];
996
997         #ifndef JCS_EXTENSIONS
998         if(pixelFormat!=TJPF_GRAY &&
999                 (RGB_RED!=tjRedOffset[pixelFormat] ||
1000                         RGB_GREEN!=tjGreenOffset[pixelFormat] ||
1001                         RGB_BLUE!=tjBlueOffset[pixelFormat] ||
1002                         RGB_PIXELSIZE!=tjPixelSize[pixelFormat]))
1003         {
1004                 rgbBuf=(unsigned char *)malloc(width*height*3);
1005                 if(!rgbBuf) _throw("tjDecompress2(): Memory allocation failure");
1006                 _pitch=pitch;  pitch=width*3;
1007                 _dstBuf=dstBuf;  dstBuf=rgbBuf;
1008         }
1009         #endif
1010
1011         if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
1012                 *dinfo->output_height))==NULL)
1013                 _throw("tjDecompress2(): Memory allocation failure");
1014         for(i=0; i<(int)dinfo->output_height; i++)
1015         {
1016                 if(flags&TJFLAG_BOTTOMUP)
1017                         row_pointer[i]=&dstBuf[(dinfo->output_height-i-1)*pitch];
1018                 else row_pointer[i]=&dstBuf[i*pitch];
1019         }
1020         while(dinfo->output_scanline<dinfo->output_height)
1021         {
1022                 jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline],
1023                         dinfo->output_height-dinfo->output_scanline);
1024         }
1025         jpeg_finish_decompress(dinfo);
1026
1027         #ifndef JCS_EXTENSIONS
1028         fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat);
1029         #endif
1030
1031         bailout:
1032         if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1033         #ifndef JCS_EXTENSIONS
1034         if(rgbBuf) free(rgbBuf);
1035         #endif
1036         if(row_pointer) free(row_pointer);
1037         return retval;
1038 }
1039
1040 DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf,
1041         unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
1042         int height, int pixelSize, int flags)
1043 {
1044         if(flags&TJ_YUV)
1045                 return tjDecompressToYUV(handle, jpegBuf, jpegSize, dstBuf, flags);
1046         else
1047                 return tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, width, pitch,
1048                         height, getPixelFormat(pixelSize, flags), flags);
1049 }
1050
1051
1052 DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle,
1053         unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
1054         int flags)
1055 {
1056         int i, row, retval=0;  JSAMPROW *outbuf[MAX_COMPONENTS];
1057         int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
1058                 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
1059         JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
1060
1061         getinstance(handle);
1062
1063         for(i=0; i<MAX_COMPONENTS; i++)
1064         {
1065                 tmpbuf[i]=NULL;  outbuf[i]=NULL;
1066         }
1067
1068         if((this->init&DECOMPRESS)==0)
1069                 _throw("tjDecompressToYUV(): Instance has not been initialized for decompression");
1070
1071         if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL)
1072                 _throw("tjDecompressToYUV(): Invalid argument");
1073
1074         if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1075         else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1076         else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1077
1078         if(setjmp(this->jerr.setjmp_buffer))
1079         {
1080                 /* If we get here, the JPEG code has signaled an error. */
1081                 retval=-1;
1082                 goto bailout;
1083         }
1084
1085         jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1086         jpeg_read_header(dinfo, TRUE);
1087
1088         for(i=0; i<dinfo->num_components; i++)
1089         {
1090                 jpeg_component_info *compptr=&dinfo->comp_info[i];
1091                 int ih;
1092                 iw[i]=compptr->width_in_blocks*DCTSIZE;
1093                 ih=compptr->height_in_blocks*DCTSIZE;
1094                 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
1095                         *compptr->h_samp_factor/dinfo->max_h_samp_factor;
1096                 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
1097                         *compptr->v_samp_factor/dinfo->max_v_samp_factor;
1098                 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
1099                 th[i]=compptr->v_samp_factor*DCTSIZE;
1100                 tmpbufsize+=iw[i]*th[i];
1101                 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
1102                         _throw("tjDecompressToYUV(): Memory allocation failure");
1103                 for(row=0; row<ch[i]; row++)
1104                 {
1105                         outbuf[i][row]=ptr;
1106                         ptr+=PAD(cw[i], 4);
1107                 }
1108         }
1109         if(usetmpbuf)
1110         {
1111                 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
1112                         _throw("tjDecompressToYUV(): Memory allocation failure");
1113                 ptr=_tmpbuf;
1114                 for(i=0; i<dinfo->num_components; i++)
1115                 {
1116                         if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
1117                                 _throw("tjDecompressToYUV(): Memory allocation failure");
1118                         for(row=0; row<th[i]; row++)
1119                         {
1120                                 tmpbuf[i][row]=ptr;
1121                                 ptr+=iw[i];
1122                         }
1123                 }
1124         }
1125
1126         if(flags&TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling=FALSE;
1127         if(flags&TJFLAG_FASTDCT) dinfo->dct_method=JDCT_FASTEST;
1128         dinfo->raw_data_out=TRUE;
1129
1130         jpeg_start_decompress(dinfo);
1131         for(row=0; row<(int)dinfo->output_height;
1132                 row+=dinfo->max_v_samp_factor*DCTSIZE)
1133         {
1134                 JSAMPARRAY yuvptr[MAX_COMPONENTS];
1135                 int crow[MAX_COMPONENTS];
1136                 for(i=0; i<dinfo->num_components; i++)
1137                 {
1138                         jpeg_component_info *compptr=&dinfo->comp_info[i];
1139                         crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
1140                         if(usetmpbuf) yuvptr[i]=tmpbuf[i];
1141                         else yuvptr[i]=&outbuf[i][crow[i]];
1142                 }
1143                 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
1144                 if(usetmpbuf)
1145                 {
1146                         int j;
1147                         for(i=0; i<dinfo->num_components; i++)
1148                         {
1149                                 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
1150                                 {
1151                                         memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
1152                                 }
1153                         }
1154                 }
1155         }
1156         jpeg_finish_decompress(dinfo);
1157
1158         bailout:
1159         if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1160         for(i=0; i<MAX_COMPONENTS; i++)
1161         {
1162                 if(tmpbuf[i]) free(tmpbuf[i]);
1163                 if(outbuf[i]) free(outbuf[i]);
1164         }
1165         if(_tmpbuf) free(_tmpbuf);
1166         return retval;
1167 }
1168
1169
1170 /* Transformer */
1171
1172 DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
1173 {
1174         tjinstance *this=NULL;  tjhandle handle=NULL;
1175         if((this=(tjinstance *)malloc(sizeof(tjinstance)))==NULL)
1176         {
1177                 snprintf(errStr, JMSG_LENGTH_MAX,
1178                         "tjInitTransform(): Memory allocation failure");
1179                 return NULL;
1180         }
1181         MEMZERO(this, sizeof(tjinstance));
1182         handle=_tjInitCompress(this);
1183         if(!handle) return NULL;
1184         handle=_tjInitDecompress(this);
1185         return handle;
1186 }
1187
1188
1189 DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
1190         unsigned long jpegSize, int n, unsigned char **dstBufs,
1191         unsigned long *dstSizes, tjtransform *t, int flags)
1192 {
1193         jpeg_transform_info *xinfo=NULL;
1194         jvirt_barray_ptr *srccoefs, *dstcoefs;
1195         int retval=0, i, jpegSubsamp;
1196
1197         getinstance(handle);
1198         if((this->init&COMPRESS)==0 || (this->init&DECOMPRESS)==0)
1199                 _throw("tjTransform(): Instance has not been initialized for transformation");
1200
1201         if(jpegBuf==NULL || jpegSize<=0 || n<1 || dstBufs==NULL || dstSizes==NULL
1202                 || t==NULL || flags<0)
1203                 _throw("tjTransform(): Invalid argument");
1204
1205         if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
1206         else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
1207         else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
1208
1209         if(setjmp(this->jerr.setjmp_buffer))
1210         {
1211                 /* If we get here, the JPEG code has signaled an error. */
1212                 retval=-1;
1213                 goto bailout;
1214         }
1215
1216         jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
1217
1218         if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
1219                 ==NULL)
1220                 _throw("tjTransform(): Memory allocation failure");
1221         MEMZERO(xinfo, sizeof(jpeg_transform_info)*n);
1222
1223         for(i=0; i<n; i++)
1224         {
1225                 xinfo[i].transform=xformtypes[t[i].op];
1226                 xinfo[i].perfect=(t[i].options&TJXOPT_PERFECT)? 1:0;
1227                 xinfo[i].trim=(t[i].options&TJXOPT_TRIM)? 1:0;
1228                 xinfo[i].force_grayscale=(t[i].options&TJXOPT_GRAY)? 1:0;
1229                 xinfo[i].crop=(t[i].options&TJXOPT_CROP)? 1:0;
1230                 if(n!=1 && t[i].op==TJXOP_HFLIP) xinfo[i].slow_hflip=1;
1231                 else xinfo[i].slow_hflip=0;
1232
1233                 if(xinfo[i].crop)
1234                 {
1235                         xinfo[i].crop_xoffset=t[i].r.x;  xinfo[i].crop_xoffset_set=JCROP_POS;
1236                         xinfo[i].crop_yoffset=t[i].r.y;  xinfo[i].crop_yoffset_set=JCROP_POS;
1237                         if(t[i].r.w!=0)
1238                         {
1239                                 xinfo[i].crop_width=t[i].r.w;  xinfo[i].crop_width_set=JCROP_POS;
1240                         }
1241                         else xinfo[i].crop_width=JCROP_UNSET;
1242                         if(t[i].r.h!=0)
1243                         {
1244                                 xinfo[i].crop_height=t[i].r.h;  xinfo[i].crop_height_set=JCROP_POS;
1245                         }
1246                         else xinfo[i].crop_height=JCROP_UNSET;
1247                 }
1248         }
1249
1250         jcopy_markers_setup(dinfo, JCOPYOPT_ALL);
1251         jpeg_read_header(dinfo, TRUE);
1252         jpegSubsamp=getSubsamp(dinfo);
1253         if(jpegSubsamp<0)
1254                 _throw("tjTransform(): Could not determine subsampling type for JPEG image");
1255
1256         for(i=0; i<n; i++)
1257         {
1258                 if(!jtransform_request_workspace(dinfo, &xinfo[i]))
1259                         _throw("tjTransform(): Transform is not perfect");
1260
1261                 if(xinfo[i].crop)
1262                 {
1263                         if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
1264                                 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
1265                         {
1266                                 snprintf(errStr, JMSG_LENGTH_MAX,
1267                                         "To crop this JPEG image, x must be a multiple of %d\n"
1268                                         "and y must be a multiple of %d.\n",
1269                                         xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
1270                                 retval=-1;  goto bailout;
1271                         }
1272                 }
1273         }
1274
1275         srccoefs=jpeg_read_coefficients(dinfo);
1276
1277         for(i=0; i<n; i++)
1278         {
1279                 int w, h, alloc=1;
1280                 if(!xinfo[i].crop)
1281                 {
1282                         w=dinfo->image_width;  h=dinfo->image_height;
1283                 }
1284                 else
1285                 {
1286                         w=xinfo[i].crop_width;  h=xinfo[i].crop_height;
1287                 }
1288                 if(flags&TJFLAG_NOREALLOC)
1289                 {
1290                         alloc=0;  dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
1291                 }
1292                 if(!(t[i].options&TJXOPT_NOOUTPUT))
1293                         jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
1294                 jpeg_copy_critical_parameters(dinfo, cinfo);
1295                 dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
1296                         &xinfo[i]);
1297                 if(!(t[i].options&TJXOPT_NOOUTPUT))
1298                 {
1299                         jpeg_write_coefficients(cinfo, dstcoefs);
1300                         jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
1301                 }
1302                 else jinit_c_master_control(cinfo, TRUE);
1303                 jtransform_execute_transformation(dinfo, cinfo, srccoefs,
1304                         &xinfo[i]);
1305                 if(t[i].customFilter)
1306                 {
1307                         int ci, y;  JDIMENSION by;
1308                         for(ci=0; ci<cinfo->num_components; ci++)
1309                         {
1310                                 jpeg_component_info *compptr=&cinfo->comp_info[ci];
1311                                 tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1312                                         DCTSIZE};
1313                                 tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
1314                                         compptr->height_in_blocks*DCTSIZE};
1315                                 for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
1316                                 {
1317                                         JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
1318                                                 ((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
1319                                                 TRUE);
1320                                         for(y=0; y<compptr->v_samp_factor; y++)
1321                                         {
1322                                                 if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
1323                                                         ci, i, &t[i])==-1)
1324                                                         _throw("tjTransform(): Error in custom filter");
1325                                                 arrayRegion.y+=DCTSIZE;
1326                                         }
1327                                 }
1328                         }
1329                 }
1330                 if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
1331         }
1332
1333         jpeg_finish_decompress(dinfo);
1334
1335         bailout:
1336         if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
1337         if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo);
1338         if(xinfo) free(xinfo);
1339         return retval;
1340 }