New comit of SDL2
[supertux.git] / src / SDL2 / IMG_jpg.c
1 /*
2   SDL_image:  An example image loading library for use with SDL
3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21
22 #if !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND)
23
24 /* This is a JPEG image file loading framework */
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <setjmp.h>
29
30 #include "SDL_image.h"
31
32 #ifdef LOAD_JPG
33
34 #include <jpeglib.h>
35
36 #ifdef JPEG_TRUE  /* MinGW version of jpeg-8.x renamed TRUE to JPEG_TRUE etc. */
37     typedef JPEG_boolean boolean;
38     #define TRUE JPEG_TRUE
39     #define FALSE JPEG_FALSE
40 #endif
41
42 /* Define this for fast loading and not as good image quality */
43 /*#define FAST_JPEG*/
44
45 /* Define this for quicker (but less perfect) JPEG identification */
46 #define FAST_IS_JPEG
47
48 static struct {
49     int loaded;
50     void *handle;
51     void (*jpeg_calc_output_dimensions) (j_decompress_ptr cinfo);
52     void (*jpeg_CreateDecompress) (j_decompress_ptr cinfo, int version, size_t structsize);
53     void (*jpeg_destroy_decompress) (j_decompress_ptr cinfo);
54     boolean (*jpeg_finish_decompress) (j_decompress_ptr cinfo);
55     int (*jpeg_read_header) (j_decompress_ptr cinfo, boolean require_image);
56     JDIMENSION (*jpeg_read_scanlines) (j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines);
57     boolean (*jpeg_resync_to_restart) (j_decompress_ptr cinfo, int desired);
58     boolean (*jpeg_start_decompress) (j_decompress_ptr cinfo);
59     struct jpeg_error_mgr * (*jpeg_std_error) (struct jpeg_error_mgr * err);
60 } lib;
61
62 #ifdef LOAD_JPG_DYNAMIC
63 int IMG_InitJPG()
64 {
65     if ( lib.loaded == 0 ) {
66         lib.handle = SDL_LoadObject(LOAD_JPG_DYNAMIC);
67         if ( lib.handle == NULL ) {
68             return -1;
69         }
70         lib.jpeg_calc_output_dimensions =
71             (void (*) (j_decompress_ptr))
72             SDL_LoadFunction(lib.handle, "jpeg_calc_output_dimensions");
73         if ( lib.jpeg_calc_output_dimensions == NULL ) {
74             SDL_UnloadObject(lib.handle);
75             return -1;
76         }
77         lib.jpeg_CreateDecompress =
78             (void (*) (j_decompress_ptr, int, size_t))
79             SDL_LoadFunction(lib.handle, "jpeg_CreateDecompress");
80         if ( lib.jpeg_CreateDecompress == NULL ) {
81             SDL_UnloadObject(lib.handle);
82             return -1;
83         }
84         lib.jpeg_destroy_decompress =
85             (void (*) (j_decompress_ptr))
86             SDL_LoadFunction(lib.handle, "jpeg_destroy_decompress");
87         if ( lib.jpeg_destroy_decompress == NULL ) {
88             SDL_UnloadObject(lib.handle);
89             return -1;
90         }
91         lib.jpeg_finish_decompress =
92             (boolean (*) (j_decompress_ptr))
93             SDL_LoadFunction(lib.handle, "jpeg_finish_decompress");
94         if ( lib.jpeg_finish_decompress == NULL ) {
95             SDL_UnloadObject(lib.handle);
96             return -1;
97         }
98         lib.jpeg_read_header =
99             (int (*) (j_decompress_ptr, boolean))
100             SDL_LoadFunction(lib.handle, "jpeg_read_header");
101         if ( lib.jpeg_read_header == NULL ) {
102             SDL_UnloadObject(lib.handle);
103             return -1;
104         }
105         lib.jpeg_read_scanlines =
106             (JDIMENSION (*) (j_decompress_ptr, JSAMPARRAY, JDIMENSION))
107             SDL_LoadFunction(lib.handle, "jpeg_read_scanlines");
108         if ( lib.jpeg_read_scanlines == NULL ) {
109             SDL_UnloadObject(lib.handle);
110             return -1;
111         }
112         lib.jpeg_resync_to_restart =
113             (boolean (*) (j_decompress_ptr, int))
114             SDL_LoadFunction(lib.handle, "jpeg_resync_to_restart");
115         if ( lib.jpeg_resync_to_restart == NULL ) {
116             SDL_UnloadObject(lib.handle);
117             return -1;
118         }
119         lib.jpeg_start_decompress =
120             (boolean (*) (j_decompress_ptr))
121             SDL_LoadFunction(lib.handle, "jpeg_start_decompress");
122         if ( lib.jpeg_start_decompress == NULL ) {
123             SDL_UnloadObject(lib.handle);
124             return -1;
125         }
126         lib.jpeg_std_error =
127             (struct jpeg_error_mgr * (*) (struct jpeg_error_mgr *))
128             SDL_LoadFunction(lib.handle, "jpeg_std_error");
129         if ( lib.jpeg_std_error == NULL ) {
130             SDL_UnloadObject(lib.handle);
131             return -1;
132         }
133     }
134     ++lib.loaded;
135
136     return 0;
137 }
138 void IMG_QuitJPG()
139 {
140     if ( lib.loaded == 0 ) {
141         return;
142     }
143     if ( lib.loaded == 1 ) {
144         SDL_UnloadObject(lib.handle);
145     }
146     --lib.loaded;
147 }
148 #else
149 int IMG_InitJPG()
150 {
151     if ( lib.loaded == 0 ) {
152         lib.jpeg_calc_output_dimensions = jpeg_calc_output_dimensions;
153         lib.jpeg_CreateDecompress = jpeg_CreateDecompress;
154         lib.jpeg_destroy_decompress = jpeg_destroy_decompress;
155         lib.jpeg_finish_decompress = jpeg_finish_decompress;
156         lib.jpeg_read_header = jpeg_read_header;
157         lib.jpeg_read_scanlines = jpeg_read_scanlines;
158         lib.jpeg_resync_to_restart = jpeg_resync_to_restart;
159         lib.jpeg_start_decompress = jpeg_start_decompress;
160         lib.jpeg_std_error = jpeg_std_error;
161     }
162     ++lib.loaded;
163
164     return 0;
165 }
166 void IMG_QuitJPG()
167 {
168     if ( lib.loaded == 0 ) {
169         return;
170     }
171     if ( lib.loaded == 1 ) {
172     }
173     --lib.loaded;
174 }
175 #endif /* LOAD_JPG_DYNAMIC */
176
177 /* See if an image is contained in a data source */
178 int IMG_isJPG(SDL_RWops *src)
179 {
180     Sint64 start;
181     int is_JPG;
182     int in_scan;
183     Uint8 magic[4];
184
185     /* This detection code is by Steaphan Greene <stea@cs.binghamton.edu> */
186     /* Blame me, not Sam, if this doesn't work right. */
187     /* And don't forget to report the problem to the the sdl list too! */
188
189     if ( !src )
190         return 0;
191     start = SDL_RWtell(src);
192     is_JPG = 0;
193     in_scan = 0;
194     if ( SDL_RWread(src, magic, 2, 1) ) {
195         if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
196             is_JPG = 1;
197             while (is_JPG == 1) {
198                 if(SDL_RWread(src, magic, 1, 2) != 2) {
199                     is_JPG = 0;
200                 } else if( (magic[0] != 0xFF) && (in_scan == 0) ) {
201                     is_JPG = 0;
202                 } else if( (magic[0] != 0xFF) || (magic[1] == 0xFF) ) {
203                     /* Extra padding in JPEG (legal) */
204                     /* or this is data and we are scanning */
205                     SDL_RWseek(src, -1, RW_SEEK_CUR);
206                 } else if(magic[1] == 0xD9) {
207                     /* Got to end of good JPEG */
208                     break;
209                 } else if( (in_scan == 1) && (magic[1] == 0x00) ) {
210                     /* This is an encoded 0xFF within the data */
211                 } else if( (magic[1] >= 0xD0) && (magic[1] < 0xD9) ) {
212                     /* These have nothing else */
213                 } else if(SDL_RWread(src, magic+2, 1, 2) != 2) {
214                     is_JPG = 0;
215                 } else {
216                     /* Yes, it's big-endian */
217                     Sint64 innerStart;
218                     Uint32 size;
219                     Sint64 end;
220                     innerStart = SDL_RWtell(src);
221                     size = (magic[2] << 8) + magic[3];
222                     end = SDL_RWseek(src, size-2, RW_SEEK_CUR);
223                     if ( end != innerStart + size - 2 ) is_JPG = 0;
224                     if ( magic[1] == 0xDA ) {
225                         /* Now comes the actual JPEG meat */
226 #ifdef  FAST_IS_JPEG
227                         /* Ok, I'm convinced.  It is a JPEG. */
228                         break;
229 #else
230                         /* I'm not convinced.  Prove it! */
231                         in_scan = 1;
232 #endif
233                     }
234                 }
235             }
236         }
237     }
238     SDL_RWseek(src, start, RW_SEEK_SET);
239     return(is_JPG);
240 }
241
242 #define INPUT_BUFFER_SIZE   4096
243 typedef struct {
244     struct jpeg_source_mgr pub;
245
246     SDL_RWops *ctx;
247     Uint8 buffer[INPUT_BUFFER_SIZE];
248 } my_source_mgr;
249
250 /*
251  * Initialize source --- called by jpeg_read_header
252  * before any data is actually read.
253  */
254 static void init_source (j_decompress_ptr cinfo)
255 {
256     /* We don't actually need to do anything */
257     return;
258 }
259
260 /*
261  * Fill the input buffer --- called whenever buffer is emptied.
262  */
263 static boolean fill_input_buffer (j_decompress_ptr cinfo)
264 {
265     my_source_mgr * src = (my_source_mgr *) cinfo->src;
266     int nbytes;
267
268     nbytes = SDL_RWread(src->ctx, src->buffer, 1, INPUT_BUFFER_SIZE);
269     if (nbytes <= 0) {
270         /* Insert a fake EOI marker */
271         src->buffer[0] = (Uint8) 0xFF;
272         src->buffer[1] = (Uint8) JPEG_EOI;
273         nbytes = 2;
274     }
275     src->pub.next_input_byte = src->buffer;
276     src->pub.bytes_in_buffer = nbytes;
277
278     return TRUE;
279 }
280
281
282 /*
283  * Skip data --- used to skip over a potentially large amount of
284  * uninteresting data (such as an APPn marker).
285  *
286  * Writers of suspendable-input applications must note that skip_input_data
287  * is not granted the right to give a suspension return.  If the skip extends
288  * beyond the data currently in the buffer, the buffer can be marked empty so
289  * that the next read will cause a fill_input_buffer call that can suspend.
290  * Arranging for additional bytes to be discarded before reloading the input
291  * buffer is the application writer's problem.
292  */
293 static void skip_input_data (j_decompress_ptr cinfo, long num_bytes)
294 {
295     my_source_mgr * src = (my_source_mgr *) cinfo->src;
296
297     /* Just a dumb implementation for now.  Could use fseek() except
298      * it doesn't work on pipes.  Not clear that being smart is worth
299      * any trouble anyway --- large skips are infrequent.
300      */
301     if (num_bytes > 0) {
302         while (num_bytes > (long) src->pub.bytes_in_buffer) {
303             num_bytes -= (long) src->pub.bytes_in_buffer;
304             (void) src->pub.fill_input_buffer(cinfo);
305             /* note we assume that fill_input_buffer will never
306              * return FALSE, so suspension need not be handled.
307              */
308         }
309         src->pub.next_input_byte += (size_t) num_bytes;
310         src->pub.bytes_in_buffer -= (size_t) num_bytes;
311     }
312 }
313
314 /*
315  * Terminate source --- called by jpeg_finish_decompress
316  * after all data has been read.
317  */
318 static void term_source (j_decompress_ptr cinfo)
319 {
320     /* We don't actually need to do anything */
321     return;
322 }
323
324 /*
325  * Prepare for input from a stdio stream.
326  * The caller must have already opened the stream, and is responsible
327  * for closing it after finishing decompression.
328  */
329 static void jpeg_SDL_RW_src (j_decompress_ptr cinfo, SDL_RWops *ctx)
330 {
331   my_source_mgr *src;
332
333   /* The source object and input buffer are made permanent so that a series
334    * of JPEG images can be read from the same file by calling jpeg_stdio_src
335    * only before the first one.  (If we discarded the buffer at the end of
336    * one image, we'd likely lose the start of the next one.)
337    * This makes it unsafe to use this manager and a different source
338    * manager serially with the same JPEG object.  Caveat programmer.
339    */
340   if (cinfo->src == NULL) { /* first time for this JPEG object? */
341     cinfo->src = (struct jpeg_source_mgr *)
342       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
343                   sizeof(my_source_mgr));
344     src = (my_source_mgr *) cinfo->src;
345   }
346
347   src = (my_source_mgr *) cinfo->src;
348   src->pub.init_source = init_source;
349   src->pub.fill_input_buffer = fill_input_buffer;
350   src->pub.skip_input_data = skip_input_data;
351   src->pub.resync_to_restart = lib.jpeg_resync_to_restart; /* use default method */
352   src->pub.term_source = term_source;
353   src->ctx = ctx;
354   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
355   src->pub.next_input_byte = NULL; /* until buffer loaded */
356 }
357
358 struct my_error_mgr {
359     struct jpeg_error_mgr errmgr;
360     jmp_buf escape;
361 };
362
363 static void my_error_exit(j_common_ptr cinfo)
364 {
365     struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err;
366     longjmp(err->escape, 1);
367 }
368
369 static void output_no_message(j_common_ptr cinfo)
370 {
371     /* do nothing */
372 }
373
374 /* Load a JPEG type image from an SDL datasource */
375 SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
376 {
377     Sint64 start;
378     struct jpeg_decompress_struct cinfo;
379     JSAMPROW rowptr[1];
380     SDL_Surface *volatile surface = NULL;
381     struct my_error_mgr jerr;
382
383     if ( !src ) {
384         /* The error message has been set in SDL_RWFromFile */
385         return NULL;
386     }
387     start = SDL_RWtell(src);
388
389     if ( !IMG_Init(IMG_INIT_JPG) ) {
390         return NULL;
391     }
392
393     /* Create a decompression structure and load the JPEG header */
394     cinfo.err = lib.jpeg_std_error(&jerr.errmgr);
395     jerr.errmgr.error_exit = my_error_exit;
396     jerr.errmgr.output_message = output_no_message;
397     if(setjmp(jerr.escape)) {
398         /* If we get here, libjpeg found an error */
399         lib.jpeg_destroy_decompress(&cinfo);
400         if ( surface != NULL ) {
401             SDL_FreeSurface(surface);
402         }
403         SDL_RWseek(src, start, RW_SEEK_SET);
404         IMG_SetError("JPEG loading error");
405         return NULL;
406     }
407
408     lib.jpeg_create_decompress(&cinfo);
409     jpeg_SDL_RW_src(&cinfo, src);
410     lib.jpeg_read_header(&cinfo, TRUE);
411
412     if(cinfo.num_components == 4) {
413         /* Set 32-bit Raw output */
414         cinfo.out_color_space = JCS_CMYK;
415         cinfo.quantize_colors = FALSE;
416         lib.jpeg_calc_output_dimensions(&cinfo);
417
418         /* Allocate an output surface to hold the image */
419         surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
420                 cinfo.output_width, cinfo.output_height, 32,
421 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
422                            0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
423 #else
424                            0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF);
425 #endif
426     } else {
427         /* Set 24-bit RGB output */
428         cinfo.out_color_space = JCS_RGB;
429         cinfo.quantize_colors = FALSE;
430 #ifdef FAST_JPEG
431         cinfo.scale_num   = 1;
432         cinfo.scale_denom = 1;
433         cinfo.dct_method = JDCT_FASTEST;
434         cinfo.do_fancy_upsampling = FALSE;
435 #endif
436         lib.jpeg_calc_output_dimensions(&cinfo);
437
438         /* Allocate an output surface to hold the image */
439         surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
440                 cinfo.output_width, cinfo.output_height, 24,
441 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
442                            0x0000FF, 0x00FF00, 0xFF0000,
443 #else
444                            0xFF0000, 0x00FF00, 0x0000FF,
445 #endif
446                            0);
447     }
448
449     if ( surface == NULL ) {
450         lib.jpeg_destroy_decompress(&cinfo);
451         SDL_RWseek(src, start, RW_SEEK_SET);
452         IMG_SetError("Out of memory");
453         return NULL;
454     }
455
456     /* Decompress the image */
457     lib.jpeg_start_decompress(&cinfo);
458     while ( cinfo.output_scanline < cinfo.output_height ) {
459         rowptr[0] = (JSAMPROW)(Uint8 *)surface->pixels +
460                             cinfo.output_scanline * surface->pitch;
461         lib.jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1);
462     }
463     lib.jpeg_finish_decompress(&cinfo);
464     lib.jpeg_destroy_decompress(&cinfo);
465
466     return(surface);
467 }
468
469 #else
470
471 int IMG_InitJPG()
472 {
473     IMG_SetError("JPEG images are not supported");
474     return(-1);
475 }
476
477 void IMG_QuitJPG()
478 {
479 }
480
481 /* See if an image is contained in a data source */
482 int IMG_isJPG(SDL_RWops *src)
483 {
484     return(0);
485 }
486
487 /* Load a JPEG type image from an SDL datasource */
488 SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
489 {
490     return(NULL);
491 }
492
493 #endif /* LOAD_JPG */
494
495 #endif /* !defined(__APPLE__) || defined(SDL_IMAGE_USE_COMMON_BACKEND) */