SDL 2.0
SDL_bmp.c File Reference
#include "../SDL_internal.h"
#include "SDL_hints.h"
#include "SDL_video.h"
#include "SDL_assert.h"
#include "SDL_endian.h"
#include "SDL_pixels_c.h"
+ Include dependency graph for SDL_bmp.c:

Go to the source code of this file.

Macros

#define SAVE_32BIT_BMP
 
#define BI_RGB   0
 
#define BI_RLE8   1
 
#define BI_RLE4   2
 
#define BI_BITFIELDS   3
 
#define LCS_WINDOWS_COLOR_SPACE   0x57696E20
 

Functions

static void CorrectAlphaChannel (SDL_Surface *surface)
 
SDL_SurfaceSDL_LoadBMP_RW (SDL_RWops *src, int freesrc)
 
int SDL_SaveBMP_RW (SDL_Surface *saveme, SDL_RWops *dst, int freedst)
 

Macro Definition Documentation

◆ BI_BITFIELDS

#define BI_BITFIELDS   3

Definition at line 48 of file SDL_bmp.c.

◆ BI_RGB

#define BI_RGB   0

Definition at line 45 of file SDL_bmp.c.

◆ BI_RLE4

#define BI_RLE4   2

Definition at line 47 of file SDL_bmp.c.

◆ BI_RLE8

#define BI_RLE8   1

Definition at line 46 of file SDL_bmp.c.

◆ LCS_WINDOWS_COLOR_SPACE

#define LCS_WINDOWS_COLOR_SPACE   0x57696E20

Definition at line 54 of file SDL_bmp.c.

◆ SAVE_32BIT_BMP

#define SAVE_32BIT_BMP

Definition at line 41 of file SDL_bmp.c.

Function Documentation

◆ CorrectAlphaChannel()

static void CorrectAlphaChannel ( SDL_Surface surface)
static

Definition at line 57 of file SDL_bmp.c.

58{
59 /* Check to see if there is any alpha channel data */
60 SDL_bool hasAlpha = SDL_FALSE;
61#if SDL_BYTEORDER == SDL_BIG_ENDIAN
62 int alphaChannelOffset = 0;
63#else
64 int alphaChannelOffset = 3;
65#endif
66 Uint8 *alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
67 Uint8 *end = alpha + surface->h * surface->pitch;
68
69 while (alpha < end) {
70 if (*alpha != 0) {
71 hasAlpha = SDL_TRUE;
72 break;
73 }
74 alpha += 4;
75 }
76
77 if (!hasAlpha) {
78 alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
79 while (alpha < end) {
81 alpha += 4;
82 }
83 }
84}
GLuint GLuint end
Definition: SDL_opengl.h:1571
GLfloat GLfloat GLfloat alpha
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:46
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
uint8_t Uint8
Definition: SDL_stdinc.h:179
EGLSurface surface
Definition: eglext.h:248

References SDL_ALPHA_OPAQUE, SDL_FALSE, and SDL_TRUE.

Referenced by SDL_LoadBMP_RW().

◆ SDL_LoadBMP_RW()

SDL_Surface * SDL_LoadBMP_RW ( SDL_RWops src,
int  freesrc 
)

Load a surface from a seekable SDL data stream (memory or file).

If freesrc is non-zero, the stream will be closed after being read.

The new surface should be freed with SDL_FreeSurface().

Returns
the new surface, or NULL if there was an error.

Definition at line 87 of file SDL_bmp.c.

