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.

Referenced by SDL_LoadBMP_RW(), and SDL_SaveBMP_RW().

◆ BI_RGB

#define BI_RGB   0

Definition at line 45 of file SDL_bmp.c.

Referenced by SDL_LoadBMP_RW(), and SDL_SaveBMP_RW().

◆ 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.

Referenced by SDL_SaveBMP_RW().

◆ 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.

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

Referenced by SDL_LoadBMP_RW().

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) {
80  *alpha = SDL_ALPHA_OPAQUE;
81  alpha += 4;
82  }
83  }
84 }
GLuint GLuint end
Definition: SDL_opengl.h:1571
GLfloat GLfloat GLfloat alpha
void * pixels
Definition: SDL_surface.h:76
uint8_t Uint8
Definition: SDL_stdinc.h:179
SDL_bool
Definition: SDL_stdinc.h:161
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:46

◆ 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.

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, void, and SDL_Surface::w.

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);
140  SDL_ClearError();
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) {
335  SDL_Color *colors;
336  int ncolors = biClrUsed;
337  colors =
338  (SDL_Color *) SDL_realloc(palette->colors,
339  ncolors *
340  sizeof(*palette->colors));
341  if (!colors) {
342  SDL_OutOfMemory();
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) {
476  CorrectAlphaChannel(surface);
477  }
478  done:
479  if (was_error) {
480  if (src) {
481  SDL_RWseek(src, fp_offset, RW_SEEK_SET);
482  }
483  SDL_FreeSurface(surface);
484  surface = NULL;
485  }
486  if (freesrc && src) {
487  SDL_RWclose(src);
488  }
489  return (surface);
490 }
#define BI_RGB
Definition: SDL_bmp.c:45
#define SDL_ClearError
#define SDL_GetError
Uint8 g
Definition: SDL_pixels.h:298
GLuint GLuint end
Definition: SDL_opengl.h:1571
EGLSurface surface
Definition: eglext.h:248
A collection of pixels used in software blitting.
Definition: SDL_surface.h:70
#define SDL_RWread
uint16_t Uint16
Definition: SDL_stdinc.h:191
#define SDL_ReadLE32
Uint8 b
Definition: SDL_pixels.h:299
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
#define SDL_realloc
static void CorrectAlphaChannel(SDL_Surface *surface)
Definition: SDL_bmp.c:57
GLdouble GLdouble GLdouble GLdouble top
#define SDL_strncmp
#define SDL_Error
#define SDL_ReadLE16
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
Definition: SDL_endian.h:162
Uint8 r
Definition: SDL_pixels.h:297
void * pixels
Definition: SDL_surface.h:76
#define SDL_FreeSurface
Uint8 a
Definition: SDL_pixels.h:300
uint8_t Uint8
Definition: SDL_stdinc.h:179
int done
Definition: checkkeys.c:28
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
Definition: SDL_endian.h:107
#define SDL_RWseek
int32_t Sint32
Definition: SDL_stdinc.h:197
#define BI_BITFIELDS
Definition: SDL_bmp.c:48
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 SDL_assert(condition)
Definition: SDL_assert.h:169
#define NULL
Definition: begin_code.h:167
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:161
SDL_Color * colors
Definition: SDL_pixels.h:307
SDL_PixelFormat * format
Definition: SDL_surface.h:73
#define SDL_SetError
#define SDL_CreateRGBSurface
#define SDL_RWtell
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
uint32_t Uint32
Definition: SDL_stdinc.h:203
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
#define SDL_RWclose
int64_t Sint64
Definition: SDL_stdinc.h:210
#define SDL_strcmp
#define RW_SEEK_CUR
Definition: SDL_rwops.h:175
static int colors[7]
Definition: testgesture.c:41
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:46

◆ 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.

References SDL_PixelFormat::Amask, BI_BITFIELDS, 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, LCS_WINDOWS_COLOR_SPACE, 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_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, SDL_WriteLE32, and SDL_Surface::w.

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);
600  SDL_ClearError();
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) {
669  SDL_Color *colors;
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.. */
720  SDL_UnlockSurface(surface);
721  if (surface != saveme) {
722  SDL_FreeSurface(surface);
723  }
724  }
725 
726  if (freedst && dst) {
727  SDL_RWclose(dst);
728  }
729  return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
730 }
#define BI_RGB
Definition: SDL_bmp.c:45
#define SDL_ClearError
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
#define SDL_GetError
#define SDL_UnlockSurface
#define SDL_COPY_COLORKEY
Definition: SDL_blit.h:39
#define LCS_WINDOWS_COLOR_SPACE
Definition: SDL_bmp.c:54
Uint8 BytesPerPixel
Definition: SDL_pixels.h:320
#define SDL_ConvertSurface
EGLSurface surface
Definition: eglext.h:248
A collection of pixels used in software blitting.
Definition: SDL_surface.h:70
#define SDL_WriteLE16
uint16_t Uint16
Definition: SDL_stdinc.h:191
#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_GetHintBoolean
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
struct SDL_BlitMap * map
Definition: SDL_surface.h:89
#define SDL_RWwrite
void * pixels
Definition: SDL_surface.h:76
#define SDL_FreeSurface
uint8_t Uint8
Definition: SDL_stdinc.h:179
Uint8 BitsPerPixel
Definition: SDL_pixels.h:319
#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
#define SDL_RWseek
int32_t Sint32
Definition: SDL_stdinc.h:197
int SDL_InitFormat(SDL_PixelFormat *format, Uint32 pixel_format)
Definition: SDL_pixels.c:537
#define BI_BITFIELDS
Definition: SDL_bmp.c:48
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
SDL_bool
Definition: SDL_stdinc.h:161
SDL_Color * colors
Definition: SDL_pixels.h:307
SDL_PixelFormat * format
Definition: SDL_surface.h:73
#define SDL_SetError
#define SDL_LockSurface
#define SDL_RWtell
uint32_t Uint32
Definition: SDL_stdinc.h:203
#define SDL_WriteLE32
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
#define SDL_RWclose
int64_t Sint64
Definition: SDL_stdinc.h:210
SDL_Palette * palette
Definition: SDL_pixels.h:318
#define SDL_strcmp
static int colors[7]
Definition: testgesture.c:41
GLboolean GLboolean GLboolean GLboolean a
GLboolean GLboolean g
GLboolean GLboolean GLboolean b
#define SDL_BYTEORDER
SDL_BlitInfo info
Definition: SDL_blit.h:92