Mercurial > sdl-ios-xcode
annotate src/video/SDL_bmp.c @ 910:4ab6d1fd028f
Date: Sat, 26 Jun 2004 14:58:42 +0300
From: "Mike Gorchak"
Subject: QNX 6.3 fixes for SDL
Sam, I've added new OpenGL framework for SDL, which appeared in the new QNX version - 6.3. I've leave compatibility with previous QNX versions. And I've moved all GL specific functions to the separate module, like it done for the other platforms.
SDL is now ready for the QNX 6.3 :)
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 18 Jul 2004 19:46:38 +0000 |
parents | b8d311d90021 |
children | f14e3059e138 |
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) ) { | |
416 /* Set the BMP file header values */ | |
417 bfSize = 0; /* We'll write this when we're done */ | |
418 bfReserved1 = 0; | |
419 bfReserved2 = 0; | |
420 bfOffBits = 0; /* We'll write this when we're done */ | |
421 | |
422 /* Write the BMP file header values */ | |
423 fp_offset = SDL_RWtell(dst); | |
424 SDL_ClearError(); | |
425 SDL_RWwrite(dst, magic, 2, 1); | |
426 SDL_WriteLE32(dst, bfSize); | |
427 SDL_WriteLE16(dst, bfReserved1); | |
428 SDL_WriteLE16(dst, bfReserved2); | |
429 SDL_WriteLE32(dst, bfOffBits); | |
430 | |
431 /* Set the BMP info values */ | |
432 biSize = 40; | |
433 biWidth = surface->w; | |
434 biHeight = surface->h; | |
435 biPlanes = 1; | |
436 biBitCount = surface->format->BitsPerPixel; | |
437 biCompression = BI_RGB; | |
438 biSizeImage = surface->h*surface->pitch; | |
439 biXPelsPerMeter = 0; | |
440 biYPelsPerMeter = 0; | |
441 if ( surface->format->palette ) { | |
442 biClrUsed = surface->format->palette->ncolors; | |
443 } else { | |
444 biClrUsed = 0; | |
445 } | |
446 biClrImportant = 0; | |
447 | |
448 /* Write the BMP info values */ | |
449 SDL_WriteLE32(dst, biSize); | |
450 SDL_WriteLE32(dst, biWidth); | |
451 SDL_WriteLE32(dst, biHeight); | |
452 SDL_WriteLE16(dst, biPlanes); | |
453 SDL_WriteLE16(dst, biBitCount); | |
454 SDL_WriteLE32(dst, biCompression); | |
455 SDL_WriteLE32(dst, biSizeImage); | |
456 SDL_WriteLE32(dst, biXPelsPerMeter); | |
457 SDL_WriteLE32(dst, biYPelsPerMeter); | |
458 SDL_WriteLE32(dst, biClrUsed); | |
459 SDL_WriteLE32(dst, biClrImportant); | |
460 | |
461 /* Write the palette (in BGR color order) */ | |
462 if ( surface->format->palette ) { | |
463 SDL_Color *colors; | |
464 int ncolors; | |
465 | |
466 colors = surface->format->palette->colors; | |
467 ncolors = surface->format->palette->ncolors; | |
468 for ( i=0; i<ncolors; ++i ) { | |
469 SDL_RWwrite(dst, &colors[i].b, 1, 1); | |
470 SDL_RWwrite(dst, &colors[i].g, 1, 1); | |
471 SDL_RWwrite(dst, &colors[i].r, 1, 1); | |
472 SDL_RWwrite(dst, &colors[i].unused, 1, 1); | |
473 } | |
474 } | |
475 | |
476 /* Write the bitmap offset */ | |
477 bfOffBits = SDL_RWtell(dst)-fp_offset; | |
478 if ( SDL_RWseek(dst, fp_offset+10, SEEK_SET) < 0 ) { | |
479 SDL_Error(SDL_EFSEEK); | |
480 } | |
481 SDL_WriteLE32(dst, bfOffBits); | |
482 if ( SDL_RWseek(dst, fp_offset+bfOffBits, SEEK_SET) < 0 ) { | |
483 SDL_Error(SDL_EFSEEK); | |
484 } | |
485 | |
486 /* Write the bitmap image upside down */ | |
487 bits = (Uint8 *)surface->pixels+(surface->h*surface->pitch); | |
488 pad = ((surface->pitch%4) ? (4-(surface->pitch%4)) : 0); | |
489 while ( bits > (Uint8 *)surface->pixels ) { | |
490 bits -= surface->pitch; | |
491 if ( SDL_RWwrite(dst, bits, 1, surface->pitch) | |
492 != surface->pitch) { | |
493 SDL_Error(SDL_EFWRITE); | |
494 break; | |
495 } | |
496 if ( pad ) { | |
497 const Uint8 padbyte = 0; | |
498 for ( i=0; i<pad; ++i ) { | |
499 SDL_RWwrite(dst, &padbyte, 1, 1); | |
500 } | |
501 } | |
502 } | |
503 | |
504 /* Write the BMP file size */ | |
505 bfSize = SDL_RWtell(dst)-fp_offset; | |
506 if ( SDL_RWseek(dst, fp_offset+2, SEEK_SET) < 0 ) { | |
507 SDL_Error(SDL_EFSEEK); | |
508 } | |
509 SDL_WriteLE32(dst, bfSize); | |
510 if ( SDL_RWseek(dst, fp_offset+bfSize, SEEK_SET) < 0 ) { | |
511 SDL_Error(SDL_EFSEEK); | |
512 } | |
513 | |
514 /* Close it up.. */ | |
515 SDL_UnlockSurface(surface); | |
516 if ( surface != saveme ) { | |
517 SDL_FreeSurface(surface); | |
518 } | |
519 } | |
520 | |
521 if ( freedst && dst ) { | |
522 SDL_RWclose(dst); | |
523 } | |
524 return((strcmp(SDL_GetError(), "") == 0) ? 0 : -1); | |
525 } | |
526 | |
527 #endif /* ENABLE_FILE */ |