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:1564
GLfloat GLfloat GLfloat alpha
void * pixels
Definition: SDL_surface.h:75
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:143
SDL_bool
Definition: SDL_stdinc.h:130
#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, and SDL_Surface::w.

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

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

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