Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 1 | /* |
2 | IMGLIB: An example image loading library for use with SDL |
||
3 | Copyright (C) 1999 Sam Lantinga |
||
4 | |||
5 | This library is free software; you can redistribute it and/or |
||
6 | modify it under the terms of the GNU Library General Public |
||
7 | License as published by the Free Software Foundation; either |
||
8 | version 2 of the License, or (at your option) any later version. |
||
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 GNU |
||
13 | Library General Public License for more details. |
||
14 | |||
15 | You should have received a copy of the GNU Library General Public |
||
16 | License along with this library; if not, write to the Free |
||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
18 | |||
19 | Sam Lantinga |
||
20 | 5635-34 Springhouse Dr. |
||
21 | Pleasanton, CA 94588 (USA) |
||
22 | slouken@devolution.com |
||
23 | */ |
||
24 | |||
25 | /* This is a JPEG image file loading framework */ |
||
26 | |||
27 | #include |
||
28 | #include |
||
29 | |||
30 | #include "SDL_image.h" |
||
31 | |||
32 | #ifdef LOAD_JPG |
||
33 | |||
34 | #include |
||
35 | |||
36 | /* Define this for fast loading and not as good image quality */ |
||
37 | /*#define FAST_JPEG*/ |
||
38 | |||
39 | /* See if an image is contained in a data source */ |
||
40 | int IMG_isJPG(SDL_RWops *src) |
||
41 | { |
||
42 | int is_JPG; |
||
43 | Uint8 magic[4]; |
||
44 | |||
45 | is_JPG = 0; |
||
46 | if ( SDL_RWread(src, magic, 2, 1) ) { |
||
47 | if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) { |
||
48 | SDL_RWread(src, magic, 4, 1); |
||
49 | SDL_RWread(src, magic, 4, 1); |
||
50 | if ( memcmp((char *)magic, "JFIF", 4) == 0 ) { |
||
51 | is_JPG = 1; |
||
52 | } |
||
53 | } |
||
54 | } |
||
55 | return(is_JPG); |
||
56 | } |
||
57 | |||
58 | #define INPUT_BUFFER_SIZE 4096 |
||
59 | typedef struct { |
||
60 | struct jpeg_source_mgr pub; |
||
61 | |||
62 | SDL_RWops *ctx; |
||
63 | Uint8 buffer[INPUT_BUFFER_SIZE]; |
||
64 | } my_source_mgr; |
||
65 | |||
66 | /* |
||
67 | * Initialize source --- called by jpeg_read_header |
||
68 | * before any data is actually read. |
||
69 | */ |
||
70 | static void init_source (j_decompress_ptr cinfo) |
||
71 | { |
||
72 | /* We don't actually need to do anything */ |
||
73 | return; |
||
74 | } |
||
75 | |||
76 | /* |
||
77 | * Fill the input buffer --- called whenever buffer is emptied. |
||
78 | */ |
||
79 | static int fill_input_buffer (j_decompress_ptr cinfo) |
||
80 | { |
||
81 | my_source_mgr * src = (my_source_mgr *) cinfo->src; |
||
82 | int nbytes; |
||
83 | |||
84 | nbytes = SDL_RWread(src->ctx, src->buffer, 1, INPUT_BUFFER_SIZE); |
||
85 | if (nbytes <= 0) { |
||
86 | /* Insert a fake EOI marker */ |
||
87 | src->buffer[0] = (Uint8) 0xFF; |
||
88 | src->buffer[1] = (Uint8) JPEG_EOI; |
||
89 | nbytes = 2; |
||
90 | } |
||
91 | src->pub.next_input_byte = src->buffer; |
||
92 | src->pub.bytes_in_buffer = nbytes; |
||
93 | |||
94 | return TRUE; |
||
95 | } |
||
96 | |||
97 | |||
98 | /* |
||
99 | * Skip data --- used to skip over a potentially large amount of |
||
100 | * uninteresting data (such as an APPn marker). |
||
101 | * |
||
102 | * Writers of suspendable-input applications must note that skip_input_data |
||
103 | * is not granted the right to give a suspension return. If the skip extends |
||
104 | * beyond the data currently in the buffer, the buffer can be marked empty so |
||
105 | * that the next read will cause a fill_input_buffer call that can suspend. |
||
106 | * Arranging for additional bytes to be discarded before reloading the input |
||
107 | * buffer is the application writer's problem. |
||
108 | */ |
||
109 | static void skip_input_data (j_decompress_ptr cinfo, long num_bytes) |
||
110 | { |
||
111 | my_source_mgr * src = (my_source_mgr *) cinfo->src; |
||
112 | |||
113 | /* Just a dumb implementation for now. Could use fseek() except |
||
114 | * it doesn't work on pipes. Not clear that being smart is worth |
||
115 | * any trouble anyway --- large skips are infrequent. |
||
116 | */ |
||
117 | if (num_bytes > 0) { |
||
118 | while (num_bytes > (long) src->pub.bytes_in_buffer) { |
||
119 | num_bytes -= (long) src->pub.bytes_in_buffer; |
||
120 | (void) src->pub.fill_input_buffer(cinfo); |
||
121 | /* note we assume that fill_input_buffer will never |
||
122 | * return FALSE, so suspension need not be handled. |
||
123 | */ |
||
124 | } |
||
125 | src->pub.next_input_byte += (size_t) num_bytes; |
||
126 | src->pub.bytes_in_buffer -= (size_t) num_bytes; |
||
127 | } |
||
128 | } |
||
129 | |||
130 | /* |
||
131 | * Terminate source --- called by jpeg_finish_decompress |
||
132 | * after all data has been read. |
||
133 | */ |
||
134 | static void term_source (j_decompress_ptr cinfo) |
||
135 | { |
||
136 | /* We don't actually need to do anything */ |
||
137 | return; |
||
138 | } |
||
139 | |||
140 | /* |
||
141 | * Prepare for input from a stdio stream. |
||
142 | * The caller must have already opened the stream, and is responsible |
||
143 | * for closing it after finishing decompression. |
||
144 | */ |
||
145 | static void jpeg_SDL_RW_src (j_decompress_ptr cinfo, SDL_RWops *ctx) |
||
146 | { |
||
147 | my_source_mgr *src; |
||
148 | |||
149 | /* The source object and input buffer are made permanent so that a series |
||
150 | * of JPEG images can be read from the same file by calling jpeg_stdio_src |
||
151 | * only before the first one. (If we discarded the buffer at the end of |
||
152 | * one image, we'd likely lose the start of the next one.) |
||
153 | * This makes it unsafe to use this manager and a different source |
||
154 | * manager serially with the same JPEG object. Caveat programmer. |
||
155 | */ |
||
156 | if (cinfo->src == NULL) { /* first time for this JPEG object? */ |
||
157 | cinfo->src = (struct jpeg_source_mgr *) |
||
158 | (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, |
||
159 | sizeof(my_source_mgr)); |
||
160 | src = (my_source_mgr *) cinfo->src; |
||
161 | } |
||
162 | |||
163 | src = (my_source_mgr *) cinfo->src; |
||
164 | src->pub.init_source = init_source; |
||
165 | src->pub.fill_input_buffer = fill_input_buffer; |
||
166 | src->pub.skip_input_data = skip_input_data; |
||
167 | src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ |
||
168 | src->pub.term_source = term_source; |
||
169 | src->ctx = ctx; |
||
170 | src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ |
||
171 | src->pub.next_input_byte = NULL; /* until buffer loaded */ |
||
172 | } |
||
173 | |||
174 | /* Load a JPEG type image from an SDL datasource */ |
||
175 | SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src) |
||
176 | { |
||
177 | struct jpeg_error_mgr errmgr; |
||
178 | struct jpeg_decompress_struct cinfo; |
||
179 | JSAMPROW rowptr[1]; |
||
180 | SDL_Surface *surface; |
||
181 | |||
182 | /* Create a decompression structure and load the JPEG header */ |
||
183 | cinfo.err = jpeg_std_error(&errmgr); |
||
184 | jpeg_create_decompress(&cinfo); |
||
185 | jpeg_SDL_RW_src(&cinfo, src); |
||
186 | jpeg_read_header(&cinfo, TRUE); |
||
187 | |||
188 | /* Set 24-bit RGB output */ |
||
189 | cinfo.out_color_space = JCS_RGB; |
||
190 | cinfo.quantize_colors = FALSE; |
||
191 | #ifdef FAST_JPEG |
||
192 | cinfo.scale_num = 1; |
||
193 | cinfo.scale_denom = 1; |
||
194 | cinfo.dct_method = JDCT_FASTEST; |
||
195 | cinfo.do_fancy_upsampling = FALSE; |
||
196 | #endif |
||
197 | jpeg_calc_output_dimensions(&cinfo); |
||
198 | |||
199 | /* Allocate an output surface to hold the image */ |
||
200 | surface = SDL_AllocSurface(SDL_SWSURFACE, |
||
201 | cinfo.output_width, cinfo.output_height, 24, |
||
202 | #if SDL_BYTEORDER == SDL_LIL_ENDIAN |
||
203 | 0x0000FF, 0x00FF00, 0xFF0000, |
||
204 | #else |
||
205 | 0xFF0000, 0x00FF00, 0x0000FF, |
||
206 | #endif |
||
207 | 0); |
||
208 | if ( surface == NULL ) { |
||
209 | IMG_SetError("Out of memory"); |
||
210 | goto done; |
||
211 | } |
||
212 | |||
213 | /* Decompress the image */ |
||
214 | jpeg_start_decompress(&cinfo); |
||
215 | while ( cinfo.output_scanline < cinfo.output_height ) { |
||
216 | rowptr[0] = (JSAMPROW)(Uint8 *)surface->pixels + |
||
217 | cinfo.output_scanline * surface->pitch; |
||
218 | jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1); |
||
219 | } |
||
220 | jpeg_finish_decompress(&cinfo); |
||
221 | |||
222 | /* Clean up and return */ |
||
223 | done: |
||
224 | jpeg_destroy_decompress(&cinfo); |
||
225 | return(surface); |
||
226 | } |
||
227 | |||
228 | #else |
||
229 | |||
230 | /* See if an image is contained in a data source */ |
||
231 | int IMG_isJPG(SDL_RWops *src) |
||
232 | { |
||
233 | return(0); |
||
234 | } |
||
235 | |||
236 | /* Load a JPEG type image from an SDL datasource */ |
||
237 | SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src) |
||
238 | { |
||
239 | return(NULL); |
||
240 | } |
||
241 | |||
242 | #endif /* LOAD_JPG */>=> |