SDL  2.0
SDL_bmp.c File Reference
#include "../SDL_internal.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
 

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

#define BI_BITFIELDS   3

Definition at line 47 of file SDL_bmp.c.

Referenced by SDL_LoadBMP_RW().

#define BI_RGB   0

Definition at line 44 of file SDL_bmp.c.

Referenced by SDL_LoadBMP_RW(), and SDL_SaveBMP_RW().

#define BI_RLE4   2

Definition at line 46 of file SDL_bmp.c.

#define BI_RLE8   1

Definition at line 45 of file SDL_bmp.c.

#define SAVE_32BIT_BMP

Definition at line 40 of file SDL_bmp.c.

Function Documentation

static void CorrectAlphaChannel ( SDL_Surface surface)
static

Definition at line 51 of file SDL_bmp.c.

References SDL_Surface::h, SDL_Surface::pitch, SDL_Surface::pixels, SDL_ALPHA_OPAQUE, SDL_FALSE, and SDL_TRUE.

Referenced by SDL_LoadBMP_RW().

52 {
53  /* Check to see if there is any alpha channel data */
54  SDL_bool hasAlpha = SDL_FALSE;
55 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
56  int alphaChannelOffset = 0;
57 #else
58  int alphaChannelOffset = 3;
59 #endif
60  Uint8 *alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
61  Uint8 *end = alpha + surface->h * surface->pitch;
62 
63  while (alpha < end) {
64  if (*alpha != 0) {
65  hasAlpha = SDL_TRUE;
66  break;
67  }
68  alpha += 4;
69  }
70 
71  if (!hasAlpha) {
72  alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
73  while (alpha < end) {
74  *alpha = SDL_ALPHA_OPAQUE;
75  alpha += 4;
76  }
77  }
78 }
GLuint GLuint end
Definition: SDL_opengl.h:1564
GLfloat GLfloat GLfloat alpha
SDL_bool
Definition: SDL_stdinc.h:126
void * pixels
Definition: SDL_surface.h:75
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:45
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 81 of file SDL_bmp.c.

References SDL_Color::a, SDL_Color::b, BI_BITFIELDS, BI_RGB, colors, SDL_Palette::colors, CorrectAlphaChannel(), done, SDL_Surface::format, SDL_Color::g, SDL_Surface::h, i, SDL_Palette::ncolors, NULL, SDL_Surface::pitch, SDL_Surface::pixels, 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 SDL_Surface::w.

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

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

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 479 of file SDL_bmp.c.

References SDL_PixelFormat::Amask, BI_RGB, SDL_PixelFormat::BitsPerPixel, SDL_PixelFormat::Bmask, SDL_PixelFormat::BytesPerPixel, colors, SDL_Palette::colors, SDL_BlitInfo::flags, SDL_Surface::format, SDL_PixelFormat::Gmask, SDL_Surface::h, i, SDL_BlitMap::info, SDL_Surface::map, SDL_Palette::ncolors, NULL, SDL_PixelFormat::palette, SDL_Surface::pitch, SDL_Surface::pixels, 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_InitFormat(), SDL_LIL_ENDIAN, SDL_LockSurface, SDL_PIXELFORMAT_ARGB8888, SDL_PIXELFORMAT_BGR24, SDL_PIXELFORMAT_BGRA8888, SDL_RWclose, SDL_RWseek, SDL_RWtell, SDL_RWwrite, SDL_SetError, SDL_strcmp, SDL_TRUE, SDL_UnlockSurface, SDL_WriteLE16, SDL_WriteLE32, and SDL_Surface::w.

