Mercurial > sdl-ios-xcode
annotate src/video/SDL_bmp.c @ 1143:71a2648acc75
Replaced Mac OS X's C++ cdrom code with almost-direct translation to C. Sam
requested this effort on the mailing list, apparently because of binary
compatibility issues between 10.4 and earlier systems (or gcc4 and earlier
compilers?).
Works fine with SDL12/test/testcdrom.c, with this command line:
./testcdrom -status -list -play -sleep 5000 -pause -sleep 3000 -resume \
-sleep 5000 -stop -sleep 3000 -play -sleep 3000 -stop \
-sleep 3000 -eject
Unix Makefiles work, XCode project still need updating for new filenames.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Thu, 22 Sep 2005 08:48:16 +0000 |
parents | f14e3059e138 |
children | c9b51268668f |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
769
b8d311d90021
Updated copyright information for 2004 (Happy New Year!)
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
3 Copyright (C) 1997-2004 Sam Lantinga |
0 | 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 | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 #ifndef DISABLE_FILE | |
29 | |
30 /* | |
31 Code to load and save surfaces in Windows BMP format. | |
32 | |
33 Why support BMP format? Well, it's a native format for Windows, and | |
34 most image processing programs can read and write it. It would be nice | |
35 to be able to have at least one image format that we can natively load | |
36 and save, and since PNG is so complex that it would bloat the library, | |
37 BMP is a good alternative. | |
38 | |
39 This code currently supports Win32 DIBs in uncompressed 8 and 24 bpp. | |
40 */ | |
41 | |
42 #include <string.h> | |
43 | |
44 #include "SDL_error.h" | |
45 #include "SDL_video.h" | |
46 #include "SDL_endian.h" | |
47 | |
48 /* Compression encodings for BMP files */ | |
49 #ifndef BI_RGB | |
50 #define BI_RGB 0 | |
51 #define BI_RLE8 1 | |
52 #define BI_RLE4 2 | |
53 #define BI_BITFIELDS 3 | |
54 #endif | |
55 | |
56 | |
57 SDL_Surface * SDL_LoadBMP_RW (SDL_RWops *src, int freesrc) | |
58 { | |
59 int was_error; | |
60 long fp_offset; | |
61 int bmpPitch; | |
62 int i, pad; | |
63 SDL_Surface *surface; | |
64 Uint32 Rmask; | |
65 Uint32 Gmask; | |
66 Uint32 Bmask; | |
67 SDL_Palette *palette; | |
68 Uint8 *bits; | |
69 int ExpandBMP; | |
70 | |
71 /* The Win32 BMP file header (14 bytes) */ | |
72 char magic[2]; | |
73 Uint32 bfSize; | |
74 Uint16 bfReserved1; | |
75 Uint16 bfReserved2; | |
76 Uint32 bfOffBits; | |
77 | |
78 /* The Win32 BITMAPINFOHEADER struct (40 bytes) */ | |
79 Uint32 biSize; | |
80 Sint32 biWidth; | |
81 Sint32 biHeight; | |
82 Uint16 biPlanes; | |
83 Uint16 biBitCount; | |
84 Uint32 biCompression; | |
85 Uint32 biSizeImage; | |
86 Sint32 biXPelsPerMeter; | |
87 Sint32 biYPelsPerMeter; | |
88 Uint32 biClrUsed; | |
89 Uint32 biClrImportant; | |
90 | |
91 /* Make sure we are passed a valid data source */ | |
92 surface = NULL; | |
93 was_error = 0; | |
94 if ( src == NULL ) { | |
95 was_error = 1; | |
96 goto done; | |
97 } | |
98 | |
99 /* Read in the BMP file header */ | |
100 fp_offset = SDL_RWtell(src); | |
101 SDL_ClearError(); | |
102 if ( SDL_RWread(src, magic, 1, 2) != 2 ) { | |
103 SDL_Error(SDL_EFREAD); | |
104 was_error = 1; | |
105 goto done; | |
106 } | |
107 if ( strncmp(magic, "BM", 2) != 0 ) { | |
108 SDL_SetError("File is not a Windows BMP file"); | |
109 was_error = 1; | |
110 goto done; | |
111 } | |
112 bfSize = SDL_ReadLE32(src); | |
113 bfReserved1 = SDL_ReadLE16(src); | |
114 bfReserved2 = SDL_ReadLE16(src); | |
115 bfOffBits = SDL_ReadLE32(src); | |
116 | |
117 /* Read the Win32 BITMAPINFOHEADER */ | |
118 biSize = SDL_ReadLE32(src); | |
119 if ( biSize == 12 ) { | |
120 biWidth = (Uint32)SDL_ReadLE16(src); | |
121 biHeight = (Uint32)SDL_ReadLE16(src); | |
122 biPlanes = SDL_ReadLE16(src); | |
123 biBitCount = SDL_ReadLE16(src); | |
124 biCompression = BI_RGB; | |
125 biSizeImage = 0; | |
126 biXPelsPerMeter = 0; | |
127 biYPelsPerMeter = 0; | |
128 biClrUsed = 0; | |
129 biClrImportant = 0; | |
130 } else { | |
131 biWidth = SDL_ReadLE32(src); | |
132 biHeight = SDL_ReadLE32(src); | |
133 biPlanes = SDL_ReadLE16(src); | |
134 biBitCount = SDL_ReadLE16(src); | |
135 biCompression = SDL_ReadLE32(src); | |
136 biSizeImage = SDL_ReadLE32(src); | |
137 biXPelsPerMeter = SDL_ReadLE32(src); | |
138 biYPelsPerMeter = SDL_ReadLE32(src); | |
139 biClrUsed = SDL_ReadLE32(src); | |
140 biClrImportant = SDL_ReadLE32(src); | |
141 } | |
142 | |
143 /* Check for read error */ | |
144 if ( strcmp(SDL_GetError(), "") != 0 ) { | |
145 was_error = 1; | |
146 goto done; | |
147 } | |
148 | |
149 /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */ | |
150 switch (biBitCount) { | |
151 case 1: | |
152 case 4: | |
153 ExpandBMP = biBitCount; | |
154 biBitCount = 8; | |
155 break; | |
156 default: | |
157 ExpandBMP = 0; | |
158 break; | |
159 } | |
160 | |
161 /* We don't support any BMP compression right now */ | |
162 Rmask = Gmask = Bmask = 0; | |
163 switch (biCompression) { | |
164 case BI_RGB: | |
165 /* If there are no masks, use the defaults */ | |
166 if ( bfOffBits == (14+biSize) ) { | |
167 /* Default values for the BMP format */ | |
168 switch (biBitCount) { | |
169 case 15: | |
170 case 16: | |
171 Rmask = 0x7C00; | |
172 Gmask = 0x03E0; | |
173 Bmask = 0x001F; | |
174 break; | |
175 case 24: | |
176 #if SDL_BYTEORDER == SDL_BIG_ENDIAN | |
177 Rmask = 0x000000FF; | |
178 Gmask = 0x0000FF00; | |
179 Bmask = 0x00FF0000; | |
180 break; | |
181 #endif | |
182 case 32: | |
183 Rmask = 0x00FF0000; | |
184 Gmask = 0x0000FF00; | |
185 Bmask = 0x000000FF; | |
186 break; | |
187 default: | |
188 break; | |
189 } | |
190 break; | |
191 } | |
192 /* Fall through -- read the RGB masks */ | |
193 | |
194 case BI_BITFIELDS: | |
195 switch (biBitCount) { | |
196 case 15: | |
197 case 16: | |
198 case 32: | |
199 Rmask = SDL_ReadLE32(src); | |
200 Gmask = SDL_ReadLE32(src); | |
201 Bmask = SDL_ReadLE32(src); | |
202 break; | |
203 default: | |
204 break; | |
205 } | |
206 break; | |
207 default: | |
208 SDL_SetError("Compressed BMP files not supported"); | |
209 was_error = 1; | |
210 goto done; | |
211 } | |
212 | |
213 /* Create a compatible surface, note that the colors are RGB ordered */ | |
214 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, | |
215 biWidth, biHeight, biBitCount, Rmask, Gmask, Bmask, 0); | |
216 if ( surface == NULL ) { | |
217 was_error = 1; | |
218 goto done; | |
219 } | |
220 | |
221 /* Load the palette, if any */ | |
222 palette = (surface->format)->palette; | |
223 if ( palette ) { | |
224 if ( biClrUsed == 0 ) { | |
225 biClrUsed = 1 << biBitCount; | |
226 } | |
227 if ( biSize == 12 ) { | |
228 for ( i = 0; i < (int)biClrUsed; ++i ) { | |
229 SDL_RWread(src, &palette->colors[i].b, 1, 1); | |
230 SDL_RWread(src, &palette->colors[i].g, 1, 1); | |
231 SDL_RWread(src, &palette->colors[i].r, 1, 1); | |
232 palette->colors[i].unused = 0; | |
233 } | |
234 } else { | |
235 for ( i = 0; i < (int)biClrUsed; ++i ) { | |
236 SDL_RWread(src, &palette->colors[i].b, 1, 1); | |
237 SDL_RWread(src, &palette->colors[i].g, 1, 1); | |
238 SDL_RWread(src, &palette->colors[i].r, 1, 1); | |
239 SDL_RWread(src, &palette->colors[i].unused, 1, 1); | |
240 } | |
241 } | |
242 palette->ncolors = biClrUsed; | |
243 } | |
244 | |
245 /* Read the surface pixels. Note that the bmp image is upside down */ | |
246 if ( SDL_RWseek(src, fp_offset+bfOffBits, SEEK_SET) < 0 ) { | |
247 SDL_Error(SDL_EFSEEK); | |
248 was_error = 1; | |
249 goto done; | |
250 } | |
251 bits = (Uint8 *)surface->pixels+(surface->h*surface->pitch); | |
252 switch (ExpandBMP) { | |
253 case 1: | |
254 bmpPitch = (biWidth + 7) >> 3; | |
255 pad = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0); | |
256 break; | |
257 case 4: | |
258 bmpPitch = (biWidth + 1) >> 1; | |
259 pad = (((bmpPitch)%4) ? (4-((bmpPitch)%4)) : 0); | |
260 break; | |
261 default: | |
262 pad = ((surface->pitch%4) ? | |
263 (4-(surface->pitch%4)) : 0); | |
264 break; | |
265 } | |
266 while ( bits > (Uint8 *)surface->pixels ) { | |
267 bits -= surface->pitch; | |
268 switch (ExpandBMP) { | |
269 case 1: | |
270 case 4: { | |
271 Uint8 pixel = 0; | |
272 int shift = (8-ExpandBMP); | |
273 for ( i=0; i<surface->w; ++i ) { | |
274 if ( i%(8/ExpandBMP) == 0 ) { | |
275 if ( !SDL_RWread(src, &pixel, 1, 1) ) { | |
276 SDL_SetError( | |
277 "Error reading from BMP"); | |
278 was_error = 1; | |
279 goto done; | |
280 } | |
281 } | |
282 *(bits+i) = (pixel>>shift); | |
283 pixel <<= ExpandBMP; | |
284 } } | |
285 break; | |
286 | |
287 default: | |
288 if ( SDL_RWread(src, bits, 1, surface->pitch) | |
289 != surface->pitch ) { | |
290 SDL_Error(SDL_EFREAD); | |
291 was_error = 1; | |
292 goto done; | |
293 } | |
294 #if SDL_BYTEORDER == SDL_BIG_ENDIAN | |
295 /* Byte-swap the pixels if needed. Note that the 24bpp | |
296 case has already been taken care of above. */ | |
297 switch(biBitCount) { | |
298 case 15: | |
299 case 16: { | |
300 Uint16 *pix = (Uint16 *)bits; | |
301 for(i = 0; i < surface->w; i++) | |
302 pix[i] = SDL_Swap16(pix[i]); | |
303 break; | |
304 } | |
305 | |
306 case 32: { | |
307 Uint32 *pix = (Uint32 *)bits; | |
308 for(i = 0; i < surface->w; i++) | |
309 pix[i] = SDL_Swap32(pix[i]); | |
310 break; | |
311 } | |
312 } | |
313 #endif | |
314 break; | |
315 } | |
316 /* Skip padding bytes, ugh */ | |
317 if ( pad ) { | |
318 Uint8 padbyte; | |
319 for ( i=0; i<pad; ++i ) { | |
320 SDL_RWread(src, &padbyte, 1, 1); | |
321 } | |
322 } | |
323 } | |
324 done: | |
325 if ( was_error ) { | |
326 if ( surface ) { | |
327 SDL_FreeSurface(surface); | |
328 } | |
329 surface = NULL; | |
330 } | |
331 if ( freesrc && src ) { | |
332 SDL_RWclose(src); | |
333 } | |
334 return(surface); | |
335 } | |
336 | |
337 int SDL_SaveBMP_RW (SDL_Surface *saveme, SDL_RWops *dst, int freedst) | |
338 { | |
339 long fp_offset; | |
340 int i, pad; | |
341 SDL_Surface *surface; | |
342 Uint8 *bits; | |
343 | |
344 /* The Win32 BMP file header (14 bytes) */ | |
345 char magic[2] = { 'B', 'M' }; | |
346 Uint32 bfSize; | |
347 Uint16 bfReserved1; | |
348 Uint16 bfReserved2; | |
349 Uint32 bfOffBits; | |
350 | |
351 /* The Win32 BITMAPINFOHEADER struct (40 bytes) */ | |
352 Uint32 biSize; | |
353 Sint32 biWidth; | |
354 Sint32 biHeight; | |
355 Uint16 biPlanes; | |
356 Uint16 biBitCount; | |
357 Uint32 biCompression; | |
358 Uint32 biSizeImage; | |
359 Sint32 biXPelsPerMeter; | |
360 Sint32 biYPelsPerMeter; | |
361 Uint32 biClrUsed; | |
362 Uint32 biClrImportant; | |
363 | |
364 /* Make sure we have somewhere to save */ | |
365 surface = NULL; | |
366 if ( dst ) { | |
367 if ( saveme->format->palette ) { | |
368 if ( saveme->format->BitsPerPixel == 8 ) { | |
369 surface = saveme; | |
370 } else { | |
371 SDL_SetError("%d bpp BMP files not supported", | |
372 saveme->format->BitsPerPixel); | |
373 } | |
374 } | |
375 else if ( (saveme->format->BitsPerPixel == 24) && | |
376 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
377 (saveme->format->Rmask == 0x00FF0000) && | |
378 (saveme->format->Gmask == 0x0000FF00) && | |
379 (saveme->format->Bmask == 0x000000FF) | |
380 #else | |
381 (saveme->format->Rmask == 0x000000FF) && | |
382 (saveme->format->Gmask == 0x0000FF00) && | |
383 (saveme->format->Bmask == 0x00FF0000) | |
384 #endif | |
385 ) { | |
386 surface = saveme; | |
387 } else { | |
388 SDL_Rect bounds; | |
389 | |
390 /* Convert to 24 bits per pixel */ | |
391 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, | |
392 saveme->w, saveme->h, 24, | |
393 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
394 0x00FF0000, 0x0000FF00, 0x000000FF, | |
395 #else | |
396 0x000000FF, 0x0000FF00, 0x00FF0000, | |
397 #endif | |
398 0); | |
399 if ( surface != NULL ) { | |
400 bounds.x = 0; | |
401 bounds.y = 0; | |
402 bounds.w = saveme->w; | |
403 bounds.h = saveme->h; | |
404 if ( SDL_LowerBlit(saveme, &bounds, surface, | |
405 &bounds) < 0 ) { | |
406 SDL_FreeSurface(surface); | |
407 SDL_SetError( | |
408 "Couldn't convert image to 24 bpp"); | |
409 surface = NULL; | |
410 } | |
411 } | |
412 } | |
413 } | |
414 | |
415 if ( surface && (SDL_LockSurface(surface) == 0) ) { | |
1012
f14e3059e138
Date: Mon, 13 Dec 2004 21:28:18 -0500
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
416 const int bw = surface->w*surface->format->BytesPerPixel; |
f14e3059e138
Date: Mon, 13 Dec 2004 21:28:18 -0500
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
417 |
0 | 418 /* Set the BMP file header values */ |
419 bfSize = 0; /* We'll write this when we're done */ | |
420 bfReserved1 = 0; | |
421 bfReserved2 = 0; | |
422 bfOffBits = 0; /* We'll write this when we're done */ | |
423 | |
424 /* Write the BMP file header values */ | |
425 fp_offset = SDL_RWtell(dst); | |
426 SDL_ClearError(); | |
427 SDL_RWwrite(dst, magic, 2, 1); | |
428 SDL_WriteLE32(dst, bfSize); | |
429 SDL_WriteLE16(dst, bfReserved1); | |
430 SDL_WriteLE16(dst, bfReserved2); | |
431 SDL_WriteLE32(dst, bfOffBits); | |
432 | |
433 /* Set the BMP info values */ | |
434 biSize = 40; | |
435 biWidth = surface->w; | |
436 biHeight = surface->h; | |
437 biPlanes = 1; | |
438 biBitCount = surface->format->BitsPerPixel; | |
439 biCompression = BI_RGB; | |
440 biSizeImage = surface->h*surface->pitch; | |
441 biXPelsPerMeter = 0; | |
442 biYPelsPerMeter = 0; | |
443 if ( surface->format->palette ) { | |
444 biClrUsed = surface->format->palette->ncolors; | |
445 } else { | |
446 biClrUsed = 0; | |
447 } | |
448 biClrImportant = 0; | |
449 | |
450 /* Write the BMP info values */ | |
451 SDL_WriteLE32(dst, biSize); | |
452 SDL_WriteLE32(dst, biWidth); | |
453 SDL_WriteLE32(dst, biHeight); | |
454 SDL_WriteLE16(dst, biPlanes); | |
455 SDL_WriteLE16(dst, biBitCount); | |
456 SDL_WriteLE32(dst, biCompression); | |
457 SDL_WriteLE32(dst, biSizeImage); | |
458 SDL_WriteLE32(dst, biXPelsPerMeter); | |
459 SDL_WriteLE32(dst, biYPelsPerMeter); | |
460 SDL_WriteLE32(dst, biClrUsed); | |
461 SDL_WriteLE32(dst, biClrImportant); | |
462 | |
463 /* Write the palette (in BGR color order) */ | |
464 if ( surface->format->palette ) { | |
465 SDL_Color *colors; | |
466 int ncolors; | |
467 | |
468 colors = surface->format->palette->colors; | |
469 ncolors = surface->format->palette->ncolors; | |
470 for ( i=0; i<ncolors; ++i ) { | |
471 SDL_RWwrite(dst, &colors[i].b, 1, 1); | |
472 SDL_RWwrite(dst, &colors[i].g, 1, 1); | |
473 SDL_RWwrite(dst, &colors[i].r, 1, 1); | |
474 SDL_RWwrite(dst, &colors[i].unused, 1, 1); | |
475 } | |
476 } | |
477 | |
478 /* Write the bitmap offset */ | |
479 bfOffBits = SDL_RWtell(dst)-fp_offset; | |
480 if ( SDL_RWseek(dst, fp_offset+10, SEEK_SET) < 0 ) { | |
481 SDL_Error(SDL_EFSEEK); | |
482 } | |
483 SDL_WriteLE32(dst, bfOffBits); | |
484 if ( SDL_RWseek(dst, fp_offset+bfOffBits, SEEK_SET) < 0 ) { | |
485 SDL_Error(SDL_EFSEEK); | |
486 } | |
487 | |
488 /* Write the bitmap image upside down */ | |
489 bits = (Uint8 *)surface->pixels+(surface->h*surface->pitch); | |
1012
f14e3059e138
Date: Mon, 13 Dec 2004 21:28:18 -0500
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
490 pad = ((bw%4) ? (4-(bw%4)) : 0); |
0 | 491 while ( bits > (Uint8 *)surface->pixels ) { |
492 bits -= surface->pitch; | |
1012
f14e3059e138
Date: Mon, 13 Dec 2004 21:28:18 -0500
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
493 if ( SDL_RWwrite(dst, bits, 1, bw) != bw) { |
0 | 494 SDL_Error(SDL_EFWRITE); |
495 break; | |
496 } | |
497 if ( pad ) { | |
498 const Uint8 padbyte = 0; | |
499 for ( i=0; i<pad; ++i ) { | |
500 SDL_RWwrite(dst, &padbyte, 1, 1); | |
501 } | |
502 } | |
503 } | |
504 | |
505 /* Write the BMP file size */ | |
506 bfSize = SDL_RWtell(dst)-fp_offset; | |
507 if ( SDL_RWseek(dst, fp_offset+2, SEEK_SET) < 0 ) { | |
508 SDL_Error(SDL_EFSEEK); | |
509 } | |
510 SDL_WriteLE32(dst, bfSize); | |
511 if ( SDL_RWseek(dst, fp_offset+bfSize, SEEK_SET) < 0 ) { | |
512 SDL_Error(SDL_EFSEEK); | |
513 } | |
514 | |
515 /* Close it up.. */ | |
516 SDL_UnlockSurface(surface); | |
517 if ( surface != saveme ) { | |
518 SDL_FreeSurface(surface); | |
519 } | |
520 } | |
521 | |
522 if ( freedst && dst ) { | |
523 SDL_RWclose(dst); | |
524 } | |
525 return((strcmp(SDL_GetError(), "") == 0) ? 0 : -1); | |
526 } | |
527 | |
528 #endif /* ENABLE_FILE */ |