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