480 {
481  Sint64 fp_offset;
482  int i, pad;
483  SDL_Surface *surface;
484  Uint8 *bits;
485 
486  /* The Win32 BMP file header (14 bytes) */
487  char magic[2] = { 'B', 'M' };
488  Uint32 bfSize;
489  Uint16 bfReserved1;
490  Uint16 bfReserved2;
491  Uint32 bfOffBits;
492 
493  /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
494  Uint32 biSize;
495  Sint32 biWidth;
496  Sint32 biHeight;
497  Uint16 biPlanes;
498  Uint16 biBitCount;
499  Uint32 biCompression;
500  Uint32 biSizeImage;
501  Sint32 biXPelsPerMeter;
502  Sint32 biYPelsPerMeter;
503  Uint32 biClrUsed;
504  Uint32 biClrImportant;
505 
506  /* Make sure we have somewhere to save */
507  surface = NULL;
508  if (dst) {
509  SDL_bool save32bit = SDL_FALSE;
510 #ifdef SAVE_32BIT_BMP
511  /* We can save alpha information in a 32-bit BMP */
512  if (saveme->map->info.flags & SDL_COPY_COLORKEY ||
513  saveme->format->Amask) {
514  save32bit = SDL_TRUE;
515  }
516 #endif /* SAVE_32BIT_BMP */
517 
518  if (saveme->format->palette && !save32bit) {
519  if (saveme->format->BitsPerPixel == 8) {
520  surface = saveme;
521  } else {
522  SDL_SetError("%d bpp BMP files not supported",
523  saveme->format->BitsPerPixel);
524  }
525  } else if ((saveme->format->BitsPerPixel == 24) &&
527  (saveme->format->Rmask == 0x00FF0000) &&
528  (saveme->format->Gmask == 0x0000FF00) &&
529  (saveme->format->Bmask == 0x000000FF)
530 #else
531  (saveme->format->Rmask == 0x000000FF) &&
532  (saveme->format->Gmask == 0x0000FF00) &&
533  (saveme->format->Bmask == 0x00FF0000)
534 #endif
535  ) {
536  surface = saveme;
537  } else {
539 
540  /* If the surface has a colorkey or alpha channel we'll save a
541  32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
542  if (save32bit) {
543  SDL_InitFormat(&format,
546 #else
548 #endif
549  );
550  } else {
552  }
553  surface = SDL_ConvertSurface(saveme, &format, 0);
554  if (!surface) {
555  SDL_SetError("Couldn't convert image to %d bpp",
556  format.BitsPerPixel);
557  }
558  }
559  } else {
560  /* Set no error here because it may overwrite a more useful message from
561  SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
562  return -1;
563  }
564 
565  if (surface && (SDL_LockSurface(surface) == 0)) {
566  const int bw = surface->w * surface->format->BytesPerPixel;
567 
568  /* Set the BMP file header values */
569  bfSize = 0; /* We'll write this when we're done */
570  bfReserved1 = 0;
571  bfReserved2 = 0;
572  bfOffBits = 0; /* We'll write this when we're done */
573 
574  /* Write the BMP file header values */
575  fp_offset = SDL_RWtell(dst);
576  SDL_ClearError();
577  SDL_RWwrite(dst, magic, 2, 1);
578  SDL_WriteLE32(dst, bfSize);
579  SDL_WriteLE16(dst, bfReserved1);
580  SDL_WriteLE16(dst, bfReserved2);
581  SDL_WriteLE32(dst, bfOffBits);
582 
583  /* Set the BMP info values */
584  biSize = 40;
585  biWidth = surface->w;
586  biHeight = surface->h;
587  biPlanes = 1;
588  biBitCount = surface->format->BitsPerPixel;
589  biCompression = BI_RGB;
590  biSizeImage = surface->h * surface->pitch;
591  biXPelsPerMeter = 0;
592  biYPelsPerMeter = 0;
593  if (surface->format->palette) {
594  biClrUsed = surface->format->palette->ncolors;
595  } else {
596  biClrUsed = 0;
597  }
598  biClrImportant = 0;
599 
600  /* Write the BMP info values */
601  SDL_WriteLE32(dst, biSize);
602  SDL_WriteLE32(dst, biWidth);
603  SDL_WriteLE32(dst, biHeight);
604  SDL_WriteLE16(dst, biPlanes);
605  SDL_WriteLE16(dst, biBitCount);
606  SDL_WriteLE32(dst, biCompression);
607  SDL_WriteLE32(dst, biSizeImage);
608  SDL_WriteLE32(dst, biXPelsPerMeter);
609  SDL_WriteLE32(dst, biYPelsPerMeter);
610  SDL_WriteLE32(dst, biClrUsed);
611  SDL_WriteLE32(dst, biClrImportant);
612 
613  /* Write the palette (in BGR color order) */
614  if (surface->format->palette) {
615  SDL_Color *colors;
616  int ncolors;
617 
618  colors = surface->format->palette->colors;
619  ncolors = surface->format->palette->ncolors;
620  for (i = 0; i < ncolors; ++i) {
621  SDL_RWwrite(dst, &colors[i].b, 1, 1);
622  SDL_RWwrite(dst, &colors[i].g, 1, 1);
623  SDL_RWwrite(dst, &colors[i].r, 1, 1);
624  SDL_RWwrite(dst, &colors[i].a, 1, 1);
625  }
626  }
627 
628  /* Write the bitmap offset */
629  bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
630  if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
632  }
633  SDL_WriteLE32(dst, bfOffBits);
634  if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
636  }
637 
638  /* Write the bitmap image upside down */
639  bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
640  pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
641  while (bits > (Uint8 *) surface->pixels) {
642  bits -= surface->pitch;
643  if (SDL_RWwrite(dst, bits, 1, bw) != bw) {
645  break;
646  }
647  if (pad) {
648  const Uint8 padbyte = 0;
649  for (i = 0; i < pad; ++i) {
650  SDL_RWwrite(dst, &padbyte, 1, 1);
651  }
652  }
653  }
654 
655  /* Write the BMP file size */
656  bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
657  if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
659  }
660  SDL_WriteLE32(dst, bfSize);
661  if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) {
663  }
664 
665  /* Close it up.. */
666  SDL_UnlockSurface(surface);
667  if (surface != saveme) {
668  SDL_FreeSurface(surface);
669  }
670  }
671 
672  if (freedst && dst) {
673  SDL_RWclose(dst);
674  }
675  return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
676 }
#define BI_RGB
Definition: SDL_bmp.c:44
#define SDL_ClearError
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1565
#define SDL_GetError
#define SDL_UnlockSurface
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2072
#define SDL_COPY_COLORKEY
Definition: SDL_blit.h:39
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:157
#define SDL_RWwrite(ctx, ptr, size, n)
Definition: SDL_rwops.h:188
Uint8 BytesPerPixel
Definition: SDL_pixels.h:304
#define SDL_ConvertSurface
A collection of pixels used in software blitting.
Definition: SDL_surface.h:69
#define SDL_WriteLE16
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
#define SDL_Error
#define SDL_RWseek(ctx, offset, whence)
Definition: SDL_rwops.h:185
SDL_bool
Definition: SDL_stdinc.h:126
GLboolean GLboolean g
struct SDL_BlitMap * map
Definition: SDL_surface.h:88
void * pixels
Definition: SDL_surface.h:75
#define SDL_FreeSurface
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
Uint8 BitsPerPixel
Definition: SDL_pixels.h:303
int32_t Sint32
Definition: SDL_stdinc.h:153
int SDL_InitFormat(SDL_PixelFormat *format, Uint32 pixel_format)
Definition: SDL_pixels.c:521
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:42
#define NULL
Definition: begin_code.h:143
SDL_Color * colors
Definition: SDL_pixels.h:291
SDL_PixelFormat * format
Definition: SDL_surface.h:72
#define SDL_RWclose(ctx)
Definition: SDL_rwops.h:189
#define SDL_SetError
#define SDL_LockSurface
#define SDL_WriteLE32
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:147
SDL_Palette * palette
Definition: SDL_pixels.h:302
#define SDL_strcmp
int64_t Sint64
A signed 64-bit integer type.
Definition: SDL_stdinc.h:162
static int colors[7]
Definition: testgesture.c:40
GLboolean GLboolean GLboolean GLboolean a
GLboolean GLboolean GLboolean b
#define SDL_RWtell(ctx)
Definition: SDL_rwops.h:186
#define SDL_BYTEORDER
SDL_BlitInfo info
Definition: SDL_blit.h:91