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:75
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 (biHeight < 0) {
230  topDown = SDL_TRUE;
231  biHeight = -biHeight;
232  } else {
233  topDown = SDL_FALSE;
234  }
235 
236  /* Check for read error */
237  if (SDL_strcmp(SDL_GetError(), "") != 0) {
238  was_error = SDL_TRUE;
239  goto done;
240  }
241 
242  /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
243  switch (biBitCount) {
244  case 1:
245  case 4:
246  ExpandBMP = biBitCount;
247  biBitCount = 8;
248  break;
249  case 2:
250  case 3:
251  case 5:
252  case 6:
253  case 7:
254  SDL_SetError("%d-bpp BMP images are not supported", biBitCount);
255  was_error = SDL_TRUE;
256  goto done;
257  default:
258  ExpandBMP = 0;
259  break;
260  }
261 
262  /* We don't support any BMP compression right now */
263  switch (biCompression) {
264  case BI_RGB:
265  /* If there are no masks, use the defaults */
266  SDL_assert(!haveRGBMasks);
267  SDL_assert(!haveAlphaMask);
268  /* Default values for the BMP format */
269  switch (biBitCount) {
270  case 15:
271  case 16:
272  Rmask = 0x7C00;
273  Gmask = 0x03E0;
274  Bmask = 0x001F;
275  break;
276  case 24:
277 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
278  Rmask = 0x000000FF;
279  Gmask = 0x0000FF00;
280  Bmask = 0x00FF0000;
281 #else
282  Rmask = 0x00FF0000;
283  Gmask = 0x0000FF00;
284  Bmask = 0x000000FF;
285 #endif
286  break;
287  case 32:
288  /* We don't know if this has alpha channel or not */
289  correctAlpha = SDL_TRUE;
290  Amask = 0xFF000000;
291  Rmask = 0x00FF0000;
292  Gmask = 0x0000FF00;
293  Bmask = 0x000000FF;
294  break;
295  default:
296  break;
297  }
298  break;
299 
300  case BI_BITFIELDS:
301  break; /* we handled this in the info header. */
302 
303  default:
304  SDL_SetError("Compressed BMP files not supported");
305  was_error = SDL_TRUE;
306  goto done;
307  }
308 
309  /* Create a compatible surface, note that the colors are RGB ordered */
310  surface =
311  SDL_CreateRGBSurface(0, biWidth, biHeight, biBitCount, Rmask, Gmask,
312  Bmask, Amask);
313  if (surface == NULL) {
314  was_error = SDL_TRUE;
315  goto done;
316  }
317 
318  /* Load the palette, if any */
319  palette = (surface->format)->palette;
320  if (palette) {
321  SDL_assert(biBitCount <= 8);
322  if (biClrUsed == 0) {
323  biClrUsed = 1 << biBitCount;
324  } else if (biClrUsed > (1 << biBitCount)) {
325  SDL_SetError("BMP file has an invalid number of colors");
326  was_error = SDL_TRUE;
327  goto done;
328  }
329  if ((int) biClrUsed > palette->ncolors) {
330  SDL_Color *colors;
331  int ncolors = biClrUsed;
332  colors =
333  (SDL_Color *) SDL_realloc(palette->colors,
334  ncolors *
335  sizeof(*palette->colors));
336  if (!colors) {
337  SDL_OutOfMemory();
338  was_error = SDL_TRUE;
339  goto done;
340  }
341  palette->ncolors = ncolors;
342  palette->colors = colors;
343  } else if ((int) biClrUsed < palette->ncolors) {
344  palette->ncolors = biClrUsed;
345  }
346  if (biSize == 12) {
347  for (i = 0; i < (int) biClrUsed; ++i) {
348  SDL_RWread(src, &palette->colors[i].b, 1, 1);
349  SDL_RWread(src, &palette->colors[i].g, 1, 1);
350  SDL_RWread(src, &palette->colors[i].r, 1, 1);
351  palette->colors[i].a = SDL_ALPHA_OPAQUE;
352  }
353  } else {
354  for (i = 0; i < (int) biClrUsed; ++i) {
355  SDL_RWread(src, &palette->colors[i].b, 1, 1);
356  SDL_RWread(src, &palette->colors[i].g, 1, 1);
357  SDL_RWread(src, &palette->colors[i].r, 1, 1);
358  SDL_RWread(src, &palette->colors[i].a, 1, 1);
359 
360  /* According to Microsoft documentation, the fourth element
361  is reserved and must be zero, so we shouldn't treat it as
362  alpha.
363  */
364  palette->colors[i].a = SDL_ALPHA_OPAQUE;
365  }
366  }
367  }
368 
369  /* Read the surface pixels. Note that the bmp image is upside down */
370  if (SDL_RWseek(src, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
372  was_error = SDL_TRUE;
373  goto done;
374  }
375  top = (Uint8 *)surface->pixels;
376  end = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
377  switch (ExpandBMP) {
378  case 1:
379  bmpPitch = (biWidth + 7) >> 3;
380  pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
381  break;
382  case 4:
383  bmpPitch = (biWidth + 1) >> 1;
384  pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
385  break;
386  default:
387  pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
388  break;
389  }
390  if (topDown) {
391  bits = top;
392  } else {
393  bits = end - surface->pitch;
394  }
395  while (bits >= top && bits < end) {
396  switch (ExpandBMP) {
397  case 1:
398  case 4:{
399  Uint8 pixel = 0;
400  int shift = (8 - ExpandBMP);
401  for (i = 0; i < surface->w; ++i) {
402  if (i % (8 / ExpandBMP) == 0) {
403  if (!SDL_RWread(src, &pixel, 1, 1)) {
404  SDL_SetError("Error reading from BMP");
405  was_error = SDL_TRUE;
406  goto done;
407  }
408  }
409  bits[i] = (pixel >> shift);
410  if (bits[i] >= biClrUsed) {
411  SDL_SetError("A BMP image contains a pixel with a color out of the palette");
412  was_error = SDL_TRUE;
413  goto done;
414  }
415  pixel <<= ExpandBMP;
416  }
417  }
418  break;
419 
420  default:
421  if (SDL_RWread(src, bits, 1, surface->pitch) != surface->pitch) {
423  was_error = SDL_TRUE;
424  goto done;
425  }
426  if (biBitCount == 8 && palette && biClrUsed < (1 << biBitCount)) {
427  for (i = 0; i < surface->w; ++i) {
428  if (bits[i] >= biClrUsed) {
429  SDL_SetError("A BMP image contains a pixel with a color out of the palette");
430  was_error = SDL_TRUE;
431  goto done;
432  }
433  }
434  }
435 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
436  /* Byte-swap the pixels if needed. Note that the 24bpp
437  case has already been taken care of above. */
438  switch (biBitCount) {
439  case 15:
440  case 16:{
441  Uint16 *pix = (Uint16 *) bits;
442  for (i = 0; i < surface->w; i++)
443  pix[i] = SDL_Swap16(pix[i]);
444  break;
445  }
446 
447  case 32:{
448  Uint32 *pix = (Uint32 *) bits;
449  for (i = 0; i < surface->w; i++)
450  pix[i] = SDL_Swap32(pix[i]);
451  break;
452  }
453  }
454 #endif
455  break;
456  }
457  /* Skip padding bytes, ugh */
458  if (pad) {
459  Uint8 padbyte;
460  for (i = 0; i < pad; ++i) {
461  SDL_RWread(src, &padbyte, 1, 1);
462  }
463  }
464  if (topDown) {
465  bits += surface->pitch;
466  } else {
467  bits -= surface->pitch;
468  }
469  }
470  if (correctAlpha) {
471  CorrectAlphaChannel(surface);
472  }
473  done:
474  if (was_error) {
475  if (src) {
476  SDL_RWseek(src, fp_offset, RW_SEEK_SET);
477  }
478  SDL_FreeSurface(surface);
479  surface = NULL;
480  }
481  if (freesrc && src) {
482  SDL_RWclose(src);
483  }
484  return (surface);
485 }
#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:69
uint16_t Uint16
Definition: SDL_stdinc.h:191
#define SDL_ReadLE32
#define SDL_RWread(ctx, ptr, size, n)
Definition: SDL_rwops.h:187
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_RWseek(ctx, offset, whence)
Definition: SDL_rwops.h:185
#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:75
#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
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:164
#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:72
#define SDL_RWclose(ctx)
Definition: SDL_rwops.h:189
#define SDL_SetError
#define SDL_CreateRGBSurface
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_strcmp
#define RW_SEEK_CUR
Definition: SDL_rwops.h:175
int64_t Sint64
Definition: SDL_stdinc.h:210
static int colors[7]
Definition: testgesture.c:39
#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 488 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.

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