88{
89 SDL_bool was_error;
90 Sint64 fp_offset = 0;
91 int bmpPitch;
92 int i, pad;
94 Uint32 Rmask = 0;
95 Uint32 Gmask = 0;
96 Uint32 Bmask = 0;
97 Uint32 Amask = 0;
98 SDL_Palette *palette;
99 Uint8 *bits;
100 Uint8 *top, *end;
101 SDL_bool topDown;
102 int ExpandBMP;
103 SDL_bool haveRGBMasks = SDL_FALSE;
104 SDL_bool haveAlphaMask = SDL_FALSE;
105 SDL_bool correctAlpha = SDL_FALSE;
106
107 /* The Win32 BMP file header (14 bytes) */
108 char magic[2];
109 /* Uint32 bfSize = 0; */
110 /* Uint16 bfReserved1 = 0; */
111 /* Uint16 bfReserved2 = 0; */
112 Uint32 bfOffBits = 0;
113
114 /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
115 Uint32 biSize = 0;
116 Sint32 biWidth = 0;
117 Sint32 biHeight = 0;
118 /* Uint16 biPlanes = 0; */
119 Uint16 biBitCount = 0;
120 Uint32 biCompression = 0;
121 /* Uint32 biSizeImage = 0; */
122 /* Sint32 biXPelsPerMeter = 0; */
123 /* Sint32 biYPelsPerMeter = 0; */
124 Uint32 biClrUsed = 0;
125 /* Uint32 biClrImportant = 0; */
126
127 (void) haveRGBMasks;
128 (void) haveAlphaMask;
129
130 /* Make sure we are passed a valid data source */
131 surface = NULL;
132 was_error = SDL_FALSE;
133 if (src == NULL) {
134 was_error = SDL_TRUE;
135 goto done;
136 }
137
138 /* Read in the BMP file header */
139 fp_offset = SDL_RWtell(src);
141 if (SDL_RWread(src, magic, 1, 2) != 2) {
143 was_error = SDL_TRUE;
144 goto done;
145 }
146 if (SDL_strncmp(magic, "BM", 2) != 0) {
147 SDL_SetError("File is not a Windows BMP file");
148 was_error = SDL_TRUE;
149 goto done;
150 }
151 /* bfSize = */ SDL_ReadLE32(src);
152 /* bfReserved1 = */ SDL_ReadLE16(src);
153 /* bfReserved2 = */ SDL_ReadLE16(src);
154 bfOffBits = SDL_ReadLE32(src);
155
156 /* Read the Win32 BITMAPINFOHEADER */
157 biSize = SDL_ReadLE32(src);
158 if (biSize == 12) { /* really old BITMAPCOREHEADER */
159 biWidth = (Uint32) SDL_ReadLE16(src);
160 biHeight = (Uint32) SDL_ReadLE16(src);
161 /* biPlanes = */ SDL_ReadLE16(src);
162 biBitCount = SDL_ReadLE16(src);
163 biCompression = BI_RGB;
164 } else if (biSize >= 40) { /* some version of BITMAPINFOHEADER */
165 Uint32 headerSize;
166 biWidth = SDL_ReadLE32(src);
167 biHeight = SDL_ReadLE32(src);
168 /* biPlanes = */ SDL_ReadLE16(src);
169 biBitCount = SDL_ReadLE16(src);
170 biCompression = SDL_ReadLE32(src);
171 /* biSizeImage = */ SDL_ReadLE32(src);
172 /* biXPelsPerMeter = */ SDL_ReadLE32(src);
173 /* biYPelsPerMeter = */ SDL_ReadLE32(src);
174 biClrUsed = SDL_ReadLE32(src);
175 /* biClrImportant = */ SDL_ReadLE32(src);
176
177 /* 64 == BITMAPCOREHEADER2, an incompatible OS/2 2.x extension. Skip this stuff for now. */
178 if (biSize == 64) {
179 /* ignore these extra fields. */
180 if (biCompression == BI_BITFIELDS) {
181 /* this value is actually huffman compression in this variant. */
182 SDL_SetError("Compressed BMP files not supported");
183 was_error = SDL_TRUE;
184 goto done;
185 }
186 } else {
187 /* This is complicated. If compression is BI_BITFIELDS, then
188 we have 3 DWORDS that specify the RGB masks. This is either
189 stored here in an BITMAPV2INFOHEADER (which only differs in
190 that it adds these RGB masks) and biSize >= 52, or we've got
191 these masks stored in the exact same place, but strictly
192 speaking, this is the bmiColors field in BITMAPINFO immediately
193 following the legacy v1 info header, just past biSize. */
194 if (biCompression == BI_BITFIELDS) {
195 haveRGBMasks = SDL_TRUE;
196 Rmask = SDL_ReadLE32(src);
197 Gmask = SDL_ReadLE32(src);
198 Bmask = SDL_ReadLE32(src);
199
200 /* ...v3 adds an alpha mask. */
201 if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
202 haveAlphaMask = SDL_TRUE;
203 Amask = SDL_ReadLE32(src);
204 }
205 } else {
206 /* the mask fields are ignored for v2+ headers if not BI_BITFIELD. */
207 if (biSize >= 52) { /* BITMAPV2INFOHEADER; adds RGB masks */
208 /*Rmask = */ SDL_ReadLE32(src);
209 /*Gmask = */ SDL_ReadLE32(src);
210 /*Bmask = */ SDL_ReadLE32(src);
211 }
212 if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
213 /*Amask = */ SDL_ReadLE32(src);
214 }
215 }
216
217 /* Insert other fields here; Wikipedia and MSDN say we're up to
218 v5 of this header, but we ignore those for now (they add gamma,
219 color spaces, etc). Ignoring the weird OS/2 2.x format, we
220 currently parse up to v3 correctly (hopefully!). */
221 }
222
223 /* skip any header bytes we didn't handle... */
224 headerSize = (Uint32) (SDL_RWtell(src) - (fp_offset + 14));
225 if (biSize > headerSize) {
226 SDL_RWseek(src, (biSize - headerSize), RW_SEEK_CUR);
227 }
228 }
229 if (biWidth <= 0 || biHeight == 0) {
230 SDL_SetError("BMP file with bad dimensions (%dx%d)", biWidth, biHeight);
231 was_error = SDL_TRUE;
232 goto done;
233 }
234 if (biHeight < 0) {
235 topDown = SDL_TRUE;
236 biHeight = -biHeight;
237 } else {
238 topDown = SDL_FALSE;
239 }
240
241 /* Check for read error */
242 if (SDL_strcmp(SDL_GetError(), "") != 0) {
243 was_error = SDL_TRUE;
244 goto done;
245 }
246
247 /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
248 switch (biBitCount) {
249 case 1:
250 case 4:
251 ExpandBMP = biBitCount;
252 biBitCount = 8;
253 break;
254 case 2:
255 case 3:
256 case 5:
257 case 6:
258 case 7:
259 SDL_SetError("%d-bpp BMP images are not supported", biBitCount);
260 was_error = SDL_TRUE;
261 goto done;
262 default:
263 ExpandBMP = 0;
264 break;
265 }
266
267 /* We don't support any BMP compression right now */
268 switch (biCompression) {
269 case BI_RGB:
270 /* If there are no masks, use the defaults */
271 SDL_assert(!haveRGBMasks);
272 SDL_assert(!haveAlphaMask);
273 /* Default values for the BMP format */
274 switch (biBitCount) {
275 case 15:
276 case 16:
277 Rmask = 0x7C00;
278 Gmask = 0x03E0;
279 Bmask = 0x001F;
280 break;
281 case 24:
282#if SDL_BYTEORDER == SDL_BIG_ENDIAN
283 Rmask = 0x000000FF;
284 Gmask = 0x0000FF00;
285 Bmask = 0x00FF0000;
286#else
287 Rmask = 0x00FF0000;
288 Gmask = 0x0000FF00;
289 Bmask = 0x000000FF;
290#endif
291 break;
292 case 32:
293 /* We don't know if this has alpha channel or not */
294 correctAlpha = SDL_TRUE;
295 Amask = 0xFF000000;
296 Rmask = 0x00FF0000;
297 Gmask = 0x0000FF00;
298 Bmask = 0x000000FF;
299 break;
300 default:
301 break;
302 }
303 break;
304
305 case BI_BITFIELDS:
306 break; /* we handled this in the info header. */
307
308 default:
309 SDL_SetError("Compressed BMP files not supported");
310 was_error = SDL_TRUE;
311 goto done;
312 }
313
314 /* Create a compatible surface, note that the colors are RGB ordered */
315 surface =
316 SDL_CreateRGBSurface(0, biWidth, biHeight, biBitCount, Rmask, Gmask,
317 Bmask, Amask);
318 if (surface == NULL) {
319 was_error = SDL_TRUE;
320 goto done;
321 }
322
323 /* Load the palette, if any */
324 palette = (surface->format)->palette;
325 if (palette) {
326 SDL_assert(biBitCount <= 8);
327 if (biClrUsed == 0) {
328 biClrUsed = 1 << biBitCount;
329 } else if (biClrUsed > (Uint32)(1 << biBitCount)) {
330 SDL_SetError("BMP file has an invalid number of colors");
331 was_error = SDL_TRUE;
332 goto done;
333 }
334 if ((int) biClrUsed > palette->ncolors) {
336 int ncolors = biClrUsed;
337 colors =
338 (SDL_Color *) SDL_realloc(palette->colors,
339 ncolors *
340 sizeof(*palette->colors));
341 if (!colors) {
343 was_error = SDL_TRUE;
344 goto done;
345 }
346 palette->ncolors = ncolors;
347 palette->colors = colors;
348 } else if ((int) biClrUsed < palette->ncolors) {
349 palette->ncolors = biClrUsed;
350 }
351 if (biSize == 12) {
352 for (i = 0; i < (int) biClrUsed; ++i) {
353 SDL_RWread(src, &palette->colors[i].b, 1, 1);
354 SDL_RWread(src, &palette->colors[i].g, 1, 1);
355 SDL_RWread(src, &palette->colors[i].r, 1, 1);
356 palette->colors[i].a = SDL_ALPHA_OPAQUE;
357 }
358 } else {
359 for (i = 0; i < (int) biClrUsed; ++i) {
360 SDL_RWread(src, &palette->colors[i].b, 1, 1);
361 SDL_RWread(src, &palette->colors[i].g, 1, 1);
362 SDL_RWread(src, &palette->colors[i].r, 1, 1);
363 SDL_RWread(src, &palette->colors[i].a, 1, 1);
364
365 /* According to Microsoft documentation, the fourth element
366 is reserved and must be zero, so we shouldn't treat it as
367 alpha.
368 */
369 palette->colors[i].a = SDL_ALPHA_OPAQUE;
370 }
371 }
372 }
373
374 /* Read the surface pixels. Note that the bmp image is upside down */
375 if (SDL_RWseek(src, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
377 was_error = SDL_TRUE;
378 goto done;
379 }
380 top = (Uint8 *)surface->pixels;
381 end = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
382 switch (ExpandBMP) {
383 case 1:
384 bmpPitch = (biWidth + 7) >> 3;
385 pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
386 break;
387 case 4:
388 bmpPitch = (biWidth + 1) >> 1;
389 pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
390 break;
391 default:
392 pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
393 break;
394 }
395 if (topDown) {
396 bits = top;
397 } else {
398 bits = end - surface->pitch;
399 }
400 while (bits >= top && bits < end) {
401 switch (ExpandBMP) {
402 case 1:
403 case 4:{
404 Uint8 pixel = 0;
405 int shift = (8 - ExpandBMP);
406 for (i = 0; i < surface->w; ++i) {
407 if (i % (8 / ExpandBMP) == 0) {
408 if (!SDL_RWread(src, &pixel, 1, 1)) {
409 SDL_SetError("Error reading from BMP");
410 was_error = SDL_TRUE;
411 goto done;
412 }
413 }
414 bits[i] = (pixel >> shift);
415 if (bits[i] >= biClrUsed) {
416 SDL_SetError("A BMP image contains a pixel with a color out of the palette");
417 was_error = SDL_TRUE;
418 goto done;
419 }
420 pixel <<= ExpandBMP;
421 }
422 }
423 break;
424
425 default:
426 if (SDL_RWread(src, bits, 1, surface->pitch) != surface->pitch) {
428 was_error = SDL_TRUE;
429 goto done;
430 }
431 if (biBitCount == 8 && palette && biClrUsed < (Uint32)(1 << biBitCount)) {
432 for (i = 0; i < surface->w; ++i) {
433 if (bits[i] >= biClrUsed) {
434 SDL_SetError("A BMP image contains a pixel with a color out of the palette");
435 was_error = SDL_TRUE;
436 goto done;
437 }
438 }
439 }
440#if SDL_BYTEORDER == SDL_BIG_ENDIAN
441 /* Byte-swap the pixels if needed. Note that the 24bpp
442 case has already been taken care of above. */
443 switch (biBitCount) {
444 case 15:
445 case 16:{
446 Uint16 *pix = (Uint16 *) bits;
447 for (i = 0; i < surface->w; i++)
448 pix[i] = SDL_Swap16(pix[i]);
449 break;
450 }
451
452 case 32:{
453 Uint32 *pix = (Uint32 *) bits;
454 for (i = 0; i < surface->w; i++)
455 pix[i] = SDL_Swap32(pix[i]);
456 break;
457 }
458 }
459#endif
460 break;
461 }
462 /* Skip padding bytes, ugh */
463 if (pad) {
464 Uint8 padbyte;
465 for (i = 0; i < pad; ++i) {
466 SDL_RWread(src, &padbyte, 1, 1);
467 }
468 }
469 if (topDown) {
470 bits += surface->pitch;
471 } else {
472 bits -= surface->pitch;
473 }
474 }
475 if (correctAlpha) {
477 }
478 done:
479 if (was_error) {
480 if (src) {
481 SDL_RWseek(src, fp_offset, RW_SEEK_SET);
482 }
484 surface = NULL;
485 }
486 if (freesrc && src) {
488 }
489 return (surface);
490}
#define SDL_assert(condition)
Definition: SDL_assert.h:169
#define BI_BITFIELDS
Definition: SDL_bmp.c:48
#define BI_RGB
Definition: SDL_bmp.c:45
static void CorrectAlphaChannel(SDL_Surface *surface)
Definition: SDL_bmp.c:57
#define SDL_SetError
#define SDL_GetError
#define SDL_ReadLE16
#define SDL_strncmp
#define SDL_ReadLE32
#define SDL_Error
#define SDL_RWtell
#define SDL_RWread
#define SDL_realloc
#define SDL_RWseek
#define SDL_ClearError
#define SDL_strcmp
#define SDL_CreateRGBSurface
#define SDL_FreeSurface
#define SDL_RWclose
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
Definition: SDL_endian.h:162
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
Definition: SDL_endian.h:107
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
@ SDL_EFSEEK
Definition: SDL_error.h:60
@ SDL_EFREAD
Definition: SDL_error.h:58
GLdouble GLdouble GLdouble GLdouble top
GLenum src
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
#define RW_SEEK_CUR
Definition: SDL_rwops.h:175
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
uint32_t Uint32
Definition: SDL_stdinc.h:203
int32_t Sint32
Definition: SDL_stdinc.h:197
uint16_t Uint16
Definition: SDL_stdinc.h:191
int64_t Sint64
Definition: SDL_stdinc.h:210
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
int done
Definition: checkkeys.c:28
Uint8 r
Definition: SDL_pixels.h:297
Uint8 b
Definition: SDL_pixels.h:299
Uint8 a
Definition: SDL_pixels.h:300
Uint8 g
Definition: SDL_pixels.h:298
SDL_Color * colors
Definition: SDL_pixels.h:307
A collection of pixels used in software blitting.
Definition: SDL_surface.h:71
static int colors[7]
Definition: testgesture.c:41

