blob: dc1578d17caa6af5f3f3848cb006df65fc3ca71a [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"
DRCda5220a2011-03-02 02:17:30 +000026#include "./rrutil.h"
DRC890f1e02011-02-26 22:02:37 +000027#include "transupp.h"
DRC2a2e4512011-01-05 22:33:24 +000028
DRCfbb67472010-11-24 04:02:37 +000029#ifndef min
30 #define min(a,b) ((a)<(b)?(a):(b))
31#endif
32
33#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
DRC2e7b76b2009-04-03 12:04:24 +000034
35
36// Error handling
37
38static char lasterror[JMSG_LENGTH_MAX]="No error";
39
40typedef struct _error_mgr
41{
42 struct jpeg_error_mgr pub;
43 jmp_buf jb;
44} error_mgr;
45
46static void my_error_exit(j_common_ptr cinfo)
47{
48 error_mgr *myerr = (error_mgr *)cinfo->err;
49 (*cinfo->err->output_message)(cinfo);
50 longjmp(myerr->jb, 1);
51}
52
53static void my_output_message(j_common_ptr cinfo)
54{
55 (*cinfo->err->format_message)(cinfo, lasterror);
56}
57
58
59// Global structures, macros, etc.
60
61typedef struct _jpgstruct
62{
63 struct jpeg_compress_struct cinfo;
64 struct jpeg_decompress_struct dinfo;
65 struct jpeg_destination_mgr jdms;
66 struct jpeg_source_mgr jsms;
67 error_mgr jerr;
68 int initc, initd;
69} jpgstruct;
70
71static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1};
72static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1};
DRC1fe80f82010-12-14 01:21:29 +000073static const int pixelsize[NUMSUBOPT]={3, 3, 3, 1};
DRC890f1e02011-02-26 22:02:37 +000074static const JXFORM_CODE xformtypes[NUMXFORMOPT]={
75 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
76 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
77};
DRC109a5782011-03-01 09:53:07 +000078#define NUMSF 4
79static const tjscalingfactor sf[NUMSF]={
80 {1, 1},
81 {1, 2},
82 {1, 4},
83 {1, 8}
84};
DRC2e7b76b2009-04-03 12:04:24 +000085
DRCda5220a2011-03-02 02:17:30 +000086#define _throw(c) {snprintf(lasterror, JMSG_LENGTH_MAX, "%s", c); \
87 retval=-1; goto bailout;}
DRC2e7b76b2009-04-03 12:04:24 +000088#define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
DRCda5220a2011-03-02 02:17:30 +000089 if(!j) {snprintf(lasterror, JMSG_LENGTH_MAX, "Invalid handle"); return -1;}
DRC2e7b76b2009-04-03 12:04:24 +000090
91
92// CO
93
94static boolean empty_output_buffer(struct jpeg_compress_struct *cinfo)
95{
96 ERREXIT(cinfo, JERR_BUFFER_SIZE);
97 return TRUE;
98}
99
100static void destination_noop(struct jpeg_compress_struct *cinfo)
101{
102}
103
DRC890f1e02011-02-26 22:02:37 +0000104static tjhandle _tjInitCompress(jpgstruct *j)
DRC2e7b76b2009-04-03 12:04:24 +0000105{
DRC2e7b76b2009-04-03 12:04:24 +0000106 j->cinfo.err=jpeg_std_error(&j->jerr.pub);
107 j->jerr.pub.error_exit=my_error_exit;
108 j->jerr.pub.output_message=my_output_message;
109
110 if(setjmp(j->jerr.jb))
111 { // this will execute if LIBJPEG has an error
112 if(j) free(j); return NULL;
DRCefa4ddc2010-10-13 19:22:50 +0000113 }
DRC2e7b76b2009-04-03 12:04:24 +0000114
115 jpeg_create_compress(&j->cinfo);
116 j->cinfo.dest=&j->jdms;
117 j->jdms.init_destination=destination_noop;
118 j->jdms.empty_output_buffer=empty_output_buffer;
119 j->jdms.term_destination=destination_noop;
120
121 j->initc=1;
122 return (tjhandle)j;
123}
124
DRC890f1e02011-02-26 22:02:37 +0000125DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
126{
127 jpgstruct *j=NULL;
128 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000129 {
130 snprintf(lasterror, JMSG_LENGTH_MAX, "Memory allocation failure");
131 return NULL;
132 }
DRC890f1e02011-02-26 22:02:37 +0000133 memset(j, 0, sizeof(jpgstruct));
134 return _tjInitCompress(j);
135}
136
DRC84241602011-02-25 02:08:23 +0000137
DRC2e7b76b2009-04-03 12:04:24 +0000138DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
139{
DRCf3cf9732011-02-22 00:16:14 +0000140 unsigned long retval=0;
141 if(width<1 || height<1)
142 _throw("Invalid argument in TJBUFSIZE()");
143
144 // This allows for rare corner cases in which a JPEG image can actually be
145 // larger than the uncompressed input (we wouldn't mention it if it hadn't
DRCb28fc572011-02-22 06:41:29 +0000146 // happened before.)
DRCf3cf9732011-02-22 00:16:14 +0000147 retval=((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
148
149 bailout:
150 return retval;
151}
152
DRC84241602011-02-25 02:08:23 +0000153
DRCf3cf9732011-02-22 00:16:14 +0000154DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
155 int subsamp)
156{
157 unsigned long retval=0;
158 int pw, ph, cw, ch;
159 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
160 _throw("Invalid argument in TJBUFSIZEYUV()");
161 pw=PAD(width, hsampfactor[subsamp]);
162 ph=PAD(height, vsampfactor[subsamp]);
163 cw=pw/hsampfactor[subsamp]; ch=ph/vsampfactor[subsamp];
164 retval=PAD(pw, 4)*ph + (subsamp==TJ_GRAYSCALE? 0:PAD(cw, 4)*ch*2);
165
166 bailout:
167 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000168}
169
DRC84241602011-02-25 02:08:23 +0000170
DRC2e7b76b2009-04-03 12:04:24 +0000171DLLEXPORT int DLLCALL tjCompress(tjhandle h,
172 unsigned char *srcbuf, int width, int pitch, int height, int ps,
173 unsigned char *dstbuf, unsigned long *size,
174 int jpegsub, int qual, int flags)
175{
DRC91e86ba2011-02-15 05:24:08 +0000176 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000177 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
178 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
179 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC2e7b76b2009-04-03 12:04:24 +0000180
181 checkhandle(h);
182
DRCfbb67472010-11-24 04:02:37 +0000183 for(i=0; i<MAX_COMPONENTS; i++)
184 {
185 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
186 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
187 }
188
DRC2e7b76b2009-04-03 12:04:24 +0000189 if(srcbuf==NULL || width<=0 || pitch<0 || height<=0
190 || dstbuf==NULL || size==NULL
191 || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100)
192 _throw("Invalid argument in tjCompress()");
DRC09854f52010-11-04 22:39:59 +0000193 if(ps!=3 && ps!=4 && ps!=1)
194 _throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input");
DRC2e7b76b2009-04-03 12:04:24 +0000195 if(!j->initc) _throw("Instance has not been initialized for compression");
196
197 if(pitch==0) pitch=width*ps;
198
199 j->cinfo.image_width = width;
200 j->cinfo.image_height = height;
201 j->cinfo.input_components = ps;
202
DRC09854f52010-11-04 22:39:59 +0000203 if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE;
DRC2e7b76b2009-04-03 12:04:24 +0000204 #if JCS_EXTENSIONS==1
DRC09854f52010-11-04 22:39:59 +0000205 else j->cinfo.in_color_space = JCS_EXT_RGB;
DRC2e7b76b2009-04-03 12:04:24 +0000206 if(ps==3 && (flags&TJ_BGR))
207 j->cinfo.in_color_space = JCS_EXT_BGR;
208 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
209 j->cinfo.in_color_space = JCS_EXT_RGBX;
210 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
211 j->cinfo.in_color_space = JCS_EXT_BGRX;
212 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
213 j->cinfo.in_color_space = JCS_EXT_XBGR;
214 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
215 j->cinfo.in_color_space = JCS_EXT_XRGB;
216 #else
217 #error "TurboJPEG requires JPEG colorspace extensions"
218 #endif
219
DRC0c6a2712010-02-22 08:34:44 +0000220 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
221 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
222 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
223
DRC2e7b76b2009-04-03 12:04:24 +0000224 if(setjmp(j->jerr.jb))
225 { // this will execute if LIBJPEG has an error
DRC91e86ba2011-02-15 05:24:08 +0000226 retval=-1;
227 goto bailout;
DRCefa4ddc2010-10-13 19:22:50 +0000228 }
DRC2e7b76b2009-04-03 12:04:24 +0000229
230 jpeg_set_defaults(&j->cinfo);
231
232 jpeg_set_quality(&j->cinfo, qual, TRUE);
233 if(jpegsub==TJ_GRAYSCALE)
234 jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE);
235 else
236 jpeg_set_colorspace(&j->cinfo, JCS_YCbCr);
DRCe1716b82011-02-18 03:19:43 +0000237 if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW;
238 else j->cinfo.dct_method=JDCT_FASTEST;
DRC2e7b76b2009-04-03 12:04:24 +0000239
240 j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub];
241 j->cinfo.comp_info[1].h_samp_factor=1;
242 j->cinfo.comp_info[2].h_samp_factor=1;
243 j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub];
244 j->cinfo.comp_info[1].v_samp_factor=1;
245 j->cinfo.comp_info[2].v_samp_factor=1;
246
247 j->jdms.next_output_byte = dstbuf;
248 j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height);
249
DRC2e7b76b2009-04-03 12:04:24 +0000250 jpeg_start_compress(&j->cinfo, TRUE);
DRCfbb67472010-11-24 04:02:37 +0000251 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000252 {
DRCfbb67472010-11-24 04:02:37 +0000253 j_compress_ptr cinfo=&j->cinfo;
254 int row;
255 int pw=PAD(width, cinfo->max_h_samp_factor);
256 int ph=PAD(height, cinfo->max_v_samp_factor);
257 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
258 jpeg_component_info *compptr;
259 JSAMPLE *ptr=dstbuf; unsigned long yuvsize=0;
260
261 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
262 _throw("Memory allocation failed in tjCompress()");
263 for(i=0; i<height; i++)
264 {
265 if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
266 else row_pointer[i]= &srcbuf[i*pitch];
267 }
268 if(height<ph)
269 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
270
271 for(i=0; i<cinfo->num_components; i++)
272 {
273 compptr=&cinfo->comp_info[i];
DRC57423072011-01-05 23:35:53 +0000274 _tmpbuf[i]=(JSAMPLE *)malloc(
DRCfbb67472010-11-24 04:02:37 +0000275 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC57423072011-01-05 23:35:53 +0000276 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRCfbb67472010-11-24 04:02:37 +0000277 if(!_tmpbuf[i]) _throw("Memory allocation failure");
DRC2a2e4512011-01-05 22:33:24 +0000278 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCfbb67472010-11-24 04:02:37 +0000279 if(!tmpbuf[i]) _throw("Memory allocation failure");
280 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRC57423072011-01-05 23:35:53 +0000281 {
282 unsigned char *_tmpbuf_aligned=
283 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
284 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000285 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
286 /compptr->h_samp_factor, 16) * row];
DRC57423072011-01-05 23:35:53 +0000287 }
288 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
289 * compptr->v_samp_factor + 16);
DRCfbb67472010-11-24 04:02:37 +0000290 if(!_tmpbuf2[i]) _throw("Memory allocation failure");
DRC2a2e4512011-01-05 22:33:24 +0000291 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCfbb67472010-11-24 04:02:37 +0000292 if(!tmpbuf2[i]) _throw("Memory allocation failure");
293 for(row=0; row<compptr->v_samp_factor; row++)
DRC57423072011-01-05 23:35:53 +0000294 {
295 unsigned char *_tmpbuf2_aligned=
296 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
297 tmpbuf2[i][row]=&_tmpbuf2_aligned[
DRCfbb67472010-11-24 04:02:37 +0000298 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
DRC57423072011-01-05 23:35:53 +0000299 }
DRCfbb67472010-11-24 04:02:37 +0000300 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
301 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
DRC2a2e4512011-01-05 22:33:24 +0000302 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
DRCfbb67472010-11-24 04:02:37 +0000303 if(!outbuf[i]) _throw("Memory allocation failure");
304 for(row=0; row<ch[i]; row++)
305 {
306 outbuf[i][row]=ptr;
307 ptr+=PAD(cw[i], 4);
308 }
309 }
310 yuvsize=(unsigned long)(ptr-dstbuf);
311
312 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
313 {
314 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf,
315 0, cinfo->max_v_samp_factor);
316 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
317 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components;
318 i++, compptr++)
319 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
320 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
321 compptr->v_samp_factor, cw[i]);
322 }
323 *size=yuvsize;
324 cinfo->next_scanline+=height;
DRC6ee54592011-03-01 08:18:30 +0000325 jpeg_abort_compress(&j->cinfo);
DRCfbb67472010-11-24 04:02:37 +0000326 }
327 else
328 {
329 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
330 _throw("Memory allocation failed in tjCompress()");
331 for(i=0; i<height; i++)
332 {
333 if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
334 else row_pointer[i]= &srcbuf[i*pitch];
335 }
336 while(j->cinfo.next_scanline<j->cinfo.image_height)
337 {
338 jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
339 j->cinfo.image_height-j->cinfo.next_scanline);
340 }
DRC6ee54592011-03-01 08:18:30 +0000341 jpeg_finish_compress(&j->cinfo);
DRCfbb67472010-11-24 04:02:37 +0000342 *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)
343 -(unsigned long)(j->jdms.free_in_buffer);
DRC6ee54592011-03-01 08:18:30 +0000344 }
DRC2e7b76b2009-04-03 12:04:24 +0000345
DRC91e86ba2011-02-15 05:24:08 +0000346 bailout:
DRCb28fc572011-02-22 06:41:29 +0000347 if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000348 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000349 for(i=0; i<MAX_COMPONENTS; i++)
350 {
351 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000352 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000353 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000354 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000355 if(outbuf[i]!=NULL) free(outbuf[i]);
356 }
DRC91e86ba2011-02-15 05:24:08 +0000357 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000358}
359
360
DRC84241602011-02-25 02:08:23 +0000361DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle h,
362 unsigned char *srcbuf, int width, int pitch, int height, int ps,
363 unsigned char *dstbuf, int subsamp, int flags)
364{
365 unsigned long size;
366 return tjCompress(h, srcbuf, width, pitch, height, ps, dstbuf, &size,
367 subsamp, 0, flags|TJ_YUV);
368}
369
370
DRC2e7b76b2009-04-03 12:04:24 +0000371// DEC
372
373static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo)
374{
375 ERREXIT(dinfo, JERR_BUFFER_SIZE);
376 return TRUE;
377}
378
379static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes)
380{
381 dinfo->src->next_input_byte += (size_t) num_bytes;
382 dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
383}
384
385static void source_noop (struct jpeg_decompress_struct *dinfo)
386{
387}
388
DRC890f1e02011-02-26 22:02:37 +0000389static tjhandle _tjInitDecompress(jpgstruct *j)
DRC2e7b76b2009-04-03 12:04:24 +0000390{
DRC2e7b76b2009-04-03 12:04:24 +0000391 j->dinfo.err=jpeg_std_error(&j->jerr.pub);
392 j->jerr.pub.error_exit=my_error_exit;
393 j->jerr.pub.output_message=my_output_message;
394
395 if(setjmp(j->jerr.jb))
396 { // this will execute if LIBJPEG has an error
397 free(j); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +0000398 }
DRC2e7b76b2009-04-03 12:04:24 +0000399
400 jpeg_create_decompress(&j->dinfo);
401 j->dinfo.src=&j->jsms;
402 j->jsms.init_source=source_noop;
403 j->jsms.fill_input_buffer = fill_input_buffer;
404 j->jsms.skip_input_data = skip_input_data;
405 j->jsms.resync_to_restart = jpeg_resync_to_restart;
406 j->jsms.term_source = source_noop;
407
408 j->initd=1;
409 return (tjhandle)j;
410}
411
DRC890f1e02011-02-26 22:02:37 +0000412DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
413{
414 jpgstruct *j;
415 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000416 {
417 snprintf(lasterror, JMSG_LENGTH_MAX, "Memory allocation failure");
418 return NULL;
419 }
DRC890f1e02011-02-26 22:02:37 +0000420 memset(j, 0, sizeof(jpgstruct));
421 return _tjInitDecompress(j);
422}
423
DRC2e7b76b2009-04-03 12:04:24 +0000424
DRC1fe80f82010-12-14 01:21:29 +0000425DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle h,
426 unsigned char *srcbuf, unsigned long size,
427 int *width, int *height, int *jpegsub)
428{
DRC91e86ba2011-02-15 05:24:08 +0000429 int i, k, retval=0;
DRC1fe80f82010-12-14 01:21:29 +0000430
431 checkhandle(h);
432
433 if(srcbuf==NULL || size<=0 || width==NULL || height==NULL || jpegsub==NULL)
DRC91e86ba2011-02-15 05:24:08 +0000434 _throw("Invalid argument in tjDecompressHeader2()");
DRC1fe80f82010-12-14 01:21:29 +0000435 if(!j->initd) _throw("Instance has not been initialized for decompression");
436
437 if(setjmp(j->jerr.jb))
438 { // this will execute if LIBJPEG has an error
439 return -1;
440 }
441
442 j->jsms.bytes_in_buffer = size;
443 j->jsms.next_input_byte = srcbuf;
444
445 jpeg_read_header(&j->dinfo, TRUE);
446
447 *width=j->dinfo.image_width; *height=j->dinfo.image_height;
448 *jpegsub=-1;
449 for(i=0; i<NUMSUBOPT; i++)
450 {
451 if(j->dinfo.num_components==pixelsize[i])
452 {
453 if(j->dinfo.comp_info[0].h_samp_factor==hsampfactor[i]
454 && j->dinfo.comp_info[0].v_samp_factor==vsampfactor[i])
455 {
456 int match=0;
457 for(k=1; k<j->dinfo.num_components; k++)
458 {
459 if(j->dinfo.comp_info[k].h_samp_factor==1
460 && j->dinfo.comp_info[k].v_samp_factor==1)
461 match++;
462 }
463 if(match==j->dinfo.num_components-1)
464 {
465 *jpegsub=i; break;
466 }
467 }
468 }
469 }
470
471 jpeg_abort_decompress(&j->dinfo);
472
473 if(*jpegsub<0) _throw("Could not determine subsampling type for JPEG image");
474 if(*width<1 || *height<1) _throw("Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +0000475
476 bailout:
477 return retval;
478}
479
480
481DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
482 unsigned char *srcbuf, unsigned long size,
483 int *width, int *height)
484{
485 int jpegsub;
486 return tjDecompressHeader2(h, srcbuf, size, width, height, &jpegsub);
DRC1fe80f82010-12-14 01:21:29 +0000487}
488
489
DRC109a5782011-03-01 09:53:07 +0000490DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +0000491{
DRC109a5782011-03-01 09:53:07 +0000492 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +0000493 {
DRCda5220a2011-03-02 02:17:30 +0000494 snprintf(lasterror, JMSG_LENGTH_MAX,
495 "Invalid argument in tjGetScalingFactors()");
DRC109a5782011-03-01 09:53:07 +0000496 return NULL;
DRCb28fc572011-02-22 06:41:29 +0000497 }
498
DRC109a5782011-03-01 09:53:07 +0000499 *numscalingfactors=NUMSF;
500 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +0000501}
502
503
504DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
DRC2e7b76b2009-04-03 12:04:24 +0000505 unsigned char *srcbuf, unsigned long size,
DRCb28fc572011-02-22 06:41:29 +0000506 unsigned char *dstbuf, int width, int pitch, int height, int ps,
507 int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000508{
DRC91e86ba2011-02-15 05:24:08 +0000509 int i, row, retval=0; JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
DRCf9cf5c72010-12-10 10:58:49 +0000510 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
511 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
512 JSAMPLE *_tmpbuf=NULL; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC109a5782011-03-01 09:53:07 +0000513 int jpegwidth, jpegheight, scaledw, scaledh;
DRC2e7b76b2009-04-03 12:04:24 +0000514
515 checkhandle(h);
516
DRCf9cf5c72010-12-10 10:58:49 +0000517 for(i=0; i<MAX_COMPONENTS; i++)
518 {
519 tmpbuf[i]=NULL; outbuf[i]=NULL;
520 }
DRC9e17f7d2010-12-10 04:59:13 +0000521
DRCb28fc572011-02-22 06:41:29 +0000522 if(srcbuf==NULL || size<=0
523 || dstbuf==NULL || width<0 || pitch<0 || height<0)
524 _throw("Invalid argument in tjDecompress()");
DRC09854f52010-11-04 22:39:59 +0000525 if(ps!=3 && ps!=4 && ps!=1)
526 _throw("This decompressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale output");
DRC2e7b76b2009-04-03 12:04:24 +0000527 if(!j->initd) _throw("Instance has not been initialized for decompression");
528
DRC0c6a2712010-02-22 08:34:44 +0000529 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
530 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
531 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
532
DRC2e7b76b2009-04-03 12:04:24 +0000533 if(setjmp(j->jerr.jb))
534 { // this will execute if LIBJPEG has an error
DRC91e86ba2011-02-15 05:24:08 +0000535 retval=-1;
536 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +0000537 }
DRC2e7b76b2009-04-03 12:04:24 +0000538
539 j->jsms.bytes_in_buffer = size;
540 j->jsms.next_input_byte = srcbuf;
541
542 jpeg_read_header(&j->dinfo, TRUE);
543
DRC9e17f7d2010-12-10 04:59:13 +0000544 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000545 {
DRC9e17f7d2010-12-10 04:59:13 +0000546 j_decompress_ptr dinfo=&j->dinfo;
547 JSAMPLE *ptr=dstbuf;
548
549 for(i=0; i<dinfo->num_components; i++)
550 {
551 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRCf9cf5c72010-12-10 10:58:49 +0000552 int ih;
553 iw[i]=compptr->width_in_blocks*DCTSIZE;
554 ih=compptr->height_in_blocks*DCTSIZE;
DRC8ed7b812011-02-15 08:31:34 +0000555 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
556 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
557 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
558 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRCa6f4fca2010-12-11 06:01:11 +0000559 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
560 th[i]=compptr->v_samp_factor*DCTSIZE;
561 tmpbufsize+=iw[i]*th[i];
DRC9e17f7d2010-12-10 04:59:13 +0000562 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
DRC84241602011-02-25 02:08:23 +0000563 _throw("Memory allocation failed in tjDecompress()");
DRC9e17f7d2010-12-10 04:59:13 +0000564 for(row=0; row<ch[i]; row++)
565 {
566 outbuf[i][row]=ptr;
DRCf9cf5c72010-12-10 10:58:49 +0000567 ptr+=PAD(cw[i], 4);
568 }
569 }
570 if(usetmpbuf)
571 {
572 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRC84241602011-02-25 02:08:23 +0000573 _throw("Memory allocation failed in tjDecompress()");
DRCf9cf5c72010-12-10 10:58:49 +0000574 ptr=_tmpbuf;
575 for(i=0; i<dinfo->num_components; i++)
576 {
DRCf9cf5c72010-12-10 10:58:49 +0000577 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRC84241602011-02-25 02:08:23 +0000578 _throw("Memory allocation failed in tjDecompress()");
DRCf9cf5c72010-12-10 10:58:49 +0000579 for(row=0; row<th[i]; row++)
580 {
581 tmpbuf[i][row]=ptr;
582 ptr+=iw[i];
583 }
DRC9e17f7d2010-12-10 04:59:13 +0000584 }
585 }
586 }
DRC2e7b76b2009-04-03 12:04:24 +0000587
DRC09854f52010-11-04 22:39:59 +0000588 if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE;
DRC2e7b76b2009-04-03 12:04:24 +0000589 #if JCS_EXTENSIONS==1
DRC09854f52010-11-04 22:39:59 +0000590 else j->dinfo.out_color_space = JCS_EXT_RGB;
DRC2e7b76b2009-04-03 12:04:24 +0000591 if(ps==3 && (flags&TJ_BGR))
592 j->dinfo.out_color_space = JCS_EXT_BGR;
593 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
594 j->dinfo.out_color_space = JCS_EXT_RGBX;
595 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
596 j->dinfo.out_color_space = JCS_EXT_BGRX;
597 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
598 j->dinfo.out_color_space = JCS_EXT_XBGR;
599 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
600 j->dinfo.out_color_space = JCS_EXT_XRGB;
601 #else
602 #error "TurboJPEG requires JPEG colorspace extensions"
603 #endif
DRCfbb67472010-11-24 04:02:37 +0000604
DRC61e51f92009-04-05 21:53:20 +0000605 if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
DRC9e17f7d2010-12-10 04:59:13 +0000606 if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE;
DRC8ed7b812011-02-15 08:31:34 +0000607 else
608 {
DRC84241602011-02-25 02:08:23 +0000609 jpegwidth=j->dinfo.image_width; jpegheight=j->dinfo.image_height;
610 if(width==0) width=jpegwidth;
611 if(height==0) height=jpegheight;
DRC109a5782011-03-01 09:53:07 +0000612 for(i=0; i<NUMSF; i++)
DRC84241602011-02-25 02:08:23 +0000613 {
DRC109a5782011-03-01 09:53:07 +0000614 scaledw=(jpegwidth*sf[i].num+sf[i].denom-1)/sf[i].denom;
615 scaledh=(jpegheight*sf[i].num+sf[i].denom-1)/sf[i].denom;
616 if(scaledw<=width && scaledh<=height)
DRC84241602011-02-25 02:08:23 +0000617 break;
DRC84241602011-02-25 02:08:23 +0000618 }
DRC109a5782011-03-01 09:53:07 +0000619 if(scaledw>width || scaledh>height)
620 _throw("Could not scale down to desired image dimensions");
621 width=scaledw; height=scaledh;
622 j->dinfo.scale_num=sf[i].num;
623 j->dinfo.scale_denom=sf[i].denom;
DRC8ed7b812011-02-15 08:31:34 +0000624 }
DRC2e7b76b2009-04-03 12:04:24 +0000625
626 jpeg_start_decompress(&j->dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000627 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000628 {
DRCf9cf5c72010-12-10 10:58:49 +0000629 j_decompress_ptr dinfo=&j->dinfo;
DRC43a29d22011-03-02 01:27:26 +0000630 for(row=0; row<(int)dinfo->output_height;
DRCf9cf5c72010-12-10 10:58:49 +0000631 row+=dinfo->max_v_samp_factor*DCTSIZE)
DRC9e17f7d2010-12-10 04:59:13 +0000632 {
633 JSAMPARRAY yuvptr[MAX_COMPONENTS];
DRCa6f4fca2010-12-11 06:01:11 +0000634 int crow[MAX_COMPONENTS];
DRCf9cf5c72010-12-10 10:58:49 +0000635 for(i=0; i<dinfo->num_components; i++)
DRC9e17f7d2010-12-10 04:59:13 +0000636 {
DRCf9cf5c72010-12-10 10:58:49 +0000637 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRCa6f4fca2010-12-11 06:01:11 +0000638 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRCf9cf5c72010-12-10 10:58:49 +0000639 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
DRCa6f4fca2010-12-11 06:01:11 +0000640 else yuvptr[i]=&outbuf[i][crow[i]];
DRC9e17f7d2010-12-10 04:59:13 +0000641 }
DRCf9cf5c72010-12-10 10:58:49 +0000642 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
643 if(usetmpbuf)
644 {
645 int j;
646 for(i=0; i<dinfo->num_components; i++)
647 {
DRCa6f4fca2010-12-11 06:01:11 +0000648 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +0000649 {
DRCa6f4fca2010-12-11 06:01:11 +0000650 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000651 }
652 }
653 }
DRC9e17f7d2010-12-10 04:59:13 +0000654 }
655 }
656 else
657 {
DRC8ed7b812011-02-15 08:31:34 +0000658 if(pitch==0) pitch=j->dinfo.output_width*ps;
659 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
660 *j->dinfo.output_height))==NULL)
DRC8ed7b812011-02-15 08:31:34 +0000661 _throw("Memory allocation failed in tjInitDecompress()");
DRC43a29d22011-03-02 01:27:26 +0000662 for(i=0; i<(int)j->dinfo.output_height; i++)
DRC8ed7b812011-02-15 08:31:34 +0000663 {
664 if(flags&TJ_BOTTOMUP)
665 row_pointer[i]= &dstbuf[(j->dinfo.output_height-i-1)*pitch];
666 else row_pointer[i]= &dstbuf[i*pitch];
667 }
DRC9e17f7d2010-12-10 04:59:13 +0000668 while(j->dinfo.output_scanline<j->dinfo.output_height)
669 {
670 jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
671 j->dinfo.output_height-j->dinfo.output_scanline);
672 }
DRC2e7b76b2009-04-03 12:04:24 +0000673 }
674 jpeg_finish_decompress(&j->dinfo);
675
DRC91e86ba2011-02-15 05:24:08 +0000676 bailout:
DRCb28fc572011-02-22 06:41:29 +0000677 if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000678 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +0000679 {
680 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +0000681 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000682 }
683 if(_tmpbuf) free(_tmpbuf);
DRC2e7b76b2009-04-03 12:04:24 +0000684 if(row_pointer) free(row_pointer);
DRC91e86ba2011-02-15 05:24:08 +0000685 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000686}
687
688
DRC84241602011-02-25 02:08:23 +0000689DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle h,
690 unsigned char *srcbuf, unsigned long size,
691 unsigned char *dstbuf, int flags)
692{
693 return tjDecompress(h, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV);
694}
695
696
DRC890f1e02011-02-26 22:02:37 +0000697// Transformation
698
699DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
700{
701 jpgstruct *j=NULL; tjhandle tj=NULL;
702 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000703 {
704 snprintf(lasterror, JMSG_LENGTH_MAX, "Memory allocation failure");
705 return NULL;
706 }
DRC890f1e02011-02-26 22:02:37 +0000707 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 {
DRCda5220a2011-03-02 02:17:30 +0000788 snprintf(lasterror, JMSG_LENGTH_MAX,
789 "To crop this JPEG image, x must be a multiple of %d and y must be a multiple\n"
DRC890f1e02011-02-26 22:02:37 +0000790 "of %d.\n", xinfo.iMCU_sample_width, xinfo.iMCU_sample_height);
791 retval=-1; goto bailout;
792 }
793 }
794
795 srccoefs=jpeg_read_coefficients(&j->dinfo);
796 jpeg_copy_critical_parameters(&j->dinfo, &j->cinfo);
797 dstcoefs=jtransform_adjust_parameters(&j->dinfo, &j->cinfo, srccoefs,
798 &xinfo);
799 jpeg_write_coefficients(&j->cinfo, dstcoefs);
800 jcopy_markers_execute(&j->dinfo, &j->cinfo, JCOPYOPT_ALL);
801 jtransform_execute_transformation(&j->dinfo, &j->cinfo, srccoefs, &xinfo);
802
803 jpeg_finish_compress(&j->cinfo);
804 jpeg_finish_decompress(&j->dinfo);
805
806 *dstsize=TJBUFSIZE(w, h)-(unsigned long)(j->jdms.free_in_buffer);
807
808 bailout:
809 if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
810 if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
811 return retval;
812}
813
814
DRC2e7b76b2009-04-03 12:04:24 +0000815// General
816
817DLLEXPORT char* DLLCALL tjGetErrorStr(void)
818{
819 return lasterror;
820}
821
822DLLEXPORT int DLLCALL tjDestroy(tjhandle h)
823{
824 checkhandle(h);
825 if(setjmp(j->jerr.jb)) return -1;
826 if(j->initc) jpeg_destroy_compress(&j->cinfo);
827 if(j->initd) jpeg_destroy_decompress(&j->dinfo);
828 free(j);
829 return 0;
830}