blob: 266e335df9f5d586dc2594a5a3b57266e5384905 [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
DRCa3f68b42011-03-04 12:52:45 +000071static const int pixelsize[NUMSUBOPT]={3, 3, 3, 1, 3};
DRC890f1e02011-02-26 22:02:37 +000072static const JXFORM_CODE xformtypes[NUMXFORMOPT]={
73 JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
74 JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
75};
DRC109a5782011-03-01 09:53:07 +000076#define NUMSF 4
77static const tjscalingfactor sf[NUMSF]={
78 {1, 1},
79 {1, 2},
80 {1, 4},
81 {1, 8}
82};
DRC2e7b76b2009-04-03 12:04:24 +000083
DRCda5220a2011-03-02 02:17:30 +000084#define _throw(c) {snprintf(lasterror, JMSG_LENGTH_MAX, "%s", c); \
85 retval=-1; goto bailout;}
DRC0a325192011-03-02 09:22:41 +000086#define checkhandle(hnd) jpgstruct *j=(jpgstruct *)hnd; \
DRCda5220a2011-03-02 02:17:30 +000087 if(!j) {snprintf(lasterror, JMSG_LENGTH_MAX, "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)
DRCda5220a2011-03-02 02:17:30 +0000127 {
128 snprintf(lasterror, JMSG_LENGTH_MAX, "Memory allocation failure");
129 return NULL;
130 }
DRC890f1e02011-02-26 22:02:37 +0000131 memset(j, 0, sizeof(jpgstruct));
132 return _tjInitCompress(j);
133}
134
DRC84241602011-02-25 02:08:23 +0000135
DRC2e7b76b2009-04-03 12:04:24 +0000136DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
137{
DRCf3cf9732011-02-22 00:16:14 +0000138 unsigned long retval=0;
139 if(width<1 || height<1)
140 _throw("Invalid argument in TJBUFSIZE()");
141
142 // This allows for rare corner cases in which a JPEG image can actually be
143 // larger than the uncompressed input (we wouldn't mention it if it hadn't
DRCb28fc572011-02-22 06:41:29 +0000144 // happened before.)
DRCf3cf9732011-02-22 00:16:14 +0000145 retval=((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
146
147 bailout:
148 return retval;
149}
150
DRC84241602011-02-25 02:08:23 +0000151
DRCf3cf9732011-02-22 00:16:14 +0000152DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
153 int subsamp)
154{
155 unsigned long retval=0;
156 int pw, ph, cw, ch;
157 if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
158 _throw("Invalid argument in TJBUFSIZEYUV()");
DRC0a325192011-03-02 09:22:41 +0000159 pw=PAD(width, tjmcuw[subsamp]/8);
160 ph=PAD(height, tjmcuh[subsamp]/8);
161 cw=pw*8/tjmcuw[subsamp]; ch=ph*8/tjmcuh[subsamp];
DRCf3cf9732011-02-22 00:16:14 +0000162 retval=PAD(pw, 4)*ph + (subsamp==TJ_GRAYSCALE? 0:PAD(cw, 4)*ch*2);
163
164 bailout:
165 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000166}
167
DRC84241602011-02-25 02:08:23 +0000168
DRC0a325192011-03-02 09:22:41 +0000169DLLEXPORT int DLLCALL tjCompress(tjhandle hnd,
DRC2e7b76b2009-04-03 12:04:24 +0000170 unsigned char *srcbuf, int width, int pitch, int height, int ps,
171 unsigned char *dstbuf, unsigned long *size,
172 int jpegsub, int qual, int flags)
173{
DRC91e86ba2011-02-15 05:24:08 +0000174 int i, retval=0; JSAMPROW *row_pointer=NULL;
DRCfbb67472010-11-24 04:02:37 +0000175 JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
176 JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
177 JSAMPROW *outbuf[MAX_COMPONENTS];
DRC2e7b76b2009-04-03 12:04:24 +0000178
DRC0a325192011-03-02 09:22:41 +0000179 checkhandle(hnd);
DRC2e7b76b2009-04-03 12:04:24 +0000180
DRCfbb67472010-11-24 04:02:37 +0000181 for(i=0; i<MAX_COMPONENTS; i++)
182 {
183 tmpbuf[i]=NULL; _tmpbuf[i]=NULL;
184 tmpbuf2[i]=NULL; _tmpbuf2[i]=NULL; outbuf[i]=NULL;
185 }
186
DRC2e7b76b2009-04-03 12:04:24 +0000187 if(srcbuf==NULL || width<=0 || pitch<0 || height<=0
188 || dstbuf==NULL || size==NULL
189 || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100)
190 _throw("Invalid argument in tjCompress()");
DRC09854f52010-11-04 22:39:59 +0000191 if(ps!=3 && ps!=4 && ps!=1)
192 _throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input");
DRC2e7b76b2009-04-03 12:04:24 +0000193 if(!j->initc) _throw("Instance has not been initialized for compression");
194
195 if(pitch==0) pitch=width*ps;
196
197 j->cinfo.image_width = width;
198 j->cinfo.image_height = height;
199 j->cinfo.input_components = ps;
200
DRC09854f52010-11-04 22:39:59 +0000201 if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE;
DRC2e7b76b2009-04-03 12:04:24 +0000202 #if JCS_EXTENSIONS==1
DRC09854f52010-11-04 22:39:59 +0000203 else j->cinfo.in_color_space = JCS_EXT_RGB;
DRC2e7b76b2009-04-03 12:04:24 +0000204 if(ps==3 && (flags&TJ_BGR))
205 j->cinfo.in_color_space = JCS_EXT_BGR;
206 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
207 j->cinfo.in_color_space = JCS_EXT_RGBX;
208 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
209 j->cinfo.in_color_space = JCS_EXT_BGRX;
210 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
211 j->cinfo.in_color_space = JCS_EXT_XBGR;
212 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
213 j->cinfo.in_color_space = JCS_EXT_XRGB;
214 #else
215 #error "TurboJPEG requires JPEG colorspace extensions"
216 #endif
217
DRC0c6a2712010-02-22 08:34:44 +0000218 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
219 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
220 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
221
DRC2e7b76b2009-04-03 12:04:24 +0000222 if(setjmp(j->jerr.jb))
223 { // this will execute if LIBJPEG has an error
DRC91e86ba2011-02-15 05:24:08 +0000224 retval=-1;
225 goto bailout;
DRCefa4ddc2010-10-13 19:22:50 +0000226 }
DRC2e7b76b2009-04-03 12:04:24 +0000227
228 jpeg_set_defaults(&j->cinfo);
229
230 jpeg_set_quality(&j->cinfo, qual, TRUE);
231 if(jpegsub==TJ_GRAYSCALE)
232 jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE);
233 else
234 jpeg_set_colorspace(&j->cinfo, JCS_YCbCr);
DRCe1716b82011-02-18 03:19:43 +0000235 if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW;
236 else j->cinfo.dct_method=JDCT_FASTEST;
DRC2e7b76b2009-04-03 12:04:24 +0000237
DRC0a325192011-03-02 09:22:41 +0000238 j->cinfo.comp_info[0].h_samp_factor=tjmcuw[jpegsub]/8;
DRC2e7b76b2009-04-03 12:04:24 +0000239 j->cinfo.comp_info[1].h_samp_factor=1;
240 j->cinfo.comp_info[2].h_samp_factor=1;
DRC0a325192011-03-02 09:22:41 +0000241 j->cinfo.comp_info[0].v_samp_factor=tjmcuh[jpegsub]/8;
DRC2e7b76b2009-04-03 12:04:24 +0000242 j->cinfo.comp_info[1].v_samp_factor=1;
243 j->cinfo.comp_info[2].v_samp_factor=1;
244
245 j->jdms.next_output_byte = dstbuf;
246 j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height);
247
DRC2e7b76b2009-04-03 12:04:24 +0000248 jpeg_start_compress(&j->cinfo, TRUE);
DRCfbb67472010-11-24 04:02:37 +0000249 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000250 {
DRCfbb67472010-11-24 04:02:37 +0000251 j_compress_ptr cinfo=&j->cinfo;
252 int row;
253 int pw=PAD(width, cinfo->max_h_samp_factor);
254 int ph=PAD(height, cinfo->max_v_samp_factor);
255 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
256 jpeg_component_info *compptr;
257 JSAMPLE *ptr=dstbuf; unsigned long yuvsize=0;
258
259 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
260 _throw("Memory allocation failed in tjCompress()");
261 for(i=0; i<height; i++)
262 {
263 if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
264 else row_pointer[i]= &srcbuf[i*pitch];
265 }
266 if(height<ph)
267 for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
268
269 for(i=0; i<cinfo->num_components; i++)
270 {
271 compptr=&cinfo->comp_info[i];
DRC57423072011-01-05 23:35:53 +0000272 _tmpbuf[i]=(JSAMPLE *)malloc(
DRCfbb67472010-11-24 04:02:37 +0000273 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
DRC57423072011-01-05 23:35:53 +0000274 /compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
DRCfbb67472010-11-24 04:02:37 +0000275 if(!_tmpbuf[i]) _throw("Memory allocation failure");
DRC2a2e4512011-01-05 22:33:24 +0000276 tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
DRCfbb67472010-11-24 04:02:37 +0000277 if(!tmpbuf[i]) _throw("Memory allocation failure");
278 for(row=0; row<cinfo->max_v_samp_factor; row++)
DRC57423072011-01-05 23:35:53 +0000279 {
280 unsigned char *_tmpbuf_aligned=
281 (unsigned char *)PAD((size_t)_tmpbuf[i], 16);
282 tmpbuf[i][row]=&_tmpbuf_aligned[
DRCfbb67472010-11-24 04:02:37 +0000283 PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
284 /compptr->h_samp_factor, 16) * row];
DRC57423072011-01-05 23:35:53 +0000285 }
286 _tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
287 * compptr->v_samp_factor + 16);
DRCfbb67472010-11-24 04:02:37 +0000288 if(!_tmpbuf2[i]) _throw("Memory allocation failure");
DRC2a2e4512011-01-05 22:33:24 +0000289 tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
DRCfbb67472010-11-24 04:02:37 +0000290 if(!tmpbuf2[i]) _throw("Memory allocation failure");
291 for(row=0; row<compptr->v_samp_factor; row++)
DRC57423072011-01-05 23:35:53 +0000292 {
293 unsigned char *_tmpbuf2_aligned=
294 (unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
295 tmpbuf2[i][row]=&_tmpbuf2_aligned[
DRCfbb67472010-11-24 04:02:37 +0000296 PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
DRC57423072011-01-05 23:35:53 +0000297 }
DRCfbb67472010-11-24 04:02:37 +0000298 cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
299 ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
DRC2a2e4512011-01-05 22:33:24 +0000300 outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
DRCfbb67472010-11-24 04:02:37 +0000301 if(!outbuf[i]) _throw("Memory allocation failure");
302 for(row=0; row<ch[i]; row++)
303 {
304 outbuf[i][row]=ptr;
305 ptr+=PAD(cw[i], 4);
306 }
307 }
308 yuvsize=(unsigned long)(ptr-dstbuf);
309
310 for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
311 {
312 (*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf,
313 0, cinfo->max_v_samp_factor);
314 (cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
315 for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components;
316 i++, compptr++)
317 jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
318 row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
319 compptr->v_samp_factor, cw[i]);
320 }
321 *size=yuvsize;
322 cinfo->next_scanline+=height;
DRC6ee54592011-03-01 08:18:30 +0000323 jpeg_abort_compress(&j->cinfo);
DRCfbb67472010-11-24 04:02:37 +0000324 }
325 else
326 {
327 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
328 _throw("Memory allocation failed in tjCompress()");
329 for(i=0; i<height; i++)
330 {
331 if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
332 else row_pointer[i]= &srcbuf[i*pitch];
333 }
334 while(j->cinfo.next_scanline<j->cinfo.image_height)
335 {
336 jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
337 j->cinfo.image_height-j->cinfo.next_scanline);
338 }
DRC6ee54592011-03-01 08:18:30 +0000339 jpeg_finish_compress(&j->cinfo);
DRCfbb67472010-11-24 04:02:37 +0000340 *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)
341 -(unsigned long)(j->jdms.free_in_buffer);
DRC6ee54592011-03-01 08:18:30 +0000342 }
DRC2e7b76b2009-04-03 12:04:24 +0000343
DRC91e86ba2011-02-15 05:24:08 +0000344 bailout:
DRCb28fc572011-02-22 06:41:29 +0000345 if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000346 if(row_pointer) free(row_pointer);
DRCfbb67472010-11-24 04:02:37 +0000347 for(i=0; i<MAX_COMPONENTS; i++)
348 {
349 if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
DRC57423072011-01-05 23:35:53 +0000350 if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
DRCfbb67472010-11-24 04:02:37 +0000351 if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
DRC57423072011-01-05 23:35:53 +0000352 if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
DRCfbb67472010-11-24 04:02:37 +0000353 if(outbuf[i]!=NULL) free(outbuf[i]);
354 }
DRC91e86ba2011-02-15 05:24:08 +0000355 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000356}
357
358
DRC0a325192011-03-02 09:22:41 +0000359DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle hnd,
DRC84241602011-02-25 02:08:23 +0000360 unsigned char *srcbuf, int width, int pitch, int height, int ps,
361 unsigned char *dstbuf, int subsamp, int flags)
362{
363 unsigned long size;
DRC0a325192011-03-02 09:22:41 +0000364 return tjCompress(hnd, srcbuf, width, pitch, height, ps, dstbuf, &size,
DRC84241602011-02-25 02:08:23 +0000365 subsamp, 0, flags|TJ_YUV);
366}
367
368
DRC2e7b76b2009-04-03 12:04:24 +0000369// DEC
370
371static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo)
372{
373 ERREXIT(dinfo, JERR_BUFFER_SIZE);
374 return TRUE;
375}
376
377static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes)
378{
379 dinfo->src->next_input_byte += (size_t) num_bytes;
380 dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
381}
382
383static void source_noop (struct jpeg_decompress_struct *dinfo)
384{
385}
386
DRC890f1e02011-02-26 22:02:37 +0000387static tjhandle _tjInitDecompress(jpgstruct *j)
DRC2e7b76b2009-04-03 12:04:24 +0000388{
DRC2e7b76b2009-04-03 12:04:24 +0000389 j->dinfo.err=jpeg_std_error(&j->jerr.pub);
390 j->jerr.pub.error_exit=my_error_exit;
391 j->jerr.pub.output_message=my_output_message;
392
393 if(setjmp(j->jerr.jb))
394 { // this will execute if LIBJPEG has an error
395 free(j); return NULL;
DRC9e17f7d2010-12-10 04:59:13 +0000396 }
DRC2e7b76b2009-04-03 12:04:24 +0000397
398 jpeg_create_decompress(&j->dinfo);
399 j->dinfo.src=&j->jsms;
400 j->jsms.init_source=source_noop;
401 j->jsms.fill_input_buffer = fill_input_buffer;
402 j->jsms.skip_input_data = skip_input_data;
403 j->jsms.resync_to_restart = jpeg_resync_to_restart;
404 j->jsms.term_source = source_noop;
405
406 j->initd=1;
407 return (tjhandle)j;
408}
409
DRC890f1e02011-02-26 22:02:37 +0000410DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
411{
412 jpgstruct *j;
413 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000414 {
415 snprintf(lasterror, JMSG_LENGTH_MAX, "Memory allocation failure");
416 return NULL;
417 }
DRC890f1e02011-02-26 22:02:37 +0000418 memset(j, 0, sizeof(jpgstruct));
419 return _tjInitDecompress(j);
420}
421
DRC2e7b76b2009-04-03 12:04:24 +0000422
DRC0a325192011-03-02 09:22:41 +0000423DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle hnd,
DRC1fe80f82010-12-14 01:21:29 +0000424 unsigned char *srcbuf, unsigned long size,
425 int *width, int *height, int *jpegsub)
426{
DRC91e86ba2011-02-15 05:24:08 +0000427 int i, k, retval=0;
DRC1fe80f82010-12-14 01:21:29 +0000428
DRC0a325192011-03-02 09:22:41 +0000429 checkhandle(hnd);
DRC1fe80f82010-12-14 01:21:29 +0000430
431 if(srcbuf==NULL || size<=0 || width==NULL || height==NULL || jpegsub==NULL)
DRC91e86ba2011-02-15 05:24:08 +0000432 _throw("Invalid argument in tjDecompressHeader2()");
DRC1fe80f82010-12-14 01:21:29 +0000433 if(!j->initd) _throw("Instance has not been initialized for decompression");
434
435 if(setjmp(j->jerr.jb))
436 { // this will execute if LIBJPEG has an error
437 return -1;
438 }
439
440 j->jsms.bytes_in_buffer = size;
441 j->jsms.next_input_byte = srcbuf;
442
443 jpeg_read_header(&j->dinfo, TRUE);
444
445 *width=j->dinfo.image_width; *height=j->dinfo.image_height;
446 *jpegsub=-1;
447 for(i=0; i<NUMSUBOPT; i++)
448 {
449 if(j->dinfo.num_components==pixelsize[i])
450 {
DRC0a325192011-03-02 09:22:41 +0000451 if(j->dinfo.comp_info[0].h_samp_factor==tjmcuw[i]/8
452 && j->dinfo.comp_info[0].v_samp_factor==tjmcuh[i]/8)
DRC1fe80f82010-12-14 01:21:29 +0000453 {
454 int match=0;
455 for(k=1; k<j->dinfo.num_components; k++)
456 {
457 if(j->dinfo.comp_info[k].h_samp_factor==1
458 && j->dinfo.comp_info[k].v_samp_factor==1)
459 match++;
460 }
461 if(match==j->dinfo.num_components-1)
462 {
463 *jpegsub=i; break;
464 }
465 }
466 }
467 }
468
469 jpeg_abort_decompress(&j->dinfo);
470
471 if(*jpegsub<0) _throw("Could not determine subsampling type for JPEG image");
472 if(*width<1 || *height<1) _throw("Invalid data returned in header");
DRC91e86ba2011-02-15 05:24:08 +0000473
474 bailout:
475 return retval;
476}
477
478
DRC0a325192011-03-02 09:22:41 +0000479DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle hnd,
DRC91e86ba2011-02-15 05:24:08 +0000480 unsigned char *srcbuf, unsigned long size,
481 int *width, int *height)
482{
483 int jpegsub;
DRC0a325192011-03-02 09:22:41 +0000484 return tjDecompressHeader2(hnd, srcbuf, size, width, height, &jpegsub);
DRC1fe80f82010-12-14 01:21:29 +0000485}
486
487
DRC109a5782011-03-01 09:53:07 +0000488DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
DRCb28fc572011-02-22 06:41:29 +0000489{
DRC109a5782011-03-01 09:53:07 +0000490 if(numscalingfactors==NULL)
DRCb28fc572011-02-22 06:41:29 +0000491 {
DRCda5220a2011-03-02 02:17:30 +0000492 snprintf(lasterror, JMSG_LENGTH_MAX,
493 "Invalid argument in tjGetScalingFactors()");
DRC109a5782011-03-01 09:53:07 +0000494 return NULL;
DRCb28fc572011-02-22 06:41:29 +0000495 }
496
DRC109a5782011-03-01 09:53:07 +0000497 *numscalingfactors=NUMSF;
498 return (tjscalingfactor *)sf;
DRCb28fc572011-02-22 06:41:29 +0000499}
500
501
DRC0a325192011-03-02 09:22:41 +0000502DLLEXPORT int DLLCALL tjDecompress(tjhandle hnd,
DRC2e7b76b2009-04-03 12:04:24 +0000503 unsigned char *srcbuf, unsigned long size,
DRCb28fc572011-02-22 06:41:29 +0000504 unsigned char *dstbuf, int width, int pitch, int height, int ps,
505 int flags)
DRC2e7b76b2009-04-03 12:04:24 +0000506{
DRC91e86ba2011-02-15 05:24:08 +0000507 int i, row, retval=0; JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
DRCf9cf5c72010-12-10 10:58:49 +0000508 int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
509 tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
510 JSAMPLE *_tmpbuf=NULL; JSAMPROW *tmpbuf[MAX_COMPONENTS];
DRC109a5782011-03-01 09:53:07 +0000511 int jpegwidth, jpegheight, scaledw, scaledh;
DRC2e7b76b2009-04-03 12:04:24 +0000512
DRC0a325192011-03-02 09:22:41 +0000513 checkhandle(hnd);
DRC2e7b76b2009-04-03 12:04:24 +0000514
DRCf9cf5c72010-12-10 10:58:49 +0000515 for(i=0; i<MAX_COMPONENTS; i++)
516 {
517 tmpbuf[i]=NULL; outbuf[i]=NULL;
518 }
DRC9e17f7d2010-12-10 04:59:13 +0000519
DRCb28fc572011-02-22 06:41:29 +0000520 if(srcbuf==NULL || size<=0
521 || dstbuf==NULL || width<0 || pitch<0 || height<0)
522 _throw("Invalid argument in tjDecompress()");
DRC09854f52010-11-04 22:39:59 +0000523 if(ps!=3 && ps!=4 && ps!=1)
524 _throw("This decompressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale output");
DRC2e7b76b2009-04-03 12:04:24 +0000525 if(!j->initd) _throw("Instance has not been initialized for decompression");
526
DRC0c6a2712010-02-22 08:34:44 +0000527 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
528 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
529 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
530
DRC2e7b76b2009-04-03 12:04:24 +0000531 if(setjmp(j->jerr.jb))
532 { // this will execute if LIBJPEG has an error
DRC91e86ba2011-02-15 05:24:08 +0000533 retval=-1;
534 goto bailout;
DRC9e17f7d2010-12-10 04:59:13 +0000535 }
DRC2e7b76b2009-04-03 12:04:24 +0000536
537 j->jsms.bytes_in_buffer = size;
538 j->jsms.next_input_byte = srcbuf;
539
540 jpeg_read_header(&j->dinfo, TRUE);
541
DRC9e17f7d2010-12-10 04:59:13 +0000542 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000543 {
DRC9e17f7d2010-12-10 04:59:13 +0000544 j_decompress_ptr dinfo=&j->dinfo;
545 JSAMPLE *ptr=dstbuf;
546
547 for(i=0; i<dinfo->num_components; i++)
548 {
549 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRCf9cf5c72010-12-10 10:58:49 +0000550 int ih;
551 iw[i]=compptr->width_in_blocks*DCTSIZE;
552 ih=compptr->height_in_blocks*DCTSIZE;
DRC8ed7b812011-02-15 08:31:34 +0000553 cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
554 *compptr->h_samp_factor/dinfo->max_h_samp_factor;
555 ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
556 *compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRCa6f4fca2010-12-11 06:01:11 +0000557 if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
558 th[i]=compptr->v_samp_factor*DCTSIZE;
559 tmpbufsize+=iw[i]*th[i];
DRC9e17f7d2010-12-10 04:59:13 +0000560 if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
DRC84241602011-02-25 02:08:23 +0000561 _throw("Memory allocation failed in tjDecompress()");
DRC9e17f7d2010-12-10 04:59:13 +0000562 for(row=0; row<ch[i]; row++)
563 {
564 outbuf[i][row]=ptr;
DRCf9cf5c72010-12-10 10:58:49 +0000565 ptr+=PAD(cw[i], 4);
566 }
567 }
568 if(usetmpbuf)
569 {
570 if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
DRC84241602011-02-25 02:08:23 +0000571 _throw("Memory allocation failed in tjDecompress()");
DRCf9cf5c72010-12-10 10:58:49 +0000572 ptr=_tmpbuf;
573 for(i=0; i<dinfo->num_components; i++)
574 {
DRCf9cf5c72010-12-10 10:58:49 +0000575 if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
DRC84241602011-02-25 02:08:23 +0000576 _throw("Memory allocation failed in tjDecompress()");
DRCf9cf5c72010-12-10 10:58:49 +0000577 for(row=0; row<th[i]; row++)
578 {
579 tmpbuf[i][row]=ptr;
580 ptr+=iw[i];
581 }
DRC9e17f7d2010-12-10 04:59:13 +0000582 }
583 }
584 }
DRC2e7b76b2009-04-03 12:04:24 +0000585
DRC09854f52010-11-04 22:39:59 +0000586 if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE;
DRC2e7b76b2009-04-03 12:04:24 +0000587 #if JCS_EXTENSIONS==1
DRC09854f52010-11-04 22:39:59 +0000588 else j->dinfo.out_color_space = JCS_EXT_RGB;
DRC2e7b76b2009-04-03 12:04:24 +0000589 if(ps==3 && (flags&TJ_BGR))
590 j->dinfo.out_color_space = JCS_EXT_BGR;
591 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
592 j->dinfo.out_color_space = JCS_EXT_RGBX;
593 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
594 j->dinfo.out_color_space = JCS_EXT_BGRX;
595 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
596 j->dinfo.out_color_space = JCS_EXT_XBGR;
597 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
598 j->dinfo.out_color_space = JCS_EXT_XRGB;
599 #else
600 #error "TurboJPEG requires JPEG colorspace extensions"
601 #endif
DRCfbb67472010-11-24 04:02:37 +0000602
DRC61e51f92009-04-05 21:53:20 +0000603 if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
DRC9e17f7d2010-12-10 04:59:13 +0000604 if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE;
DRC8ed7b812011-02-15 08:31:34 +0000605 else
606 {
DRC84241602011-02-25 02:08:23 +0000607 jpegwidth=j->dinfo.image_width; jpegheight=j->dinfo.image_height;
608 if(width==0) width=jpegwidth;
609 if(height==0) height=jpegheight;
DRC109a5782011-03-01 09:53:07 +0000610 for(i=0; i<NUMSF; i++)
DRC84241602011-02-25 02:08:23 +0000611 {
DRC109a5782011-03-01 09:53:07 +0000612 scaledw=(jpegwidth*sf[i].num+sf[i].denom-1)/sf[i].denom;
613 scaledh=(jpegheight*sf[i].num+sf[i].denom-1)/sf[i].denom;
614 if(scaledw<=width && scaledh<=height)
DRC84241602011-02-25 02:08:23 +0000615 break;
DRC84241602011-02-25 02:08:23 +0000616 }
DRC109a5782011-03-01 09:53:07 +0000617 if(scaledw>width || scaledh>height)
618 _throw("Could not scale down to desired image dimensions");
619 width=scaledw; height=scaledh;
620 j->dinfo.scale_num=sf[i].num;
621 j->dinfo.scale_denom=sf[i].denom;
DRC8ed7b812011-02-15 08:31:34 +0000622 }
DRC2e7b76b2009-04-03 12:04:24 +0000623
624 jpeg_start_decompress(&j->dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000625 if(flags&TJ_YUV)
DRC2e7b76b2009-04-03 12:04:24 +0000626 {
DRCf9cf5c72010-12-10 10:58:49 +0000627 j_decompress_ptr dinfo=&j->dinfo;
DRC43a29d22011-03-02 01:27:26 +0000628 for(row=0; row<(int)dinfo->output_height;
DRCf9cf5c72010-12-10 10:58:49 +0000629 row+=dinfo->max_v_samp_factor*DCTSIZE)
DRC9e17f7d2010-12-10 04:59:13 +0000630 {
631 JSAMPARRAY yuvptr[MAX_COMPONENTS];
DRCa6f4fca2010-12-11 06:01:11 +0000632 int crow[MAX_COMPONENTS];
DRCf9cf5c72010-12-10 10:58:49 +0000633 for(i=0; i<dinfo->num_components; i++)
DRC9e17f7d2010-12-10 04:59:13 +0000634 {
DRCf9cf5c72010-12-10 10:58:49 +0000635 jpeg_component_info *compptr=&dinfo->comp_info[i];
DRCa6f4fca2010-12-11 06:01:11 +0000636 crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
DRCf9cf5c72010-12-10 10:58:49 +0000637 if(usetmpbuf) yuvptr[i]=tmpbuf[i];
DRCa6f4fca2010-12-11 06:01:11 +0000638 else yuvptr[i]=&outbuf[i][crow[i]];
DRC9e17f7d2010-12-10 04:59:13 +0000639 }
DRCf9cf5c72010-12-10 10:58:49 +0000640 jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
641 if(usetmpbuf)
642 {
643 int j;
644 for(i=0; i<dinfo->num_components; i++)
645 {
DRCa6f4fca2010-12-11 06:01:11 +0000646 for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
DRCf9cf5c72010-12-10 10:58:49 +0000647 {
DRCa6f4fca2010-12-11 06:01:11 +0000648 memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000649 }
650 }
651 }
DRC9e17f7d2010-12-10 04:59:13 +0000652 }
653 }
654 else
655 {
DRC8ed7b812011-02-15 08:31:34 +0000656 if(pitch==0) pitch=j->dinfo.output_width*ps;
657 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
658 *j->dinfo.output_height))==NULL)
DRC8ed7b812011-02-15 08:31:34 +0000659 _throw("Memory allocation failed in tjInitDecompress()");
DRC43a29d22011-03-02 01:27:26 +0000660 for(i=0; i<(int)j->dinfo.output_height; i++)
DRC8ed7b812011-02-15 08:31:34 +0000661 {
662 if(flags&TJ_BOTTOMUP)
663 row_pointer[i]= &dstbuf[(j->dinfo.output_height-i-1)*pitch];
664 else row_pointer[i]= &dstbuf[i*pitch];
665 }
DRC9e17f7d2010-12-10 04:59:13 +0000666 while(j->dinfo.output_scanline<j->dinfo.output_height)
667 {
668 jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
669 j->dinfo.output_height-j->dinfo.output_scanline);
670 }
DRC2e7b76b2009-04-03 12:04:24 +0000671 }
672 jpeg_finish_decompress(&j->dinfo);
673
DRC91e86ba2011-02-15 05:24:08 +0000674 bailout:
DRCb28fc572011-02-22 06:41:29 +0000675 if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
DRC9e17f7d2010-12-10 04:59:13 +0000676 for(i=0; i<MAX_COMPONENTS; i++)
DRCf9cf5c72010-12-10 10:58:49 +0000677 {
678 if(tmpbuf[i]) free(tmpbuf[i]);
DRC9e17f7d2010-12-10 04:59:13 +0000679 if(outbuf[i]) free(outbuf[i]);
DRCf9cf5c72010-12-10 10:58:49 +0000680 }
681 if(_tmpbuf) free(_tmpbuf);
DRC2e7b76b2009-04-03 12:04:24 +0000682 if(row_pointer) free(row_pointer);
DRC91e86ba2011-02-15 05:24:08 +0000683 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000684}
685
686
DRC0a325192011-03-02 09:22:41 +0000687DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle hnd,
DRC84241602011-02-25 02:08:23 +0000688 unsigned char *srcbuf, unsigned long size,
689 unsigned char *dstbuf, int flags)
690{
DRC0a325192011-03-02 09:22:41 +0000691 return tjDecompress(hnd, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV);
DRC84241602011-02-25 02:08:23 +0000692}
693
694
DRC890f1e02011-02-26 22:02:37 +0000695// Transformation
696
697DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
698{
699 jpgstruct *j=NULL; tjhandle tj=NULL;
700 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
DRCda5220a2011-03-02 02:17:30 +0000701 {
702 snprintf(lasterror, JMSG_LENGTH_MAX, "Memory allocation failure");
703 return NULL;
704 }
DRC890f1e02011-02-26 22:02:37 +0000705 memset(j, 0, sizeof(jpgstruct));
706 tj=_tjInitCompress(j);
707 if(!tj) return NULL;
708 tj=_tjInitDecompress(j);
709 return tj;
710}
711
712
713DLLEXPORT int DLLCALL tjTransform(tjhandle hnd,
714 unsigned char *srcbuf, unsigned long srcsize,
DRC0a325192011-03-02 09:22:41 +0000715 int n, unsigned char **dstbufs, unsigned long *dstsizes,
716 tjtransform *t, int flags)
DRC890f1e02011-02-26 22:02:37 +0000717{
DRC0a325192011-03-02 09:22:41 +0000718 jpeg_transform_info *xinfo=NULL;
DRC890f1e02011-02-26 22:02:37 +0000719 jvirt_barray_ptr *srccoefs, *dstcoefs;
DRC0a325192011-03-02 09:22:41 +0000720 int retval=0, i;
DRC890f1e02011-02-26 22:02:37 +0000721
722 checkhandle(hnd);
723
DRC0a325192011-03-02 09:22:41 +0000724 if(srcbuf==NULL || srcsize<=0 || n<1 || dstbufs==NULL || dstsizes==NULL
725 || t==NULL || flags<0)
DRC890f1e02011-02-26 22:02:37 +0000726 _throw("Invalid argument in tjTransform()");
727 if(!j->initc || !j->initd)
728 _throw("Instance has not been initialized for transformation");
729
730 if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
731 else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
732 else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
733
734 if(setjmp(j->jerr.jb))
735 { // this will execute if LIBJPEG has an error
736 retval=-1;
737 goto bailout;
738 }
739
740 j->jsms.bytes_in_buffer=srcsize;
741 j->jsms.next_input_byte=srcbuf;
742
DRC0a325192011-03-02 09:22:41 +0000743 if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
744 ==NULL)
745 _throw("Memory allocation failed in tjTransform()");
DRCd932e582011-03-15 20:09:47 +0000746 memset(xinfo, 0, sizeof(jpeg_transform_info)*n);
DRC890f1e02011-02-26 22:02:37 +0000747
DRC0a325192011-03-02 09:22:41 +0000748 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +0000749 {
DRC0a325192011-03-02 09:22:41 +0000750 xinfo[i].transform=xformtypes[t[i].op];
751 xinfo[i].perfect=(t[i].options&TJXFORM_PERFECT)? 1:0;
752 xinfo[i].trim=(t[i].options&TJXFORM_TRIM)? 1:0;
753 xinfo[i].force_grayscale=(t[i].options&TJXFORM_GRAY)? 1:0;
754 xinfo[i].crop=(t[i].options&TJXFORM_CROP)? 1:0;
DRCba5ea512011-03-04 03:20:34 +0000755 if(n!=1 && t[i].op==TJXFORM_HFLIP) xinfo[i].slow_hflip=1;
756 else xinfo[i].slow_hflip=0;
DRC0a325192011-03-02 09:22:41 +0000757
758 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +0000759 {
DRC0a325192011-03-02 09:22:41 +0000760 xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
761 xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
762 if(t[i].r.w!=0)
763 {
764 xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
765 }
DRCd932e582011-03-15 20:09:47 +0000766 else xinfo[i].crop_width=JCROP_UNSET;
DRC0a325192011-03-02 09:22:41 +0000767 if(t[i].r.h!=0)
768 {
769 xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
770 }
DRCd932e582011-03-15 20:09:47 +0000771 else xinfo[i].crop_height=JCROP_UNSET;
DRC890f1e02011-02-26 22:02:37 +0000772 }
773 }
774
DRC0a325192011-03-02 09:22:41 +0000775 jcopy_markers_setup(&j->dinfo, JCOPYOPT_ALL);
DRC890f1e02011-02-26 22:02:37 +0000776 jpeg_read_header(&j->dinfo, TRUE);
777
DRC0a325192011-03-02 09:22:41 +0000778 for(i=0; i<n; i++)
DRC890f1e02011-02-26 22:02:37 +0000779 {
DRC0a325192011-03-02 09:22:41 +0000780 if(!jtransform_request_workspace(&j->dinfo, &xinfo[i]))
781 _throw("Transform is not perfect");
DRC890f1e02011-02-26 22:02:37 +0000782
DRC0a325192011-03-02 09:22:41 +0000783 if(xinfo[i].crop)
DRC890f1e02011-02-26 22:02:37 +0000784 {
DRC0a325192011-03-02 09:22:41 +0000785 if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
786 || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
787 {
788 snprintf(lasterror, JMSG_LENGTH_MAX,
789 "To crop this JPEG image, x must be a multiple of %d\n"
790 "and y must be a multiple of %d.\n",
791 xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
792 retval=-1; goto bailout;
793 }
DRC890f1e02011-02-26 22:02:37 +0000794 }
795 }
796
797 srccoefs=jpeg_read_coefficients(&j->dinfo);
DRC890f1e02011-02-26 22:02:37 +0000798
DRC0a325192011-03-02 09:22:41 +0000799 for(i=0; i<n; i++)
800 {
801 int w, h;
802 j->jdms.next_output_byte=dstbufs[i];
803 if(!xinfo[i].crop)
804 {
805 w=j->dinfo.image_width; h=j->dinfo.image_height;
806 }
807 else
808 {
809 w=xinfo[i].crop_width; h=xinfo[i].crop_height;
810 }
811 j->jdms.free_in_buffer=TJBUFSIZE(w, h);
812 jpeg_copy_critical_parameters(&j->dinfo, &j->cinfo);
813 dstcoefs=jtransform_adjust_parameters(&j->dinfo, &j->cinfo, srccoefs,
814 &xinfo[i]);
815 jpeg_write_coefficients(&j->cinfo, dstcoefs);
816 jcopy_markers_execute(&j->dinfo, &j->cinfo, JCOPYOPT_ALL);
817 jtransform_execute_transformation(&j->dinfo, &j->cinfo, srccoefs,
818 &xinfo[i]);
819 jpeg_finish_compress(&j->cinfo);
820
821 dstsizes[i]=TJBUFSIZE(w, h)-(unsigned long)(j->jdms.free_in_buffer);
822 }
823
DRC890f1e02011-02-26 22:02:37 +0000824 jpeg_finish_decompress(&j->dinfo);
825
DRC890f1e02011-02-26 22:02:37 +0000826 bailout:
827 if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
828 if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
DRC0a325192011-03-02 09:22:41 +0000829 if(xinfo) free(xinfo);
DRC890f1e02011-02-26 22:02:37 +0000830 return retval;
831}
832
833
DRC2e7b76b2009-04-03 12:04:24 +0000834// General
835
836DLLEXPORT char* DLLCALL tjGetErrorStr(void)
837{
838 return lasterror;
839}
840
DRC0a325192011-03-02 09:22:41 +0000841DLLEXPORT int DLLCALL tjDestroy(tjhandle hnd)
DRC2e7b76b2009-04-03 12:04:24 +0000842{
DRC0a325192011-03-02 09:22:41 +0000843 checkhandle(hnd);
DRC2e7b76b2009-04-03 12:04:24 +0000844 if(setjmp(j->jerr.jb)) return -1;
845 if(j->initc) jpeg_destroy_compress(&j->cinfo);
846 if(j->initd) jpeg_destroy_decompress(&j->dinfo);
847 free(j);
848 return 0;
849}