References SDL_Color::a, SDL_Color::b, BI_BITFIELDS, BI_RGB, SDL_Palette::colors, colors, CorrectAlphaChannel(), done, SDL_Color::g, i, SDL_Palette::ncolors, NULL, SDL_Color::r, RW_SEEK_CUR, RW_SEEK_SET, SDL_ALPHA_OPAQUE, SDL_assert, SDL_ClearError, SDL_CreateRGBSurface, SDL_EFREAD, SDL_EFSEEK, SDL_Error, SDL_FALSE, SDL_FreeSurface, SDL_GetError, SDL_OutOfMemory, SDL_ReadLE16, SDL_ReadLE32, SDL_realloc, SDL_RWclose, SDL_RWread, SDL_RWseek, SDL_RWtell, SDL_SetError, SDL_strcmp, SDL_strncmp, SDL_Swap16(), SDL_Swap32(), SDL_TRUE, and void.

◆ SDL_SaveBMP_RW()

int SDL_SaveBMP_RW ( SDL_Surface surface,
SDL_RWops dst,
int  freedst 
)

Save a surface to a seekable SDL data stream (memory or file).

Surfaces with a 24-bit, 32-bit and paletted 8-bit format get saved in the BMP directly. Other RGB formats with 8-bit or higher get converted to a 24-bit surface or, if they have an alpha mask or a colorkey, to a 32-bit surface before they are saved. YUV and paletted 1-bit and 4-bit formats are not supported.

