blob: 3f03aed9c85c3fad03c39cd8c2fea21de1366fbe [file] [log] [blame]
DRCe34390b2009-04-03 12:04:24 +00001/* Copyright (C)2004 Landmark Graphics Corporation
2 * Copyright (C)2005 Sun Microsystems, Inc.
3 *
4 * This library is free software and may be redistributed and/or modified under
5 * the terms of the wxWindows Library License, Version 3.1 or (at your option)
6 * any later version. The full license is in the LICENSE.txt file included
7 * with this distribution.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * wxWindows Library License for more details.
13 */
14
15// This implements a JPEG compressor/decompressor using the libjpeg API
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <jpeglib.h>
21#include <jerror.h>
22#include <setjmp.h>
23#include "./turbojpeg.h"
24
25
26// Error handling
27
28static char lasterror[JMSG_LENGTH_MAX]="No error";
29
30typedef struct _error_mgr
31{
32 struct jpeg_error_mgr pub;
33 jmp_buf jb;
34} error_mgr;
35
36static void my_error_exit(j_common_ptr cinfo)
37{
38 error_mgr *myerr = (error_mgr *)cinfo->err;
39 (*cinfo->err->output_message)(cinfo);
40 longjmp(myerr->jb, 1);
41}
42
43static void my_output_message(j_common_ptr cinfo)
44{
45 (*cinfo->err->format_message)(cinfo, lasterror);
46}
47
48
49// Global structures, macros, etc.
50
51typedef struct _jpgstruct
52{
53 struct jpeg_compress_struct cinfo;
54 struct jpeg_decompress_struct dinfo;
55 struct jpeg_destination_mgr jdms;
56 struct jpeg_source_mgr jsms;
57 error_mgr jerr;
58 int initc, initd;
59} jpgstruct;
60
61static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1};
62static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1};
63
64#define _throw(c) {sprintf(lasterror, "%s", c); return -1;}
65#define _catch(f) {if((f)==-1) return -1;}
66#define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
67 if(!j) _throw("Invalid handle");
68
69
70// CO
71
72static boolean empty_output_buffer(struct jpeg_compress_struct *cinfo)
73{
74 ERREXIT(cinfo, JERR_BUFFER_SIZE);
75 return TRUE;
76}
77
78static void destination_noop(struct jpeg_compress_struct *cinfo)
79{
80}
81
82DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
83{
84 jpgstruct *j=NULL;
85 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
86 {sprintf(lasterror, "Memory allocation failure"); return NULL;}
87 memset(j, 0, sizeof(jpgstruct));
88 j->cinfo.err=jpeg_std_error(&j->jerr.pub);
89 j->jerr.pub.error_exit=my_error_exit;
90 j->jerr.pub.output_message=my_output_message;
91
92 if(setjmp(j->jerr.jb))
93 { // this will execute if LIBJPEG has an error
94 if(j) free(j); return NULL;
95 }
96
97 jpeg_create_compress(&j->cinfo);
98 j->cinfo.dest=&j->jdms;
99 j->jdms.init_destination=destination_noop;
100 j->jdms.empty_output_buffer=empty_output_buffer;
101 j->jdms.term_destination=destination_noop;
102
103 j->initc=1;
104 return (tjhandle)j;
105}
106
107DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
108{
109 // This allows enough room in case the image doesn't compress
110 return ((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
111}
112
113DLLEXPORT int DLLCALL tjCompress(tjhandle h,
114 unsigned char *srcbuf, int width, int pitch, int height, int ps,
115 unsigned char *dstbuf, unsigned long *size,
116 int jpegsub, int qual, int flags)
117{
118 int i; JSAMPROW *row_pointer=NULL;
119
120 checkhandle(h);
121
122 if(srcbuf==NULL || width<=0 || pitch<0 || height<=0
123 || dstbuf==NULL || size==NULL
124 || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100)
125 _throw("Invalid argument in tjCompress()");
126 if(ps!=3 && ps!=4) _throw("This compressor can only take 24-bit or 32-bit RGB input");
127 if(!j->initc) _throw("Instance has not been initialized for compression");
128
129 if(pitch==0) pitch=width*ps;
130
131 j->cinfo.image_width = width;
132 j->cinfo.image_height = height;
133 j->cinfo.input_components = ps;
134
135 #if JCS_EXTENSIONS==1
136 j->cinfo.in_color_space = JCS_EXT_RGB;
137 if(ps==3 && (flags&TJ_BGR))
138 j->cinfo.in_color_space = JCS_EXT_BGR;
139 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
140 j->cinfo.in_color_space = JCS_EXT_RGBX;
141 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
142 j->cinfo.in_color_space = JCS_EXT_BGRX;
143 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
144 j->cinfo.in_color_space = JCS_EXT_XBGR;
145 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
146 j->cinfo.in_color_space = JCS_EXT_XRGB;
147 #else
148 #error "TurboJPEG requires JPEG colorspace extensions"
149 #endif
150
151 if(setjmp(j->jerr.jb))
152 { // this will execute if LIBJPEG has an error
153 if(row_pointer) free(row_pointer);
154 return -1;
155 }
156
157 jpeg_set_defaults(&j->cinfo);
158
159 jpeg_set_quality(&j->cinfo, qual, TRUE);
160 if(jpegsub==TJ_GRAYSCALE)
161 jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE);
162 else
163 jpeg_set_colorspace(&j->cinfo, JCS_YCbCr);
164 j->cinfo.dct_method = JDCT_FASTEST;
165
166 j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub];
167 j->cinfo.comp_info[1].h_samp_factor=1;
168 j->cinfo.comp_info[2].h_samp_factor=1;
169 j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub];
170 j->cinfo.comp_info[1].v_samp_factor=1;
171 j->cinfo.comp_info[2].v_samp_factor=1;
172
173 j->jdms.next_output_byte = dstbuf;
174 j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height);
175
176 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
177 _throw("Memory allocation failed in tjInitCompress()");
178 for(i=0; i<height; i++)
179 {
180 if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
181 else row_pointer[i]= &srcbuf[i*pitch];
182 }
183 jpeg_start_compress(&j->cinfo, TRUE);
184 while(j->cinfo.next_scanline<j->cinfo.image_height)
185 {
186 jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
187 j->cinfo.image_height-j->cinfo.next_scanline);
188 }
189 jpeg_finish_compress(&j->cinfo);
190 *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)-(j->jdms.free_in_buffer);
191
192 if(row_pointer) free(row_pointer);
193 return 0;
194}
195
196
197// DEC
198
199static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo)
200{
201 ERREXIT(dinfo, JERR_BUFFER_SIZE);
202 return TRUE;
203}
204
205static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes)
206{
207 dinfo->src->next_input_byte += (size_t) num_bytes;
208 dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
209}
210
211static void source_noop (struct jpeg_decompress_struct *dinfo)
212{
213}
214
215DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
216{
217 jpgstruct *j;
218 if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
219 {sprintf(lasterror, "Memory allocation failure"); return NULL;}
220 memset(j, 0, sizeof(jpgstruct));
221 j->dinfo.err=jpeg_std_error(&j->jerr.pub);
222 j->jerr.pub.error_exit=my_error_exit;
223 j->jerr.pub.output_message=my_output_message;
224
225 if(setjmp(j->jerr.jb))
226 { // this will execute if LIBJPEG has an error
227 free(j); return NULL;
228 }
229
230 jpeg_create_decompress(&j->dinfo);
231 j->dinfo.src=&j->jsms;
232 j->jsms.init_source=source_noop;
233 j->jsms.fill_input_buffer = fill_input_buffer;
234 j->jsms.skip_input_data = skip_input_data;
235 j->jsms.resync_to_restart = jpeg_resync_to_restart;
236 j->jsms.term_source = source_noop;
237
238 j->initd=1;
239 return (tjhandle)j;
240}
241
242
243DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
244 unsigned char *srcbuf, unsigned long size,
245 int *width, int *height)
246{
247 checkhandle(h);
248
249 if(srcbuf==NULL || size<=0 || width==NULL || height==NULL)
250 _throw("Invalid argument in tjDecompressHeader()");
251 if(!j->initd) _throw("Instance has not been initialized for decompression");
252
253 if(setjmp(j->jerr.jb))
254 { // this will execute if LIBJPEG has an error
255 return -1;
256 }
257
258 j->jsms.bytes_in_buffer = size;
259 j->jsms.next_input_byte = srcbuf;
260
261 jpeg_read_header(&j->dinfo, TRUE);
262
263 *width=j->dinfo.image_width; *height=j->dinfo.image_height;
264
265 jpeg_abort_decompress(&j->dinfo);
266
267 if(*width<1 || *height<1) _throw("Invalid data returned in header");
268 return 0;
269}
270
271
272DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
273 unsigned char *srcbuf, unsigned long size,
274 unsigned char *dstbuf, int width, int pitch, int height, int ps,
275 int flags)
276{
277 int i; JSAMPROW *row_pointer=NULL;
278
279 checkhandle(h);
280
281 if(srcbuf==NULL || size<=0
282 || dstbuf==NULL || width<=0 || pitch<0 || height<=0)
283 _throw("Invalid argument in tjDecompress()");
284 if(ps!=3 && ps!=4) _throw("This compressor can only take 24-bit or 32-bit RGB input");
285 if(!j->initd) _throw("Instance has not been initialized for decompression");
286
287 if(pitch==0) pitch=width*ps;
288
289 if(setjmp(j->jerr.jb))
290 { // this will execute if LIBJPEG has an error
291 if(row_pointer) free(row_pointer);
292 return -1;
293 }
294
295 j->jsms.bytes_in_buffer = size;
296 j->jsms.next_input_byte = srcbuf;
297
298 jpeg_read_header(&j->dinfo, TRUE);
299
300 if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
301 _throw("Memory allocation failed in tjInitDecompress()");
302 for(i=0; i<height; i++)
303 {
304 if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
305 else row_pointer[i]= &dstbuf[i*pitch];
306 }
307
308 #if JCS_EXTENSIONS==1
309 j->dinfo.out_color_space = JCS_EXT_RGB;
310 if(ps==3 && (flags&TJ_BGR))
311 j->dinfo.out_color_space = JCS_EXT_BGR;
312 else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
313 j->dinfo.out_color_space = JCS_EXT_RGBX;
314 else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
315 j->dinfo.out_color_space = JCS_EXT_BGRX;
316 else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
317 j->dinfo.out_color_space = JCS_EXT_XBGR;
318 else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
319 j->dinfo.out_color_space = JCS_EXT_XRGB;
320 #else
321 #error "TurboJPEG requires JPEG colorspace extensions"
322 #endif
323
324 jpeg_start_decompress(&j->dinfo);
325 while(j->dinfo.output_scanline<j->dinfo.output_height)
326 {
327 jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
328 j->dinfo.output_height-j->dinfo.output_scanline);
329 }
330 jpeg_finish_decompress(&j->dinfo);
331
332 if(row_pointer) free(row_pointer);
333 return 0;
334}
335
336
337// General
338
339DLLEXPORT char* DLLCALL tjGetErrorStr(void)
340{
341 return lasterror;
342}
343
344DLLEXPORT int DLLCALL tjDestroy(tjhandle h)
345{
346 checkhandle(h);
347 if(setjmp(j->jerr.jb)) return -1;
348 if(j->initc) jpeg_destroy_compress(&j->cinfo);
349 if(j->initd) jpeg_destroy_decompress(&j->dinfo);
350 free(j);
351 return 0;
352}