blob: 4755144e044b0db3cbcc039eae4c11df6d438180 [file] [log] [blame]
DRC2e7b76b2009-04-03 12:04:24 +00001/* Copyright (C)2004 Landmark Graphics Corporation
2 * Copyright (C)2005 Sun Microsystems, Inc.
DRC91e86ba2011-02-15 05:24:08 +00003 * Copyright (C)2009-2011 D. R. Commander
DRC2e7b76b2009-04-03 12:04:24 +00004 *
5 * This library is free software and may be redistributed and/or modified under
6 * the terms of the wxWindows Library License, Version 3.1 or (at your option)
7 * any later version. The full license is in the LICENSE.txt file included
8 * with this distribution.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * wxWindows Library License for more details.
14 */
15
16// This implements a JPEG compressor/decompressor using the libjpeg API
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
DRCfbb67472010-11-24 04:02:37 +000021#define JPEG_INTERNALS
DRC2e7b76b2009-04-03 12:04:24 +000022#include <jpeglib.h>
23#include <jerror.h>
24#include <setjmp.h>
25#include "./turbojpeg.h"
DRC890f1e02011-02-26 22:02:37 +000026#include "transupp.h"
DRC2a2e4512011-01-05 22:33:24 +000027
DRCfbb67472010-11-24 04:02:37 +000028#ifndef min
29 #define min(a,b) ((a)<(b)?(a):(b))
30#endif
31
32#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
DRC2e7b76b2009-04-03 12:04:24 +000033
34
35// Error handling
36
37static char lasterror[JMSG_LENGTH_MAX]="No error";
38
39typedef struct _error_mgr
40{
41 struct jpeg_error_mgr pub;
42 jmp_buf jb;
43} error_mgr;
44
45static void my_error_exit(j_common_ptr cinfo)
46{
47 error_mgr *myerr = (error_mgr *)cinfo->err;
48 (*cinfo->err->output_message)(cinfo);
49 longjmp(myerr->jb, 1);
50}
51
52static void my_output_message(j_common_ptr cinfo)
53{
54 (*cinfo->err->format_message)(cinfo, lasterror);
55}
56
57
58// Global structures, macros, etc.
59
60typedef struct _jpgstruct
61{
62 struct jpeg_compress_struct cinfo;
63 struct jpeg_decompress_struct dinfo;
64 struct jpeg_destination_mgr jdms;
65 struct jpeg_source_mgr jsms;
66 error_mgr jerr;
67 int initc, initd;
68} jpgstruct;
69
70static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1};
71static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1};
DRC1fe80f82010-12-14 01:21:29 +000072static const int pixelsize[NUMSUBOPT]={3, 3, 3, 1};
DRC890f1e02011-02-26 22:02:37 +000073static const JXFORM_CODE xformtypes[NUMXFORMOPT]={
74 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
75 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
76};
DRC2e7b76b2009-04-03 12:04:24 +000077
DRC91e86ba2011-02-15 05:24:08 +000078#define _throw(c) {sprintf(lasterror, "%s", c); retval=-1; goto bailout;}
DRC2e7b76b2009-04-03 12:04:24 +000079#define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
DRC91e86ba2011-02-15 05:24:08 +000080 if(!j) {sprintf(lasterror, "Invalid handle"); return -1;}
DRC2e7b76b2009-04-03 12:04:24 +000081
82
83// CO
84
85static boolean empty_output_buffer(struct jpeg_compress_struct *cinfo)
86{
87 ERREXIT(cinfo, JERR_BUFFER_SIZE);
88 return TRUE;
89}
90
91static void destination_noop(struct jpeg_compress_struct *cinfo)
92{
93}
94
DRC890f1e02011-02-26 22:02:37 +000095static tjhandle _tjInitCompress(jpgstruct *j)
DRC2e7b76b2009-04-03 12:04:24 +000096{
DRC2e7b76b2009-04-03 12:04:24 +000097 j->cinfo.err=jpeg_std_error(&j->jerr.pub);
98 j->jerr.pub.error_exit=my_error_exit;
99 j->jerr.pub.output_message=my_output_message;
100
101 if(setjmp(j->jerr.jb))
102 { // this will execute if LIBJPEG has an error
103 if(j) free(j); return NULL;
DRCefa4ddc2010-10-13 19:22:50 +0000104 }
DRC2e7b76b2009-04-03 12:04:24 +0000105
106 jpeg_create_compress(&j->cinfo);
107 j->cinfo.dest=&j->jdms;
108 j->jdms.init_destination=destination_noop;
109 j->jdms.empty_output_buffer=empty_output_buffer;
110 j->jdms.term_destination=destination_noop;
111
112 j->initc=1;
113 return (tjhandle)j;
114}
115
DRC890f1e02011-02-26 22:02:37 +0000116DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
117{
118 jpgstruct *j=NULL;
119 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
120 {sprintf(lasterror, "Memory allocation failure"); return NULL;}
121 memset(j, 0, sizeof(jpgstruct));
122 return _tjInitCompress(j);
123}
124
DRC84241602011-02-25 02:08:23 +0000125
DRC2e7b76b2009-04-03 12:04:24 +0000126DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
127{
DRCf3cf9732011-02-22 00:16:14 +0000128 unsigned long retval=0;
129 if(width<1 || height<1)
130 _throw("Invalid argument in TJBUFSIZE()");
131
132 // This allows for rare corner cases in which a JPEG image can actually be
133 // larger than the uncompressed input (we wouldn't mention it if it hadn't
DRCb28fc572011-02-22 06:41:29 +0000134 // happened before.)
DRCf3cf9732011-02-22 00:16:14 +0000135 retval=((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
136
137 bailout:
138 return retval;
139}
140
DRC84241602011-02-25 02:08:23 +0000141
DRCf3cf9732011-02-22 00:16:14 +0000142DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
143 int subsamp)
144{
145 unsigned long retval=0;
146 int pw, ph, cw, ch;
147 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
148 _throw("Invalid argument in TJBUFSIZEYUV()");
149 pw=PAD(width, hsampfactor[subsamp]);
150 ph=PAD(height, vsampfactor[subsamp]);
151 cw=pw/hsampfactor[subsamp]; ch=ph/vsampfactor[subsamp];
152 retval=PAD(pw, 4)*ph + (subsamp==TJ_GRAYSCALE? 0:PAD(cw, 4)*ch*2);
153
154 bailout:
155 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000156}
157
DRC84241602011-02-25 02:08:23 +0000158
DRC2e7b76b2009-04-03 12:04:24 +0000159DLLEXPORT int DLLCALL tjCompress(tjhandle h,
160 unsigned char *srcbuf, int width, int pitch, int height, int ps,
161 unsigned char *dstbuf, unsigned long *size,
162 int jpegsub, int qual, int flags)
163{
DRC91e86ba2011-02-15 05:24:08 +0000164 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000165 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
166 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
167 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC2e7b76b2009-04-03 12:04:24 +0000168
169 checkhandle(h);
170
DRCfbb67472010-11-24 04:02:37 +0000171 for(i=0; i<MAX_COMPONENTS; i++)
172 {
173 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
174 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
175 }
176
DRC2e7b76b2009-04-03 12:04:24 +0000177 if(srcbuf==NULL || width<=0 || pitch<0 || height<=0
178 || dstbuf==NULL || size==NULL
179 || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100)
180 _throw("Invalid argument in tjCompress()");
DRC09854f52010-11-04 22:39:59 +0000181 if(ps!=3 && ps!=4 && ps!=1)
182 _throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input");
DRC2e7b76b2009-04-03 12:04:24 +0000183 if(!j->initc) _throw("Instance has not been initialized for compression");
184
185 if(pitch==0) pitch=width*ps;
186
187 j->cinfo.image_width = width;
188 j->cinfo.image_height = height;
189 j->cinfo.input_components = ps;
190
DRC09854f52010-11-04 22:39:59 +0000191 if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE;
DRC2e7b76b2009-04-03 12:04:24 +0000192 #if JCS_EXTENSIONS==1
DRC09854f52010-11-04 22:39:59 +0000193 else j->cinfo.in_color_space = JCS_EXT_RGB;
DRC2e7b76b2009-04-03 12:04:24 +0000194 if(ps==3 && (flags&TJ_BGR))
195 j->cinfo.in_color_space = JCS_EXT_BGR;
196 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
197 j->cinfo.in_color_space = JCS_EXT_RGBX;
198 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
199 j->cinfo.in_color_space = JCS_EXT_BGRX;
200 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
201 j->cinfo.in_color_space = JCS_EXT_XBGR;
202 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
203 j->cinfo.in_color_space = JCS_EXT_XRGB;
204 #else
205 #error "TurboJPEG requires JPEG colorspace extensions"
206 #endif
207
DRC0c6a2712010-02-22 08:34:44 +0000208 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
209 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
210 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
211
DRC2e7b76b2009-04-03 12:04:24 +0000212 if(setjmp(j->jerr.jb))
213 { // this will execute if LIBJPEG has an error
DRC91e86ba2011-02-15 05:24:08 +0000214 retval=-1;
215 goto bailout;
DRCefa4ddc2010-10-13 19:22:50 +0000216 }
DRC2e7b76b2009-04-03 12:04:24 +0000217
218 jpeg_set_defaults(&j->cinfo);
219
220 jpeg_set_quality(&j->cinfo, qual, TRUE);
221 if(jpegsub==TJ_GRAYSCALE)
222 jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE);
223 else
224 jpeg_set_colorspace(&j->cinfo, JCS_YCbCr);
DRCe1716b82011-02-18 03:19:43 +0000225 if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW;
226 else j->cinfo.dct_method=JDCT_FASTEST;
DRC2e7b76b2009-04-03 12:04:24 +0000227
228 j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub];
229 j->cinfo.comp_info[1].h_samp_factor=1;
230 j->cinfo.comp_info[2].h_samp_factor=1;
231 j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub];
232 j->cinfo.comp_info[1].v_samp_factor=1;
233 j->cinfo.comp_info[2].v_samp_factor=1;
234
235 j->jdms.next_output_byte = dstbuf;
236 j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height);
237
DRC2e7b76b2009-04-03 12:04:24 +0000238 jpeg_start_compress(&j->cinfo, TRUE);
DRCfbb67472010-11-24 04:02:37 +0000239 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000240 {
DRCfbb67472010-11-24 04:02:37 +0000241 j_compress_ptr cinfo=&j->cinfo;
242 int row;
243 int pw=PAD(width, cinfo->max_h_samp_factor);
244 int ph=PAD(height, cinfo->max_v_samp_factor);
245 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
246 jpeg_component_info *compptr;
247 JSAMPLE *ptr=dstbuf; unsigned long yuvsize=0;
248
249 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
250 _throw("Memory allocation failed in tjCompress()");
251 for(i=0; i<height; i++)
252 {
253 if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
254 else row_pointer[i]= &srcbuf[i*pitch];
255 }
256 if(height<ph)
257 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
258
259 for(i=0; i<cinfo->num_components; i++)
260 {
261 compptr=&cinfo->comp_info[i];
DRC57423072011-01-05 23:35:53 +0000262 _tmpbuf[i]=(JSAMPLE *)malloc(
DRCfbb67472010-11-24 04:02:37 +0000263 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC57423072011-01-05 23:35:53 +0000264 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRCfbb67472010-11-24 04:02:37 +0000265 if(!_tmpbuf[i]) _throw("Memory allocation failure");
DRC2a2e4512011-01-05 22:33:24 +0000266 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCfbb67472010-11-24 04:02:37 +0000267 if(!tmpbuf[i]) _throw("Memory allocation failure");
268 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRC57423072011-01-05 23:35:53 +0000269 {
270 unsigned char *_tmpbuf_aligned=
271 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
272 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000273 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
274 /compptr->h_samp_factor, 16) * row];
DRC57423072011-01-05 23:35:53 +0000275 }
276 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
277 * compptr->v_samp_factor + 16);
DRCfbb67472010-11-24 04:02:37 +0000278 if(!_tmpbuf2[i]) _throw("Memory allocation failure");
DRC2a2e4512011-01-05 22:33:24 +0000279 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCfbb67472010-11-24 04:02:37 +0000280 if(!tmpbuf2[i]) _throw("Memory allocation failure");
281 for(row=0; row<compptr->v_samp_factor; row++)
DRC57423072011-01-05 23:35:53 +0000282 {
283 unsigned char *_tmpbuf2_aligned=
284 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
285 tmpbuf2[i][row]=&_tmpbuf2_aligned[
DRCfbb67472010-11-24 04:02:37 +0000286 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
DRC57423072011-01-05 23:35:53 +0000287 }
DRCfbb67472010-11-24 04:02:37 +0000288 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
289 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
DRC2a2e4512011-01-05 22:33:24 +0000290 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
DRCfbb67472010-11-24 04:02:37 +0000291 if(!outbuf[i]) _throw("Memory allocation failure");
292 for(row=0; row<ch[i]; row++)
293 {
294 outbuf[i][row]=ptr;
295 ptr+=PAD(cw[i], 4);
296 }
297 }
298 yuvsize=(unsigned long)(ptr-dstbuf);
299
300 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
301 {
302 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf,
303 0, cinfo->max_v_samp_factor);
304 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
305 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components;
306 i++, compptr++)
307 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
308 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
309 compptr->v_samp_factor, cw[i]);
310 }
311 *size=yuvsize;
312 cinfo->next_scanline+=height;
313 }
314 else
315 {
316 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
317 _throw("Memory allocation failed in tjCompress()");
318 for(i=0; i<height; i++)
319 {
320 if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
321 else row_pointer[i]= &srcbuf[i*pitch];
322 }
323 while(j->cinfo.next_scanline<j->cinfo.image_height)
324 {
325 jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
326 j->cinfo.image_height-j->cinfo.next_scanline);
327 }
DRC2e7b76b2009-04-03 12:04:24 +0000328 }
329 jpeg_finish_compress(&j->cinfo);
DRCfbb67472010-11-24 04:02:37 +0000330 if(!(flags&TJ_YUV))
331 *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)
332 -(unsigned long)(j->jdms.free_in_buffer);
DRC2e7b76b2009-04-03 12:04:24 +0000333
DRC91e86ba2011-02-15 05:24:08 +0000334 bailout:
DRCb28fc572011-02-22 06:41:29 +0000335 if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000336 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000337 for(i=0; i<MAX_COMPONENTS; i++)
338 {
339 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000340 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000341 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000342 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000343 if(outbuf[i]!=NULL) free(outbuf[i]);
344 }
DRC91e86ba2011-02-15 05:24:08 +0000345 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000346}
347
348
DRC84241602011-02-25 02:08:23 +0000349DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle h,
350 unsigned char *srcbuf, int width, int pitch, int height, int ps,
351 unsigned char *dstbuf, int subsamp, int flags)
352{
353 unsigned long size;
354 return tjCompress(h, srcbuf, width, pitch, height, ps, dstbuf, &size,
355 subsamp, 0, flags|TJ_YUV);
356}
357
358
DRC2e7b76b2009-04-03 12:04:24 +0000359// DEC
360
361static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo)
362{
363 ERREXIT(dinfo, JERR_BUFFER_SIZE);
364 return TRUE;
365}
366
367static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes)
368{
369 dinfo->src->next_input_byte += (size_t) num_bytes;
370 dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
371}
372
373static void source_noop (struct jpeg_decompress_struct *dinfo)
374{
375}
376
DRC890f1e02011-02-26 22:02:37 +0000377static tjhandle _tjInitDecompress(jpgstruct *j)
DRC2e7b76b2009-04-03 12:04:24 +0000378{
DRC2e7b76b2009-04-03 12:04:24 +0000379 j->dinfo.err=jpeg_std_error(&j->jerr.pub);
380 j->jerr.pub.error_exit=my_error_exit;
381 j->jerr.pub.output_message=my_output_message;
382
383 if(setjmp(j->jerr.jb))
384 { // this will execute if LIBJPEG has an error
385 free(j); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +0000386 }
DRC2e7b76b2009-04-03 12:04:24 +0000387
388 jpeg_create_decompress(&j->dinfo);
389 j->dinfo.src=&j->jsms;
390 j->jsms.init_source=source_noop;
391 j->jsms.fill_input_buffer = fill_input_buffer;
392 j->jsms.skip_input_data = skip_input_data;
393 j->jsms.resync_to_restart = jpeg_resync_to_restart;
394 j->jsms.term_source = source_noop;
395
396 j->initd=1;
397 return (tjhandle)j;
398}
399
DRC890f1e02011-02-26 22:02:37 +0000400DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
401{
402 jpgstruct *j;
403 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
404 {sprintf(lasterror, "Memory allocation failure"); return NULL;}
405 memset(j, 0, sizeof(jpgstruct));
406 return _tjInitDecompress(j);
407}
408
DRC2e7b76b2009-04-03 12:04:24 +0000409
DRC1fe80f82010-12-14 01:21:29 +0000410DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle h,
411 unsigned char *srcbuf, unsigned long size,
412 int *width, int *height, int *jpegsub)
413{
DRC91e86ba2011-02-15 05:24:08 +0000414 int i, k, retval=0;
DRC1fe80f82010-12-14 01:21:29 +0000415
416 checkhandle(h);
417
418 if(srcbuf==NULL || size<=0 || width==NULL || height==NULL || jpegsub==NULL)
DRC91e86ba2011-02-15 05:24:08 +0000419 _throw("Invalid argument in tjDecompressHeader2()");
DRC1fe80f82010-12-14 01:21:29 +0000420 if(!j->initd) _throw("Instance has not been initialized for decompression");
421
422 if(setjmp(j->jerr.jb))
423 { // this will execute if LIBJPEG has an error
424 return -1;
425 }
426
427 j->jsms.bytes_in_buffer = size;
428 j->jsms.next_input_byte = srcbuf;
429
430 jpeg_read_header(&j->dinfo, TRUE);
431
432 *width=j->dinfo.image_width; *height=j->dinfo.image_height;
433 *jpegsub=-1;
434 for(i=0; i<NUMSUBOPT; i++)
435 {
436 if(j->dinfo.num_components==pixelsize[i])
437 {
438 if(j->dinfo.comp_info[0].h_samp_factor==hsampfactor[i]
439 && j->dinfo.comp_info[0].v_samp_factor==vsampfactor[i])
440 {
441 int match=0;
442 for(k=1; k<j->dinfo.num_components; k++)
443 {
444 if(j->dinfo.comp_info[k].h_samp_factor==1
445 && j->dinfo.comp_info[k].v_samp_factor==1)
446 match++;
447 }
448 if(match==j->dinfo.num_components-1)
449 {
450 *jpegsub=i; break;
451 }
452 }
453 }
454 }
455
456 jpeg_abort_decompress(&j->dinfo);
457
458 if(*jpegsub<0) _throw("Could not determine subsampling type for JPEG image");
459 if(*width<1 || *height<1) _throw("Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +0000460
461 bailout:
462 return retval;
463}
464
465
466DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
467 unsigned char *srcbuf, unsigned long size,
468 int *width, int *height)
469{
470 int jpegsub;
471 return tjDecompressHeader2(h, srcbuf, size, width, height, &jpegsub);
DRC1fe80f82010-12-14 01:21:29 +0000472}
473
474
DRC1b1e8862011-02-26 19:53:58 +0000475DLLEXPORT int DLLCALL tjGetScaledSize(int input_width, int input_height,
DRCb28fc572011-02-22 06:41:29 +0000476 int *output_width, int *output_height)
477{
478 int i, retval=0, scaledw=0, scaledh=0;
479
480 if(input_width<1 || input_height<1 || output_width==NULL
481 || output_height==NULL || *output_width<0 || *output_height<0)
DRC1b1e8862011-02-26 19:53:58 +0000482 _throw("Invalid argument in tjGetScaledSize()");
DRCb28fc572011-02-22 06:41:29 +0000483
484 if(*output_width==0) *output_width=input_width;
485 if(*output_height==0) *output_height=input_height;
486 if(*output_width<input_width || *output_height<input_height)
487 {
488 for(i=1; i<=8; i*=2)
489 {
490 scaledw=(input_width+i-1)/i;
491 scaledh=(input_height+i-1)/i;
492 if(scaledw<=*output_width && scaledh<=*output_height)
493 break;
494 }
495 *output_width=scaledw; *output_height=scaledh;
496 }
497
498 bailout:
499 return retval;
500}
501
502
503DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
DRC2e7b76b2009-04-03 12:04:24 +0000504 unsigned char *srcbuf, unsigned long size,
DRCb28fc572011-02-22 06:41:29 +0000505 unsigned char *dstbuf, int width, int pitch, int height, int ps,
506 int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000507{
DRC91e86ba2011-02-15 05:24:08 +0000508 int i, row, retval=0; JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
DRCf9cf5c72010-12-10 10:58:49 +0000509 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
510 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
511 JSAMPLE *_tmpbuf=NULL; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRCb28fc572011-02-22 06:41:29 +0000512 int scale_num=1, scale_denom=1, jpegwidth, jpegheight, scaledw, scaledh;
DRC2e7b76b2009-04-03 12:04:24 +0000513
514 checkhandle(h);
515
DRCf9cf5c72010-12-10 10:58:49 +0000516 for(i=0; i<MAX_COMPONENTS; i++)
517 {
518 tmpbuf[i]=NULL; outbuf[i]=NULL;
519 }
DRC9e17f7d2010-12-10 04:59:13 +0000520
DRCb28fc572011-02-22 06:41:29 +0000521 if(srcbuf==NULL || size<=0
522 || dstbuf==NULL || width<0 || pitch<0 || height<0)
523 _throw("Invalid argument in tjDecompress()");
DRC09854f52010-11-04 22:39:59 +0000524 if(ps!=3 && ps!=4 && ps!=1)
525 _throw("This decompressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale output");
DRC2e7b76b2009-04-03 12:04:24 +0000526 if(!j->initd) _throw("Instance has not been initialized for decompression");
527
DRC0c6a2712010-02-22 08:34:44 +0000528 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
529 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
530 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
531
DRC2e7b76b2009-04-03 12:04:24 +0000532 if(setjmp(j->jerr.jb))
533 { // this will execute if LIBJPEG has an error
DRC91e86ba2011-02-15 05:24:08 +0000534 retval=-1;
535 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +0000536 }
DRC2e7b76b2009-04-03 12:04:24 +0000537
538 j->jsms.bytes_in_buffer = size;
539 j->jsms.next_input_byte = srcbuf;
540
541 jpeg_read_header(&j->dinfo, TRUE);
542
DRC9e17f7d2010-12-10 04:59:13 +0000543 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000544 {
DRC9e17f7d2010-12-10 04:59:13 +0000545 j_decompress_ptr dinfo=&j->dinfo;
546 JSAMPLE *ptr=dstbuf;
547
548 for(i=0; i<dinfo->num_components; i++)
549 {
550 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRCf9cf5c72010-12-10 10:58:49 +0000551 int ih;
552 iw[i]=compptr->width_in_blocks*DCTSIZE;
553 ih=compptr->height_in_blocks*DCTSIZE;
DRC8ed7b812011-02-15 08:31:34 +0000554 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
555 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
556 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
557 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRCa6f4fca2010-12-11 06:01:11 +0000558 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
559 th[i]=compptr->v_samp_factor*DCTSIZE;
560 tmpbufsize+=iw[i]*th[i];
DRC9e17f7d2010-12-10 04:59:13 +0000561 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
DRC84241602011-02-25 02:08:23 +0000562 _throw("Memory allocation failed in tjDecompress()");
DRC9e17f7d2010-12-10 04:59:13 +0000563 for(row=0; row<ch[i]; row++)
564 {
565 outbuf[i][row]=ptr;
DRCf9cf5c72010-12-10 10:58:49 +0000566 ptr+=PAD(cw[i], 4);
567 }
568 }
569 if(usetmpbuf)
570 {
571 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRC84241602011-02-25 02:08:23 +0000572 _throw("Memory allocation failed in tjDecompress()");
DRCf9cf5c72010-12-10 10:58:49 +0000573 ptr=_tmpbuf;
574 for(i=0; i<dinfo->num_components; i++)
575 {
DRCf9cf5c72010-12-10 10:58:49 +0000576 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRC84241602011-02-25 02:08:23 +0000577 _throw("Memory allocation failed in tjDecompress()");
DRCf9cf5c72010-12-10 10:58:49 +0000578 for(row=0; row<th[i]; row++)
579 {
580 tmpbuf[i][row]=ptr;
581 ptr+=iw[i];
582 }
DRC9e17f7d2010-12-10 04:59:13 +0000583 }
584 }
585 }
DRC2e7b76b2009-04-03 12:04:24 +0000586
DRC09854f52010-11-04 22:39:59 +0000587 if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE;
DRC2e7b76b2009-04-03 12:04:24 +0000588 #if JCS_EXTENSIONS==1
DRC09854f52010-11-04 22:39:59 +0000589 else j->dinfo.out_color_space = JCS_EXT_RGB;
DRC2e7b76b2009-04-03 12:04:24 +0000590 if(ps==3 && (flags&TJ_BGR))
591 j->dinfo.out_color_space = JCS_EXT_BGR;
592 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
593 j->dinfo.out_color_space = JCS_EXT_RGBX;
594 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
595 j->dinfo.out_color_space = JCS_EXT_BGRX;
596 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
597 j->dinfo.out_color_space = JCS_EXT_XBGR;
598 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
599 j->dinfo.out_color_space = JCS_EXT_XRGB;
600 #else
601 #error "TurboJPEG requires JPEG colorspace extensions"
602 #endif
DRCfbb67472010-11-24 04:02:37 +0000603
DRC61e51f92009-04-05 21:53:20 +0000604 if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
DRC9e17f7d2010-12-10 04:59:13 +0000605 if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE;
DRC8ed7b812011-02-15 08:31:34 +0000606 else
607 {
DRC84241602011-02-25 02:08:23 +0000608 jpegwidth=j->dinfo.image_width; jpegheight=j->dinfo.image_height;
609 if(width==0) width=jpegwidth;
610 if(height==0) height=jpegheight;
611 if(width<jpegwidth || height<jpegheight)
612 {
613 for(i=1; i<=8; i*=2)
614 {
615 scaledw=(jpegwidth+i-1)/i;
616 scaledh=(jpegheight+i-1)/i;
617 if(scaledw<=width && scaledh<=height)
618 break;
619 }
620 if(scaledw>width || scaledh>height)
621 _throw("Could not scale down to desired image dimensions");
622 width=scaledw; height=scaledh;
623 scale_denom=i;
624 }
DRC8ed7b812011-02-15 08:31:34 +0000625 j->dinfo.scale_num=scale_num;
626 j->dinfo.scale_denom=scale_denom;
627 }
DRC2e7b76b2009-04-03 12:04:24 +0000628
629 jpeg_start_decompress(&j->dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000630 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000631 {
DRCf9cf5c72010-12-10 10:58:49 +0000632 j_decompress_ptr dinfo=&j->dinfo;
633 for(row=0; row<dinfo->output_height;
634 row+=dinfo->max_v_samp_factor*DCTSIZE)
DRC9e17f7d2010-12-10 04:59:13 +0000635 {
636 JSAMPARRAY yuvptr[MAX_COMPONENTS];
DRCa6f4fca2010-12-11 06:01:11 +0000637 int crow[MAX_COMPONENTS];
DRCf9cf5c72010-12-10 10:58:49 +0000638 for(i=0; i<dinfo->num_components; i++)
DRC9e17f7d2010-12-10 04:59:13 +0000639 {
DRCf9cf5c72010-12-10 10:58:49 +0000640 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRCa6f4fca2010-12-11 06:01:11 +0000641 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRCf9cf5c72010-12-10 10:58:49 +0000642 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
DRCa6f4fca2010-12-11 06:01:11 +0000643 else yuvptr[i]=&outbuf[i][crow[i]];
DRC9e17f7d2010-12-10 04:59:13 +0000644 }
DRCf9cf5c72010-12-10 10:58:49 +0000645 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
646 if(usetmpbuf)
647 {
648 int j;
649 for(i=0; i<dinfo->num_components; i++)
650 {
DRCa6f4fca2010-12-11 06:01:11 +0000651 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +0000652 {
DRCa6f4fca2010-12-11 06:01:11 +0000653 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000654 }
655 }
656 }
DRC9e17f7d2010-12-10 04:59:13 +0000657 }
658 }
659 else
660 {
DRC8ed7b812011-02-15 08:31:34 +0000661 if(pitch==0) pitch=j->dinfo.output_width*ps;
662 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
663 *j->dinfo.output_height))==NULL)
DRC8ed7b812011-02-15 08:31:34 +0000664 _throw("Memory allocation failed in tjInitDecompress()");
DRC8ed7b812011-02-15 08:31:34 +0000665 for(i=0; i<j->dinfo.output_height; i++)
666 {
667 if(flags&TJ_BOTTOMUP)
668 row_pointer[i]= &dstbuf[(j->dinfo.output_height-i-1)*pitch];
669 else row_pointer[i]= &dstbuf[i*pitch];
670 }
DRC9e17f7d2010-12-10 04:59:13 +0000671 while(j->dinfo.output_scanline<j->dinfo.output_height)
672 {
673 jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
674 j->dinfo.output_height-j->dinfo.output_scanline);
675 }
DRC2e7b76b2009-04-03 12:04:24 +0000676 }
677 jpeg_finish_decompress(&j->dinfo);
678
DRC91e86ba2011-02-15 05:24:08 +0000679 bailout:
DRCb28fc572011-02-22 06:41:29 +0000680 if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000681 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +0000682 {
683 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +0000684 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000685 }
686 if(_tmpbuf) free(_tmpbuf);
DRC2e7b76b2009-04-03 12:04:24 +0000687 if(row_pointer) free(row_pointer);
DRC91e86ba2011-02-15 05:24:08 +0000688 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000689}
690
691
DRC84241602011-02-25 02:08:23 +0000692DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle h,
693 unsigned char *srcbuf, unsigned long size,
694 unsigned char *dstbuf, int flags)
695{
696 return tjDecompress(h, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV);
697}
698
699
DRC890f1e02011-02-26 22:02:37 +0000700// Transformation
701
702DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
703{
704 jpgstruct *j=NULL; tjhandle tj=NULL;
705 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
706 {sprintf(lasterror, "Memory allocation failure"); return NULL;}
707 memset(j, 0, sizeof(jpgstruct));
708 tj=_tjInitCompress(j);
709 if(!tj) return NULL;
710 tj=_tjInitDecompress(j);
711 return tj;
712}
713
714
715DLLEXPORT int DLLCALL tjTransform(tjhandle hnd,
716 unsigned char *srcbuf, unsigned long srcsize,
717 unsigned char *dstbuf, unsigned long *dstsize,
718 int x, int y, int w, int h, int op, int options, int flags)
719{
720 jpeg_transform_info xinfo;
721 jvirt_barray_ptr *srccoefs, *dstcoefs;
722 int retval=0;
723
724 checkhandle(hnd);
725
726 if(srcbuf==NULL || srcsize<=0 || dstbuf==NULL || dstsize==NULL
727 || x<0 || y<0 || w<0 || h<0 || op<0 || op>=NUMXFORMOPT
728 || flags<0)
729 _throw("Invalid argument in tjTransform()");
730 if(!j->initc || !j->initd)
731 _throw("Instance has not been initialized for transformation");
732
733 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
734 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
735 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
736
737 if(setjmp(j->jerr.jb))
738 { // this will execute if LIBJPEG has an error
739 retval=-1;
740 goto bailout;
741 }
742
743 j->jsms.bytes_in_buffer=srcsize;
744 j->jsms.next_input_byte=srcbuf;
745
746 xinfo.transform=xformtypes[op];
747 xinfo.perfect=(options&TJXFORM_PERFECT)? 1:0;
748 xinfo.trim=(options&TJXFORM_TRIM)? 1:0;
749 xinfo.force_grayscale=(options&TJXFORM_GRAY)? 1:0;
750 xinfo.crop=(options&TJXFORM_CROP)? 1:0;
751
752 if(xinfo.crop)
753 {
754 xinfo.crop_xoffset=x; xinfo.crop_xoffset_set=JCROP_POS;
755 xinfo.crop_yoffset=y; xinfo.crop_yoffset_set=JCROP_POS;
756 if(w!=0)
757 {
758 xinfo.crop_width=w; xinfo.crop_width_set=JCROP_POS;
759 }
760 if(h!=0)
761 {
762 xinfo.crop_height=h; xinfo.crop_height_set=JCROP_POS;
763 }
764 }
765
766 jcopy_markers_setup(&j->dinfo, JCOPYOPT_NONE);
767 jpeg_read_header(&j->dinfo, TRUE);
768
769 if(!jtransform_request_workspace(&j->dinfo, &xinfo))
770 _throw("Transform is not perfect");
771
772 if(!xinfo.crop)
773 {
774 w=j->dinfo.image_width; h=j->dinfo.image_height;
775 }
776 else
777 {
778 w=xinfo.crop_width; h=xinfo.crop_height;
779 }
780
781 j->jdms.next_output_byte=dstbuf;
782 j->jdms.free_in_buffer=TJBUFSIZE(w, h);
783
784 if(xinfo.crop)
785 {
786 if((x%xinfo.iMCU_sample_width)!=0 || (y%xinfo.iMCU_sample_height)!=0)
787 {
788 sprintf(lasterror, "To crop this JPEG image, x must be a multiple of %d and y must be a multiple\n"
789 "of %d.\n", xinfo.iMCU_sample_width, xinfo.iMCU_sample_height);
790 retval=-1; goto bailout;
791 }
792 }
793
794 srccoefs=jpeg_read_coefficients(&j->dinfo);
795 jpeg_copy_critical_parameters(&j->dinfo, &j->cinfo);
796 dstcoefs=jtransform_adjust_parameters(&j->dinfo, &j->cinfo, srccoefs,
797 &xinfo);
798 jpeg_write_coefficients(&j->cinfo, dstcoefs);
799 jcopy_markers_execute(&j->dinfo, &j->cinfo, JCOPYOPT_ALL);
800 jtransform_execute_transformation(&j->dinfo, &j->cinfo, srccoefs, &xinfo);
801
802 jpeg_finish_compress(&j->cinfo);
803 jpeg_finish_decompress(&j->dinfo);
804
805 *dstsize=TJBUFSIZE(w, h)-(unsigned long)(j->jdms.free_in_buffer);
806
807 bailout:
808 if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
809 if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
810 return retval;
811}
812
813
DRC2e7b76b2009-04-03 12:04:24 +0000814// General
815
816DLLEXPORT char* DLLCALL tjGetErrorStr(void)
817{
818 return lasterror;
819}
820
821DLLEXPORT int DLLCALL tjDestroy(tjhandle h)
822{
823 checkhandle(h);
824 if(setjmp(j->jerr.jb)) return -1;
825 if(j->initc) jpeg_destroy_compress(&j->cinfo);
826 if(j->initd) jpeg_destroy_decompress(&j->dinfo);
827 free(j);
828 return 0;
829}