If freedst is non-zero, the stream will be closed after being written.

Returns
0 if successful or -1 if there was an error.

Definition at line 493 of file SDL_bmp.c.

494{
495 Sint64 fp_offset;
496 int i, pad;
498 Uint8 *bits;
499 SDL_bool save32bit = SDL_FALSE;
500 SDL_bool saveLegacyBMP = SDL_FALSE;
501
502 /* The Win32 BMP file header (14 bytes) */
503 char magic[2] = { 'B', 'M' };
504 Uint32 bfSize;
505 Uint16 bfReserved1;
506 Uint16 bfReserved2;
507 Uint32 bfOffBits;
508
509 /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
510 Uint32 biSize;
511 Sint32 biWidth;
512 Sint32 biHeight;
513 Uint16 biPlanes;
514 Uint16 biBitCount;
515 Uint32 biCompression;
516 Uint32 biSizeImage;
517 Sint32 biXPelsPerMeter;
518 Sint32 biYPelsPerMeter;
519 Uint32 biClrUsed;
520 Uint32 biClrImportant;
521
522 /* The additional header members from the Win32 BITMAPV4HEADER struct (108 bytes in total) */
523 Uint32 bV4RedMask = 0;
524 Uint32 bV4GreenMask = 0;
525 Uint32 bV4BlueMask = 0;
526 Uint32 bV4AlphaMask = 0;
527 Uint32 bV4CSType = 0;
528 Sint32 bV4Endpoints[3 * 3] = {0};
529 Uint32 bV4GammaRed = 0;
530 Uint32 bV4GammaGreen = 0;
531 Uint32 bV4GammaBlue = 0;
532
533 /* Make sure we have somewhere to save */
534 surface = NULL;
535 if (dst) {
536#ifdef SAVE_32BIT_BMP
537 /* We can save alpha information in a 32-bit BMP */
538 if (saveme->format->BitsPerPixel >= 8 && (saveme->format->Amask ||
539 saveme->map->info.flags & SDL_COPY_COLORKEY)) {
540 save32bit = SDL_TRUE;
541 }
542#endif /* SAVE_32BIT_BMP */
543
544 if (saveme->format->palette && !save32bit) {
545 if (saveme->format->BitsPerPixel == 8) {
546 surface = saveme;
547 } else {
548 SDL_SetError("%d bpp BMP files not supported",
549 saveme->format->BitsPerPixel);
550 }
551 } else if ((saveme->format->BitsPerPixel == 24) && !save32bit &&
553 (saveme->format->Rmask == 0x00FF0000) &&
554 (saveme->format->Gmask == 0x0000FF00) &&
555 (saveme->format->Bmask == 0x000000FF)
556#else
557 (saveme->format->Rmask == 0x000000FF) &&
558 (saveme->format->Gmask == 0x0000FF00) &&
559 (saveme->format->Bmask == 0x00FF0000)
560#endif
561 ) {
562 surface = saveme;
563 } else {
565
566 /* If the surface has a colorkey or alpha channel we'll save a
567 32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
568 if (save32bit) {
570 } else {
572 }
573 surface = SDL_ConvertSurface(saveme, &format, 0);
574 if (!surface) {
575 SDL_SetError("Couldn't convert image to %d bpp",
576 format.BitsPerPixel);
577 }
578 }
579 } else {
580 /* Set no error here because it may overwrite a more useful message from
581 SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
582 return -1;
583 }
584
585 if (save32bit) {
587 }
588
589 if (surface && (SDL_LockSurface(surface) == 0)) {
590 const int bw = surface->w * surface->format->BytesPerPixel;
591
592 /* Set the BMP file header values */
593 bfSize = 0; /* We'll write this when we're done */
594 bfReserved1 = 0;
595 bfReserved2 = 0;
596 bfOffBits = 0; /* We'll write this when we're done */
597
598 /* Write the BMP file header values */
599 fp_offset = SDL_RWtell(dst);
601 SDL_RWwrite(dst, magic, 2, 1);
602 SDL_WriteLE32(dst, bfSize);
603 SDL_WriteLE16(dst, bfReserved1);
604 SDL_WriteLE16(dst, bfReserved2);
605 SDL_WriteLE32(dst, bfOffBits);
606
607 /* Set the BMP info values */
608 biSize = 40;
609 biWidth = surface->w;
610 biHeight = surface->h;
611 biPlanes = 1;
612 biBitCount = surface->format->BitsPerPixel;
613 biCompression = BI_RGB;
614 biSizeImage = surface->h * surface->pitch;
615 biXPelsPerMeter = 0;
616 biYPelsPerMeter = 0;
617 if (surface->format->palette) {
618 biClrUsed = surface->format->palette->ncolors;
619 } else {
620 biClrUsed = 0;
621 }
622 biClrImportant = 0;
623
624 /* Set the BMP info values for the version 4 header */
625 if (save32bit && !saveLegacyBMP) {
626 biSize = 108;
627 biCompression = BI_BITFIELDS;
628 /* The BMP format is always little endian, these masks stay the same */
629 bV4RedMask = 0x00ff0000;
630 bV4GreenMask = 0x0000ff00;
631 bV4BlueMask = 0x000000ff;
632 bV4AlphaMask = 0xff000000;
633 bV4CSType = LCS_WINDOWS_COLOR_SPACE;
634 bV4GammaRed = 0;
635 bV4GammaGreen = 0;
636 bV4GammaBlue = 0;
637 }
638
639 /* Write the BMP info values */
640 SDL_WriteLE32(dst, biSize);
641 SDL_WriteLE32(dst, biWidth);
642 SDL_WriteLE32(dst, biHeight);
643 SDL_WriteLE16(dst, biPlanes);
644 SDL_WriteLE16(dst, biBitCount);
645 SDL_WriteLE32(dst, biCompression);
646 SDL_WriteLE32(dst, biSizeImage);
647 SDL_WriteLE32(dst, biXPelsPerMeter);
648 SDL_WriteLE32(dst, biYPelsPerMeter);
649 SDL_WriteLE32(dst, biClrUsed);
650 SDL_WriteLE32(dst, biClrImportant);
651
652 /* Write the BMP info values for the version 4 header */
653 if (save32bit && !saveLegacyBMP) {
654 SDL_WriteLE32(dst, bV4RedMask);
655 SDL_WriteLE32(dst, bV4GreenMask);
656 SDL_WriteLE32(dst, bV4BlueMask);
657 SDL_WriteLE32(dst, bV4AlphaMask);
658 SDL_WriteLE32(dst, bV4CSType);
659 for (i = 0; i < 3 * 3; i++) {
660 SDL_WriteLE32(dst, bV4Endpoints[i]);
661 }
662 SDL_WriteLE32(dst, bV4GammaRed);
663 SDL_WriteLE32(dst, bV4GammaGreen);
664 SDL_WriteLE32(dst, bV4GammaBlue);
665 }
666
667 /* Write the palette (in BGR color order) */
668 if (surface->format->palette) {
670 int ncolors;
671
672 colors = surface->format->palette->colors;
673 ncolors = surface->format->palette->ncolors;
674 for (i = 0; i < ncolors; ++i) {
675 SDL_RWwrite(dst, &colors[i].b, 1, 1);
676 SDL_RWwrite(dst, &colors[i].g, 1, 1);
677 SDL_RWwrite(dst, &colors[i].r, 1, 1);
678 SDL_RWwrite(dst, &colors[i].a, 1, 1);
679 }
680 }
681
682 /* Write the bitmap offset */
683 bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
684 if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
686 }
687 SDL_WriteLE32(dst, bfOffBits);
688 if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
690 }
691
692 /* Write the bitmap image upside down */
693 bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
694 pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
695 while (bits > (Uint8 *) surface->pixels) {
696 bits -= surface->pitch;
697 if (SDL_RWwrite(dst, bits, 1, bw) != bw) {
699 break;
700 }
701 if (pad) {
702 const Uint8 padbyte = 0;
703 for (i = 0; i < pad; ++i) {
704 SDL_RWwrite(dst, &padbyte, 1, 1);
705 }
706 }
707 }
708
709 /* Write the BMP file size */
710 bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
711 if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
713 }
714 SDL_WriteLE32(dst, bfSize);
715 if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) {
717 }
718
719 /* Close it up.. */
721 if (surface != saveme) {
723 }
724 }
725
726 if (freedst && dst) {
728 }
729 return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
730}
#define SDL_COPY_COLORKEY
Definition: SDL_blit.h:39
#define LCS_WINDOWS_COLOR_SPACE
Definition: SDL_bmp.c:54
#define SDL_BYTEORDER
#define SDL_RWwrite
#define SDL_WriteLE16
#define SDL_UnlockSurface
#define SDL_GetHintBoolean
#define SDL_LockSurface
#define SDL_WriteLE32
#define SDL_ConvertSurface
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
@ SDL_EFWRITE
Definition: SDL_error.h:59
#define SDL_HINT_BMP_SAVE_LEGACY_FORMAT
Prevent SDL from using version 4 of the bitmap header when saving BMPs.
Definition: SDL_hints.h:951
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
GLenum GLenum dst
GLboolean GLboolean g
int SDL_InitFormat(SDL_PixelFormat *format, Uint32 pixel_format)
Definition: SDL_pixels.c:537
@ SDL_PIXELFORMAT_BGR24
Definition: SDL_pixels.h:233
@ SDL_PIXELFORMAT_BGRA32
Definition: SDL_pixels.h:273
SDL_BlitInfo info
Definition: SDL_blit.h:92
Uint8 BitsPerPixel
Definition: SDL_pixels.h:319
SDL_Palette * palette
Definition: SDL_pixels.h:318
SDL_PixelFormat * format
Definition: SDL_surface.h:73
struct SDL_BlitMap * map
Definition: SDL_surface.h:89

