blob: 4ae41b7cc3f1bd17b33ad578bfce350af04e029f [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};
DRC109a5782011-03-01 09:53:07 +000077#define NUMSF 4
78static const tjscalingfactor sf[NUMSF]={
79 {1, 1},
80 {1, 2},
81 {1, 4},
82 {1, 8}
83};
DRC2e7b76b2009-04-03 12:04:24 +000084
DRC91e86ba2011-02-15 05:24:08 +000085#define _throw(c) {sprintf(lasterror, "%s", c); retval=-1; goto bailout;}
DRC2e7b76b2009-04-03 12:04:24 +000086#define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
DRC91e86ba2011-02-15 05:24:08 +000087 if(!j) {sprintf(lasterror, "Invalid handle"); return -1;}
DRC2e7b76b2009-04-03 12:04:24 +000088
89
90// CO
91
92static boolean empty_output_buffer(struct jpeg_compress_struct *cinfo)
93{
94 ERREXIT(cinfo, JERR_BUFFER_SIZE);
95 return TRUE;
96}
97
98static void destination_noop(struct jpeg_compress_struct *cinfo)
99{
100}
101
DRC890f1e02011-02-26 22:02:37 +0000102static tjhandle _tjInitCompress(jpgstruct *j)
DRC2e7b76b2009-04-03 12:04:24 +0000103{
DRC2e7b76b2009-04-03 12:04:24 +0000104 j->cinfo.err=jpeg_std_error(&j->jerr.pub);
105 j->jerr.pub.error_exit=my_error_exit;
106 j->jerr.pub.output_message=my_output_message;
107
108 if(setjmp(j->jerr.jb))
109 { // this will execute if LIBJPEG has an error
110 if(j) free(j); return NULL;
DRCefa4ddc2010-10-13 19:22:50 +0000111 }
DRC2e7b76b2009-04-03 12:04:24 +0000112
113 jpeg_create_compress(&j->cinfo);
114 j->cinfo.dest=&j->jdms;
115 j->jdms.init_destination=destination_noop;
116 j->jdms.empty_output_buffer=empty_output_buffer;
117 j->jdms.term_destination=destination_noop;
118
119 j->initc=1;
120 return (tjhandle)j;
121}
122
DRC890f1e02011-02-26 22:02:37 +0000123DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
124{
125 jpgstruct *j=NULL;
126 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
127 {sprintf(lasterror, "Memory allocation failure"); return NULL;}
128 memset(j, 0, sizeof(jpgstruct));
129 return _tjInitCompress(j);
130}
131
DRC84241602011-02-25 02:08:23 +0000132
DRC2e7b76b2009-04-03 12:04:24 +0000133DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
134{
DRCf3cf9732011-02-22 00:16:14 +0000135 unsigned long retval=0;
136 if(width<1 || height<1)
137 _throw("Invalid argument in TJBUFSIZE()");
138
139 // This allows for rare corner cases in which a JPEG image can actually be
140 // larger than the uncompressed input (we wouldn't mention it if it hadn't
DRCb28fc572011-02-22 06:41:29 +0000141 // happened before.)
DRCf3cf9732011-02-22 00:16:14 +0000142 retval=((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
143
144 bailout:
145 return retval;
146}
147
DRC84241602011-02-25 02:08:23 +0000148
DRCf3cf9732011-02-22 00:16:14 +0000149DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
150 int subsamp)
151{
152 unsigned long retval=0;
153 int pw, ph, cw, ch;
154 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
155 _throw("Invalid argument in TJBUFSIZEYUV()");
156 pw=PAD(width, hsampfactor[subsamp]);
157 ph=PAD(height, vsampfactor[subsamp]);
158 cw=pw/hsampfactor[subsamp]; ch=ph/vsampfactor[subsamp];
159 retval=PAD(pw, 4)*ph + (subsamp==TJ_GRAYSCALE? 0:PAD(cw, 4)*ch*2);
160
161 bailout:
162 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000163}
164
DRC84241602011-02-25 02:08:23 +0000165
DRC2e7b76b2009-04-03 12:04:24 +0000166DLLEXPORT int DLLCALL tjCompress(tjhandle h,
167 unsigned char *srcbuf, int width, int pitch, int height, int ps,
168 unsigned char *dstbuf, unsigned long *size,
169 int jpegsub, int qual, int flags)
170{
DRC91e86ba2011-02-15 05:24:08 +0000171 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000172 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
173 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
174 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC2e7b76b2009-04-03 12:04:24 +0000175
176 checkhandle(h);
177
DRCfbb67472010-11-24 04:02:37 +0000178 for(i=0; i<MAX_COMPONENTS; i++)
179 {
180 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
181 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
182 }
183
DRC2e7b76b2009-04-03 12:04:24 +0000184 if(srcbuf==NULL || width<=0 || pitch<0 || height<=0
185 || dstbuf==NULL || size==NULL
186 || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100)
187 _throw("Invalid argument in tjCompress()");
DRC09854f52010-11-04 22:39:59 +0000188 if(ps!=3 && ps!=4 && ps!=1)
189 _throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input");
DRC2e7b76b2009-04-03 12:04:24 +0000190 if(!j->initc) _throw("Instance has not been initialized for compression");
191
192 if(pitch==0) pitch=width*ps;
193
194 j->cinfo.image_width = width;
195 j->cinfo.image_height = height;
196 j->cinfo.input_components = ps;
197
DRC09854f52010-11-04 22:39:59 +0000198 if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE;
DRC2e7b76b2009-04-03 12:04:24 +0000199 #if JCS_EXTENSIONS==1
DRC09854f52010-11-04 22:39:59 +0000200 else j->cinfo.in_color_space = JCS_EXT_RGB;
DRC2e7b76b2009-04-03 12:04:24 +0000201 if(ps==3 && (flags&TJ_BGR))
202 j->cinfo.in_color_space = JCS_EXT_BGR;
203 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
204 j->cinfo.in_color_space = JCS_EXT_RGBX;
205 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
206 j->cinfo.in_color_space = JCS_EXT_BGRX;
207 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
208 j->cinfo.in_color_space = JCS_EXT_XBGR;
209 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
210 j->cinfo.in_color_space = JCS_EXT_XRGB;
211 #else
212 #error "TurboJPEG requires JPEG colorspace extensions"
213 #endif
214
DRC0c6a2712010-02-22 08:34:44 +0000215 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
216 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
217 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
218
DRC2e7b76b2009-04-03 12:04:24 +0000219 if(setjmp(j->jerr.jb))
220 { // this will execute if LIBJPEG has an error
DRC91e86ba2011-02-15 05:24:08 +0000221 retval=-1;
222 goto bailout;
DRCefa4ddc2010-10-13 19:22:50 +0000223 }
DRC2e7b76b2009-04-03 12:04:24 +0000224
225 jpeg_set_defaults(&j->cinfo);
226
227 jpeg_set_quality(&j->cinfo, qual, TRUE);
228 if(jpegsub==TJ_GRAYSCALE)
229 jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE);
230 else
231 jpeg_set_colorspace(&j->cinfo, JCS_YCbCr);
DRCe1716b82011-02-18 03:19:43 +0000232 if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW;
233 else j->cinfo.dct_method=JDCT_FASTEST;
DRC2e7b76b2009-04-03 12:04:24 +0000234
235 j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub];
236 j->cinfo.comp_info[1].h_samp_factor=1;
237 j->cinfo.comp_info[2].h_samp_factor=1;
238 j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub];
239 j->cinfo.comp_info[1].v_samp_factor=1;
240 j->cinfo.comp_info[2].v_samp_factor=1;
241
242 j->jdms.next_output_byte = dstbuf;
243 j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height);
244
DRC2e7b76b2009-04-03 12:04:24 +0000245 jpeg_start_compress(&j->cinfo, TRUE);
DRCfbb67472010-11-24 04:02:37 +0000246 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000247 {
DRCfbb67472010-11-24 04:02:37 +0000248 j_compress_ptr cinfo=&j->cinfo;
249 int row;
250 int pw=PAD(width, cinfo->max_h_samp_factor);
251 int ph=PAD(height, cinfo->max_v_samp_factor);
252 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
253 jpeg_component_info *compptr;
254 JSAMPLE *ptr=dstbuf; unsigned long yuvsize=0;
255
256 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
257 _throw("Memory allocation failed in tjCompress()");
258 for(i=0; i<height; i++)
259 {
260 if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
261 else row_pointer[i]= &srcbuf[i*pitch];
262 }
263 if(height<ph)
264 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
265
266 for(i=0; i<cinfo->num_components; i++)
267 {
268 compptr=&cinfo->comp_info[i];
DRC57423072011-01-05 23:35:53 +0000269 _tmpbuf[i]=(JSAMPLE *)malloc(
DRCfbb67472010-11-24 04:02:37 +0000270 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC57423072011-01-05 23:35:53 +0000271 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRCfbb67472010-11-24 04:02:37 +0000272 if(!_tmpbuf[i]) _throw("Memory allocation failure");
DRC2a2e4512011-01-05 22:33:24 +0000273 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCfbb67472010-11-24 04:02:37 +0000274 if(!tmpbuf[i]) _throw("Memory allocation failure");
275 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRC57423072011-01-05 23:35:53 +0000276 {
277 unsigned char *_tmpbuf_aligned=
278 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
279 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000280 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
281 /compptr->h_samp_factor, 16) * row];
DRC57423072011-01-05 23:35:53 +0000282 }
283 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
284 * compptr->v_samp_factor + 16);
DRCfbb67472010-11-24 04:02:37 +0000285 if(!_tmpbuf2[i]) _throw("Memory allocation failure");
DRC2a2e4512011-01-05 22:33:24 +0000286 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCfbb67472010-11-24 04:02:37 +0000287 if(!tmpbuf2[i]) _throw("Memory allocation failure");
288 for(row=0; row<compptr->v_samp_factor; row++)
DRC57423072011-01-05 23:35:53 +0000289 {
290 unsigned char *_tmpbuf2_aligned=
291 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
292 tmpbuf2[i][row]=&_tmpbuf2_aligned[
DRCfbb67472010-11-24 04:02:37 +0000293 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
DRC57423072011-01-05 23:35:53 +0000294 }
DRCfbb67472010-11-24 04:02:37 +0000295 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
296 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
DRC2a2e4512011-01-05 22:33:24 +0000297 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
DRCfbb67472010-11-24 04:02:37 +0000298 if(!outbuf[i]) _throw("Memory allocation failure");
299 for(row=0; row<ch[i]; row++)
300 {
301 outbuf[i][row]=ptr;
302 ptr+=PAD(cw[i], 4);
303 }
304 }
305 yuvsize=(unsigned long)(ptr-dstbuf);
306
307 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
308 {
309 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf,
310 0, cinfo->max_v_samp_factor);
311 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
312 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components;
313 i++, compptr++)
314 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
315 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
316 compptr->v_samp_factor, cw[i]);
317 }
318 *size=yuvsize;
319 cinfo->next_scanline+=height;
DRC6ee54592011-03-01 08:18:30 +0000320 jpeg_abort_compress(&j->cinfo);
DRCfbb67472010-11-24 04:02:37 +0000321 }
322 else
323 {
324 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
325 _throw("Memory allocation failed in tjCompress()");
326 for(i=0; i<height; i++)
327 {
328 if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
329 else row_pointer[i]= &srcbuf[i*pitch];
330 }
331 while(j->cinfo.next_scanline<j->cinfo.image_height)
332 {
333 jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
334 j->cinfo.image_height-j->cinfo.next_scanline);
335 }
DRC6ee54592011-03-01 08:18:30 +0000336 jpeg_finish_compress(&j->cinfo);
DRCfbb67472010-11-24 04:02:37 +0000337 *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)
338 -(unsigned long)(j->jdms.free_in_buffer);
DRC6ee54592011-03-01 08:18:30 +0000339 }
DRC2e7b76b2009-04-03 12:04:24 +0000340
DRC91e86ba2011-02-15 05:24:08 +0000341 bailout:
DRCb28fc572011-02-22 06:41:29 +0000342 if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000343 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000344 for(i=0; i<MAX_COMPONENTS; i++)
345 {
346 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000347 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000348 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000349 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000350 if(outbuf[i]!=NULL) free(outbuf[i]);
351 }
DRC91e86ba2011-02-15 05:24:08 +0000352 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000353}
354
355
DRC84241602011-02-25 02:08:23 +0000356DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle h,
357 unsigned char *srcbuf, int width, int pitch, int height, int ps,
358 unsigned char *dstbuf, int subsamp, int flags)
359{
360 unsigned long size;
361 return tjCompress(h, srcbuf, width, pitch, height, ps, dstbuf, &size,
362 subsamp, 0, flags|TJ_YUV);
363}
364
365
DRC2e7b76b2009-04-03 12:04:24 +0000366// DEC
367
368static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo)
369{
370 ERREXIT(dinfo, JERR_BUFFER_SIZE);
371 return TRUE;
372}
373
374static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes)
375{
376 dinfo->src->next_input_byte += (size_t) num_bytes;
377 dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
378}
379
380static void source_noop (struct jpeg_decompress_struct *dinfo)
381{
382}
383
DRC890f1e02011-02-26 22:02:37 +0000384static tjhandle _tjInitDecompress(jpgstruct *j)
DRC2e7b76b2009-04-03 12:04:24 +0000385{
DRC2e7b76b2009-04-03 12:04:24 +0000386 j->dinfo.err=jpeg_std_error(&j->jerr.pub);
387 j->jerr.pub.error_exit=my_error_exit;
388 j->jerr.pub.output_message=my_output_message;
389
390 if(setjmp(j->jerr.jb))
391 { // this will execute if LIBJPEG has an error
392 free(j); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +0000393 }
DRC2e7b76b2009-04-03 12:04:24 +0000394
395 jpeg_create_decompress(&j->dinfo);
396 j->dinfo.src=&j->jsms;
397 j->jsms.init_source=source_noop;
398 j->jsms.fill_input_buffer = fill_input_buffer;
399 j->jsms.skip_input_data = skip_input_data;
400 j->jsms.resync_to_restart = jpeg_resync_to_restart;
401 j->jsms.term_source = source_noop;
402
403 j->initd=1;
404 return (tjhandle)j;
405}
406
DRC890f1e02011-02-26 22:02:37 +0000407DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
408{
409 jpgstruct *j;
410 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
411 {sprintf(lasterror, "Memory allocation failure"); return NULL;}
412 memset(j, 0, sizeof(jpgstruct));
413 return _tjInitDecompress(j);
414}
415
DRC2e7b76b2009-04-03 12:04:24 +0000416
DRC1fe80f82010-12-14 01:21:29 +0000417DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle h,
418 unsigned char *srcbuf, unsigned long size,
419 int *width, int *height, int *jpegsub)
420{
DRC91e86ba2011-02-15 05:24:08 +0000421 int i, k, retval=0;
DRC1fe80f82010-12-14 01:21:29 +0000422
423 checkhandle(h);
424
425 if(srcbuf==NULL || size<=0 || width==NULL || height==NULL || jpegsub==NULL)
DRC91e86ba2011-02-15 05:24:08 +0000426 _throw("Invalid argument in tjDecompressHeader2()");
DRC1fe80f82010-12-14 01:21:29 +0000427 if(!j->initd) _throw("Instance has not been initialized for decompression");
428
429 if(setjmp(j->jerr.jb))
430 { // this will execute if LIBJPEG has an error
431 return -1;
432 }
433
434 j->jsms.bytes_in_buffer = size;
435 j->jsms.next_input_byte = srcbuf;
436
437 jpeg_read_header(&j->dinfo, TRUE);
438
439 *width=j->dinfo.image_width; *height=j->dinfo.image_height;
440 *jpegsub=-1;
441 for(i=0; i<NUMSUBOPT; i++)
442 {
443 if(j->dinfo.num_components==pixelsize[i])
444 {
445 if(j->dinfo.comp_info[0].h_samp_factor==hsampfactor[i]
446 && j->dinfo.comp_info[0].v_samp_factor==vsampfactor[i])
447 {
448 int match=0;
449 for(k=1; k<j->dinfo.num_components; k++)
450 {
451 if(j->dinfo.comp_info[k].h_samp_factor==1
452 && j->dinfo.comp_info[k].v_samp_factor==1)
453 match++;
454 }
455 if(match==j->dinfo.num_components-1)
456 {
457 *jpegsub=i; break;
458 }
459 }
460 }
461 }
462
463 jpeg_abort_decompress(&j->dinfo);
464
465 if(*jpegsub<0) _throw("Could not determine subsampling type for JPEG image");
466 if(*width<1 || *height<1) _throw("Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +0000467
468 bailout:
469 return retval;
470}
471
472
473DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
474 unsigned char *srcbuf, unsigned long size,
475 int *width, int *height)
476{
477 int jpegsub;
478 return tjDecompressHeader2(h, srcbuf, size, width, height, &jpegsub);
DRC1fe80f82010-12-14 01:21:29 +0000479}
480
481
DRC109a5782011-03-01 09:53:07 +0000482DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +0000483{
DRC109a5782011-03-01 09:53:07 +0000484 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +0000485 {
DRC109a5782011-03-01 09:53:07 +0000486 sprintf(lasterror, "Invalid argument in tjGetScalingFactors()");
487 return NULL;
DRCb28fc572011-02-22 06:41:29 +0000488 }
489
DRC109a5782011-03-01 09:53:07 +0000490 *numscalingfactors=NUMSF;
491 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +0000492}
493
494
495DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
DRC2e7b76b2009-04-03 12:04:24 +0000496 unsigned char *srcbuf, unsigned long size,
DRCb28fc572011-02-22 06:41:29 +0000497 unsigned char *dstbuf, int width, int pitch, int height, int ps,
498 int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000499{
DRC91e86ba2011-02-15 05:24:08 +0000500 int i, row, retval=0; JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
DRCf9cf5c72010-12-10 10:58:49 +0000501 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
502 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
503 JSAMPLE *_tmpbuf=NULL; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC109a5782011-03-01 09:53:07 +0000504 int jpegwidth, jpegheight, scaledw, scaledh;
DRC2e7b76b2009-04-03 12:04:24 +0000505
506 checkhandle(h);
507
DRCf9cf5c72010-12-10 10:58:49 +0000508 for(i=0; i<MAX_COMPONENTS; i++)
509 {
510 tmpbuf[i]=NULL; outbuf[i]=NULL;
511 }
DRC9e17f7d2010-12-10 04:59:13 +0000512
DRCb28fc572011-02-22 06:41:29 +0000513 if(srcbuf==NULL || size<=0
514 || dstbuf==NULL || width<0 || pitch<0 || height<0)
515 _throw("Invalid argument in tjDecompress()");
DRC09854f52010-11-04 22:39:59 +0000516 if(ps!=3 && ps!=4 && ps!=1)
517 _throw("This decompressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale output");
DRC2e7b76b2009-04-03 12:04:24 +0000518 if(!j->initd) _throw("Instance has not been initialized for decompression");
519
DRC0c6a2712010-02-22 08:34:44 +0000520 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
521 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
522 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
523
DRC2e7b76b2009-04-03 12:04:24 +0000524 if(setjmp(j->jerr.jb))
525 { // this will execute if LIBJPEG has an error
DRC91e86ba2011-02-15 05:24:08 +0000526 retval=-1;
527 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +0000528 }
DRC2e7b76b2009-04-03 12:04:24 +0000529
530 j->jsms.bytes_in_buffer = size;
531 j->jsms.next_input_byte = srcbuf;
532
533 jpeg_read_header(&j->dinfo, TRUE);
534
DRC9e17f7d2010-12-10 04:59:13 +0000535 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000536 {
DRC9e17f7d2010-12-10 04:59:13 +0000537 j_decompress_ptr dinfo=&j->dinfo;
538 JSAMPLE *ptr=dstbuf;
539
540 for(i=0; i<dinfo->num_components; i++)
541 {
542 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRCf9cf5c72010-12-10 10:58:49 +0000543 int ih;
544 iw[i]=compptr->width_in_blocks*DCTSIZE;
545 ih=compptr->height_in_blocks*DCTSIZE;
DRC8ed7b812011-02-15 08:31:34 +0000546 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
547 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
548 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
549 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRCa6f4fca2010-12-11 06:01:11 +0000550 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
551 th[i]=compptr->v_samp_factor*DCTSIZE;
552 tmpbufsize+=iw[i]*th[i];
DRC9e17f7d2010-12-10 04:59:13 +0000553 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
DRC84241602011-02-25 02:08:23 +0000554 _throw("Memory allocation failed in tjDecompress()");
DRC9e17f7d2010-12-10 04:59:13 +0000555 for(row=0; row<ch[i]; row++)
556 {
557 outbuf[i][row]=ptr;
DRCf9cf5c72010-12-10 10:58:49 +0000558 ptr+=PAD(cw[i], 4);
559 }
560 }
561 if(usetmpbuf)
562 {
563 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRC84241602011-02-25 02:08:23 +0000564 _throw("Memory allocation failed in tjDecompress()");
DRCf9cf5c72010-12-10 10:58:49 +0000565 ptr=_tmpbuf;
566 for(i=0; i<dinfo->num_components; i++)
567 {
DRCf9cf5c72010-12-10 10:58:49 +0000568 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRC84241602011-02-25 02:08:23 +0000569 _throw("Memory allocation failed in tjDecompress()");
DRCf9cf5c72010-12-10 10:58:49 +0000570 for(row=0; row<th[i]; row++)
571 {
572 tmpbuf[i][row]=ptr;
573 ptr+=iw[i];
574 }
DRC9e17f7d2010-12-10 04:59:13 +0000575 }
576 }
577 }
DRC2e7b76b2009-04-03 12:04:24 +0000578
DRC09854f52010-11-04 22:39:59 +0000579 if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE;
DRC2e7b76b2009-04-03 12:04:24 +0000580 #if JCS_EXTENSIONS==1
DRC09854f52010-11-04 22:39:59 +0000581 else j->dinfo.out_color_space = JCS_EXT_RGB;
DRC2e7b76b2009-04-03 12:04:24 +0000582 if(ps==3 && (flags&TJ_BGR))
583 j->dinfo.out_color_space = JCS_EXT_BGR;
584 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
585 j->dinfo.out_color_space = JCS_EXT_RGBX;
586 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
587 j->dinfo.out_color_space = JCS_EXT_BGRX;
588 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
589 j->dinfo.out_color_space = JCS_EXT_XBGR;
590 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
591 j->dinfo.out_color_space = JCS_EXT_XRGB;
592 #else
593 #error "TurboJPEG requires JPEG colorspace extensions"
594 #endif
DRCfbb67472010-11-24 04:02:37 +0000595
DRC61e51f92009-04-05 21:53:20 +0000596 if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
DRC9e17f7d2010-12-10 04:59:13 +0000597 if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE;
DRC8ed7b812011-02-15 08:31:34 +0000598 else
599 {
DRC84241602011-02-25 02:08:23 +0000600 jpegwidth=j->dinfo.image_width; jpegheight=j->dinfo.image_height;
601 if(width==0) width=jpegwidth;
602 if(height==0) height=jpegheight;
DRC109a5782011-03-01 09:53:07 +0000603 for(i=0; i<NUMSF; i++)
DRC84241602011-02-25 02:08:23 +0000604 {
DRC109a5782011-03-01 09:53:07 +0000605 scaledw=(jpegwidth*sf[i].num+sf[i].denom-1)/sf[i].denom;
606 scaledh=(jpegheight*sf[i].num+sf[i].denom-1)/sf[i].denom;
607 if(scaledw<=width && scaledh<=height)
DRC84241602011-02-25 02:08:23 +0000608 break;
DRC84241602011-02-25 02:08:23 +0000609 }
DRC109a5782011-03-01 09:53:07 +0000610 if(scaledw>width || scaledh>height)
611 _throw("Could not scale down to desired image dimensions");
612 width=scaledw; height=scaledh;
613 j->dinfo.scale_num=sf[i].num;
614 j->dinfo.scale_denom=sf[i].denom;
DRC8ed7b812011-02-15 08:31:34 +0000615 }
DRC2e7b76b2009-04-03 12:04:24 +0000616
617 jpeg_start_decompress(&j->dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000618 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000619 {
DRCf9cf5c72010-12-10 10:58:49 +0000620 j_decompress_ptr dinfo=&j->dinfo;
DRC43a29d22011-03-02 01:27:26 +0000621 for(row=0; row<(int)dinfo->output_height;
DRCf9cf5c72010-12-10 10:58:49 +0000622 row+=dinfo->max_v_samp_factor*DCTSIZE)
DRC9e17f7d2010-12-10 04:59:13 +0000623 {
624 JSAMPARRAY yuvptr[MAX_COMPONENTS];
DRCa6f4fca2010-12-11 06:01:11 +0000625 int crow[MAX_COMPONENTS];
DRCf9cf5c72010-12-10 10:58:49 +0000626 for(i=0; i<dinfo->num_components; i++)
DRC9e17f7d2010-12-10 04:59:13 +0000627 {
DRCf9cf5c72010-12-10 10:58:49 +0000628 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRCa6f4fca2010-12-11 06:01:11 +0000629 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRCf9cf5c72010-12-10 10:58:49 +0000630 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
DRCa6f4fca2010-12-11 06:01:11 +0000631 else yuvptr[i]=&outbuf[i][crow[i]];
DRC9e17f7d2010-12-10 04:59:13 +0000632 }
DRCf9cf5c72010-12-10 10:58:49 +0000633 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
634 if(usetmpbuf)
635 {
636 int j;
637 for(i=0; i<dinfo->num_components; i++)
638 {
DRCa6f4fca2010-12-11 06:01:11 +0000639 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +0000640 {
DRCa6f4fca2010-12-11 06:01:11 +0000641 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000642 }
643 }
644 }
DRC9e17f7d2010-12-10 04:59:13 +0000645 }
646 }
647 else
648 {
DRC8ed7b812011-02-15 08:31:34 +0000649 if(pitch==0) pitch=j->dinfo.output_width*ps;
650 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
651 *j->dinfo.output_height))==NULL)
DRC8ed7b812011-02-15 08:31:34 +0000652 _throw("Memory allocation failed in tjInitDecompress()");
DRC43a29d22011-03-02 01:27:26 +0000653 for(i=0; i<(int)j->dinfo.output_height; i++)
DRC8ed7b812011-02-15 08:31:34 +0000654 {
655 if(flags&TJ_BOTTOMUP)
656 row_pointer[i]= &dstbuf[(j->dinfo.output_height-i-1)*pitch];
657 else row_pointer[i]= &dstbuf[i*pitch];
658 }
DRC9e17f7d2010-12-10 04:59:13 +0000659 while(j->dinfo.output_scanline<j->dinfo.output_height)
660 {
661 jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
662 j->dinfo.output_height-j->dinfo.output_scanline);
663 }
DRC2e7b76b2009-04-03 12:04:24 +0000664 }
665 jpeg_finish_decompress(&j->dinfo);
666
DRC91e86ba2011-02-15 05:24:08 +0000667 bailout:
DRCb28fc572011-02-22 06:41:29 +0000668 if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000669 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +0000670 {
671 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +0000672 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000673 }
674 if(_tmpbuf) free(_tmpbuf);
DRC2e7b76b2009-04-03 12:04:24 +0000675 if(row_pointer) free(row_pointer);
DRC91e86ba2011-02-15 05:24:08 +0000676 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000677}
678
679
DRC84241602011-02-25 02:08:23 +0000680DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle h,
681 unsigned char *srcbuf, unsigned long size,
682 unsigned char *dstbuf, int flags)
683{
684 return tjDecompress(h, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV);
685}
686
687
DRC890f1e02011-02-26 22:02:37 +0000688// Transformation
689
690DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
691{
692 jpgstruct *j=NULL; tjhandle tj=NULL;
693 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
694 {sprintf(lasterror, "Memory allocation failure"); return NULL;}
695 memset(j, 0, sizeof(jpgstruct));
696 tj=_tjInitCompress(j);
697 if(!tj) return NULL;
698 tj=_tjInitDecompress(j);
699 return tj;
700}
701
702
703DLLEXPORT int DLLCALL tjTransform(tjhandle hnd,
704 unsigned char *srcbuf, unsigned long srcsize,
705 unsigned char *dstbuf, unsigned long *dstsize,
706 int x, int y, int w, int h, int op, int options, int flags)
707{
708 jpeg_transform_info xinfo;
709 jvirt_barray_ptr *srccoefs, *dstcoefs;
710 int retval=0;
711
712 checkhandle(hnd);
713
714 if(srcbuf==NULL || srcsize<=0 || dstbuf==NULL || dstsize==NULL
715 || x<0 || y<0 || w<0 || h<0 || op<0 || op>=NUMXFORMOPT
716 || flags<0)
717 _throw("Invalid argument in tjTransform()");
718 if(!j->initc || !j->initd)
719 _throw("Instance has not been initialized for transformation");
720
721 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
722 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
723 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
724
725 if(setjmp(j->jerr.jb))
726 { // this will execute if LIBJPEG has an error
727 retval=-1;
728 goto bailout;
729 }
730
731 j->jsms.bytes_in_buffer=srcsize;
732 j->jsms.next_input_byte=srcbuf;
733
734 xinfo.transform=xformtypes[op];
735 xinfo.perfect=(options&TJXFORM_PERFECT)? 1:0;
736 xinfo.trim=(options&TJXFORM_TRIM)? 1:0;
737 xinfo.force_grayscale=(options&TJXFORM_GRAY)? 1:0;
738 xinfo.crop=(options&TJXFORM_CROP)? 1:0;
739
740 if(xinfo.crop)
741 {
742 xinfo.crop_xoffset=x; xinfo.crop_xoffset_set=JCROP_POS;
743 xinfo.crop_yoffset=y; xinfo.crop_yoffset_set=JCROP_POS;
744 if(w!=0)
745 {
746 xinfo.crop_width=w; xinfo.crop_width_set=JCROP_POS;
747 }
748 if(h!=0)
749 {
750 xinfo.crop_height=h; xinfo.crop_height_set=JCROP_POS;
751 }
752 }
753
754 jcopy_markers_setup(&j->dinfo, JCOPYOPT_NONE);
755 jpeg_read_header(&j->dinfo, TRUE);
756
757 if(!jtransform_request_workspace(&j->dinfo, &xinfo))
758 _throw("Transform is not perfect");
759
760 if(!xinfo.crop)
761 {
762 w=j->dinfo.image_width; h=j->dinfo.image_height;
763 }
764 else
765 {
766 w=xinfo.crop_width; h=xinfo.crop_height;
767 }
768
769 j->jdms.next_output_byte=dstbuf;
770 j->jdms.free_in_buffer=TJBUFSIZE(w, h);
771
772 if(xinfo.crop)
773 {
774 if((x%xinfo.iMCU_sample_width)!=0 || (y%xinfo.iMCU_sample_height)!=0)
775 {
776 sprintf(lasterror, "To crop this JPEG image, x must be a multiple of %d and y must be a multiple\n"
777 "of %d.\n", xinfo.iMCU_sample_width, xinfo.iMCU_sample_height);
778 retval=-1; goto bailout;
779 }
780 }
781
782 srccoefs=jpeg_read_coefficients(&j->dinfo);
783 jpeg_copy_critical_parameters(&j->dinfo, &j->cinfo);
784 dstcoefs=jtransform_adjust_parameters(&j->dinfo, &j->cinfo, srccoefs,
785 &xinfo);
786 jpeg_write_coefficients(&j->cinfo, dstcoefs);
787 jcopy_markers_execute(&j->dinfo, &j->cinfo, JCOPYOPT_ALL);
788 jtransform_execute_transformation(&j->dinfo, &j->cinfo, srccoefs, &xinfo);
789
790 jpeg_finish_compress(&j->cinfo);
791 jpeg_finish_decompress(&j->dinfo);
792
793 *dstsize=TJBUFSIZE(w, h)-(unsigned long)(j->jdms.free_in_buffer);
794
795 bailout:
796 if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
797 if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
798 return retval;
799}
800
801
DRC2e7b76b2009-04-03 12:04:24 +0000802// General
803
804DLLEXPORT char* DLLCALL tjGetErrorStr(void)
805{
806 return lasterror;
807}
808
809DLLEXPORT int DLLCALL tjDestroy(tjhandle h)
810{
811 checkhandle(h);
812 if(setjmp(j->jerr.jb)) return -1;
813 if(j->initc) jpeg_destroy_compress(&j->cinfo);
814 if(j->initd) jpeg_destroy_decompress(&j->dinfo);
815 free(j);
816 return 0;
817}