References SDL_PixelFormat::Amask, BI_BITFIELDS, BI_RGB, SDL_PixelFormat::BitsPerPixel, SDL_PixelFormat::Bmask, colors, SDL_BlitInfo::flags, SDL_Surface::format, SDL_PixelFormat::Gmask, i, SDL_BlitMap::info, LCS_WINDOWS_COLOR_SPACE, SDL_Surface::map, NULL, SDL_PixelFormat::palette, SDL_PixelFormat::Rmask, RW_SEEK_SET, SDL_BYTEORDER, SDL_ClearError, SDL_ConvertSurface, SDL_COPY_COLORKEY, SDL_EFSEEK, SDL_EFWRITE, SDL_Error, SDL_FALSE, SDL_FreeSurface, SDL_GetError, SDL_GetHintBoolean, SDL_HINT_BMP_SAVE_LEGACY_FORMAT, SDL_InitFormat(), SDL_LIL_ENDIAN, SDL_LockSurface, SDL_PIXELFORMAT_BGR24, SDL_PIXELFORMAT_BGRA32, SDL_RWclose, SDL_RWseek, SDL_RWtell, SDL_RWwrite, SDL_SetError, SDL_strcmp, SDL_TRUE, SDL_UnlockSurface, SDL_WriteLE16, and SDL_WriteLE32.