SDL  2.0
SDL_bmp.c File Reference
#include "../SDL_internal.h"
#include "SDL_hints.h"
#include "SDL_video.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
 
#define COPY_PIXEL(x)   spot = &bits[ofs++]; if(spot >= start && spot < end) *spot = (x)
 

Functions

static int readRlePixels (SDL_Surface *surface, SDL_RWops *src, int isRle8)
 
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 47 of file SDL_bmp.c.

◆ BI_RGB

#define BI_RGB   0

Definition at line 44 of file SDL_bmp.c.

◆ BI_RLE4

#define BI_RLE4   2

Definition at line 46 of file SDL_bmp.c.

◆ BI_RLE8

#define BI_RLE8   1

Definition at line 45 of file SDL_bmp.c.

◆ COPY_PIXEL

#define COPY_PIXEL (   x)    spot = &bits[ofs++]; if(spot >= start && spot < end) *spot = (x)

◆ LCS_WINDOWS_COLOR_SPACE

#define LCS_WINDOWS_COLOR_SPACE   0x57696E20

Definition at line 53 of file SDL_bmp.c.

◆ SAVE_32BIT_BMP

#define SAVE_32BIT_BMP

Definition at line 40 of file SDL_bmp.c.

Function Documentation

◆ CorrectAlphaChannel()

static void CorrectAlphaChannel ( SDL_Surface surface)
static

Definition at line 142 of file SDL_bmp.c.

143 {
144  /* Check to see if there is any alpha channel data */
145  SDL_bool hasAlpha = SDL_FALSE;
146 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
147  int alphaChannelOffset = 0;
148 #else
149  int alphaChannelOffset = 3;
150 #endif
151  Uint8 *alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
152  Uint8 *end = alpha + surface->h * surface->pitch;
153 
154  while (alpha < end) {
155  if (*alpha != 0) {
156  hasAlpha = SDL_TRUE;
157  break;
158  }
159  alpha += 4;
160  }
161 
162  if (!hasAlpha) {
163  alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
164  while (alpha < end) {
166  alpha += 4;
167  }
168  }
169 }
GLuint GLuint end
Definition: SDL_opengl.h:1571
GLfloat GLfloat GLfloat alpha
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:46
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
uint8_t Uint8
Definition: SDL_stdinc.h:185
EGLSurface surface
Definition: eglext.h:248

References SDL_ALPHA_OPAQUE, SDL_FALSE, and SDL_TRUE.

Referenced by SDL_LoadBMP_RW().

◆ readRlePixels()

static int readRlePixels ( SDL_Surface surface,
SDL_RWops src,
int  isRle8 
)
static

Definition at line 56 of file SDL_bmp.c.

57 {
58  /*
59  | Sets the surface pixels from src. A bmp image is upside down.
60  */
61  int pitch = surface->pitch;
62  int height = surface->h;
63  Uint8 *start = (Uint8 *)surface->pixels;
64  Uint8 *end = start + (height*pitch);
65  Uint8 *bits = end-pitch, *spot;
66  int ofs = 0;
67  Uint8 ch;
68  Uint8 needsPad;
69 
70 #define COPY_PIXEL(x) spot = &bits[ofs++]; if(spot >= start && spot < end) *spot = (x)
71 
72  for (;;) {
73  if (!SDL_RWread(src, &ch, 1, 1)) return 1;
74  /*
75  | encoded mode starts with a run length, and then a byte
76  | with two colour indexes to alternate between for the run
77  */
78  if (ch) {
79  Uint8 pixel;
80  if (!SDL_RWread(src, &pixel, 1, 1)) return 1;
81  if (isRle8) { /* 256-color bitmap, compressed */
82  do {
83  COPY_PIXEL(pixel);
84  } while (--ch);
85  } else { /* 16-color bitmap, compressed */
86  Uint8 pixel0 = pixel >> 4;
87  Uint8 pixel1 = pixel & 0x0F;
88  for (;;) {
89  COPY_PIXEL(pixel0); /* even count, high nibble */
90  if (!--ch) break;
91  COPY_PIXEL(pixel1); /* odd count, low nibble */
92  if (!--ch) break;
93  }
94  }
95  } else {
96  /*
97  | A leading zero is an escape; it may signal the end of the bitmap,
98  | a cursor move, or some absolute data.
99  | zero tag may be absolute mode or an escape
100  */
101  if (!SDL_RWread(src, &ch, 1, 1)) return 1;
102  switch (ch) {
103  case 0: /* end of line */
104  ofs = 0;
105  bits -= pitch; /* go to previous */
106  break;
107  case 1: /* end of bitmap */
108  return 0; /* success! */
109  case 2: /* delta */
110  if (!SDL_RWread(src, &ch, 1, 1)) return 1;
111  ofs += ch;
112  if (!SDL_RWread(src, &ch, 1, 1)) return 1;
113  bits -= (ch * pitch);
114  break;
115  default: /* no compression */
116  if (isRle8) {
117  needsPad = (ch & 1);
118  do {
119  Uint8 pixel;
120  if (!SDL_RWread(src, &pixel, 1, 1)) return 1;
121  COPY_PIXEL(pixel);
122  } while (--ch);
123  } else {
124  needsPad = (((ch+1)>>1) & 1); /* (ch+1)>>1: bytes size */
125  for (;;) {
126  Uint8 pixel;
127  if (!SDL_RWread(src, &pixel, 1, 1)) return 1;
128  COPY_PIXEL(pixel >> 4);
129  if (!--ch) break;
130  COPY_PIXEL(pixel & 0x0F);
131  if (!--ch) break;
132  }
133  }
134  /* pad at even boundary */
135  if (needsPad && !SDL_RWread(src, &ch, 1, 1)) return 1;
136  break;
137  }
138  }
139  }
140 }
#define COPY_PIXEL(x)
#define SDL_RWread
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
GLuint start
Definition: SDL_opengl.h:1571
GLenum src
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits

References COPY_PIXEL, and SDL_RWread.

Referenced by SDL_LoadBMP_RW().

◆ SDL_LoadBMP_RW()

SDL_Surface* SDL_LoadBMP_RW ( SDL_RWops src,
int  freesrc 
)

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

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

The new surface should be freed with SDL_FreeSurface().

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

Definition at line 172 of file SDL_bmp.c.

173 {
174  SDL_bool was_error;
175  Sint64 fp_offset = 0;
176  int bmpPitch;
177  int i, pad;
179  Uint32 Rmask = 0;
180  Uint32 Gmask = 0;
181  Uint32 Bmask = 0;
182  Uint32 Amask = 0;
183  SDL_Palette *palette;
184  Uint8 *bits;
185  Uint8 *top, *end;
186  SDL_bool topDown;
187  int ExpandBMP;
188  SDL_bool haveRGBMasks = SDL_FALSE;
189  SDL_bool haveAlphaMask = SDL_FALSE;
190  SDL_bool correctAlpha = SDL_FALSE;
191 
192  /* The Win32 BMP file header (14 bytes) */
193  char magic[2];
194  /* Uint32 bfSize; */
195  /* Uint16 bfReserved1; */
196  /* Uint16 bfReserved2; */
197  Uint32 bfOffBits;
198 
199  /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
200  Uint32 biSize;
201  Sint32 biWidth = 0;
202  Sint32 biHeight = 0;
203  /* Uint16 biPlanes; */
204  Uint16 biBitCount = 0;
205  Uint32 biCompression = 0;
206  /* Uint32 biSizeImage; */
207  /* Sint32 biXPelsPerMeter; */
208  /* Sint32 biYPelsPerMeter; */
209  Uint32 biClrUsed = 0;
210  /* Uint32 biClrImportant; */
211 
212  /* Make sure we are passed a valid data source */
213  surface = NULL;
214  was_error = SDL_FALSE;
215  if (src == NULL) {
216  was_error = SDL_TRUE;
217  goto done;
218  }
219 
220  /* Read in the BMP file header */
221  fp_offset = SDL_RWtell(src);
222  SDL_ClearError();
223  if (SDL_RWread(src, magic, 1, 2) != 2) {
225  was_error = SDL_TRUE;
226  goto done;
227  }
228  if (SDL_strncmp(magic, "BM", 2) != 0) {
229  SDL_SetError("File is not a Windows BMP file");
230  was_error = SDL_TRUE;
231  goto done;
232  }
233  /* bfSize = */ SDL_ReadLE32(src);
234  /* bfReserved1 = */ SDL_ReadLE16(src);
235  /* bfReserved2 = */ SDL_ReadLE16(src);
236  bfOffBits = SDL_ReadLE32(src);
237 
238  /* Read the Win32 BITMAPINFOHEADER */
239  biSize = SDL_ReadLE32(src);
240  if (biSize == 12) { /* really old BITMAPCOREHEADER */
241  biWidth = (Uint32) SDL_ReadLE16(src);
242  biHeight = (Uint32) SDL_ReadLE16(src);
243  /* biPlanes = */ SDL_ReadLE16(src);
244  biBitCount = SDL_ReadLE16(src);
245  biCompression = BI_RGB;
246  /* biSizeImage = 0; */
247  /* biXPelsPerMeter = 0; */
248  /* biYPelsPerMeter = 0; */
249  biClrUsed = 0;
250  /* biClrImportant = 0; */
251  } else if (biSize >= 40) { /* some version of BITMAPINFOHEADER */
252  Uint32 headerSize;
253  biWidth = SDL_ReadLE32(src);
254  biHeight = SDL_ReadLE32(src);
255  /* biPlanes = */ SDL_ReadLE16(src);
256  biBitCount = SDL_ReadLE16(src);
257  biCompression = SDL_ReadLE32(src);
258  /* biSizeImage = */ SDL_ReadLE32(src);
259  /* biXPelsPerMeter = */ SDL_ReadLE32(src);
260  /* biYPelsPerMeter = */ SDL_ReadLE32(src);
261  biClrUsed = SDL_ReadLE32(src);
262  /* biClrImportant = */ SDL_ReadLE32(src);
263 
264  /* 64 == BITMAPCOREHEADER2, an incompatible OS/2 2.x extension. Skip this stuff for now. */
265  if (biSize != 64) {
266  /* This is complicated. If compression is BI_BITFIELDS, then
267  we have 3 DWORDS that specify the RGB masks. This is either
268  stored here in an BITMAPV2INFOHEADER (which only differs in
269  that it adds these RGB masks) and biSize >= 52, or we've got
270  these masks stored in the exact same place, but strictly
271  speaking, this is the bmiColors field in BITMAPINFO immediately
272  following the legacy v1 info header, just past biSize. */
273  if (biCompression == BI_BITFIELDS) {
274  haveRGBMasks = SDL_TRUE;
275  Rmask = SDL_ReadLE32(src);
276  Gmask = SDL_ReadLE32(src);
277  Bmask = SDL_ReadLE32(src);
278 
279  /* ...v3 adds an alpha mask. */
280  if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
281  haveAlphaMask = SDL_TRUE;
282  Amask = SDL_ReadLE32(src);
283  }
284  } else {
285  /* the mask fields are ignored for v2+ headers if not BI_BITFIELD. */
286  if (biSize >= 52) { /* BITMAPV2INFOHEADER; adds RGB masks */
287  /*Rmask = */ SDL_ReadLE32(src);
288  /*Gmask = */ SDL_ReadLE32(src);
289  /*Bmask = */ SDL_ReadLE32(src);
290  }
291  if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
292  /*Amask = */ SDL_ReadLE32(src);
293  }
294  }
295 
296  /* Insert other fields here; Wikipedia and MSDN say we're up to
297  v5 of this header, but we ignore those for now (they add gamma,
298  color spaces, etc). Ignoring the weird OS/2 2.x format, we
299  currently parse up to v3 correctly (hopefully!). */
300  }
301 
302  /* skip any header bytes we didn't handle... */
303  headerSize = (Uint32) (SDL_RWtell(src) - (fp_offset + 14));
304  if (biSize > headerSize) {
305  SDL_RWseek(src, (biSize - headerSize), RW_SEEK_CUR);
306  }
307  }
308  if (biWidth <= 0 || biHeight == 0) {
309  SDL_SetError("BMP file with bad dimensions (%dx%d)", biWidth, biHeight);
310  was_error = SDL_TRUE;
311  goto done;
312  }
313  if (biHeight < 0) {
314  topDown = SDL_TRUE;
315  biHeight = -biHeight;
316  } else {
317  topDown = SDL_FALSE;
318  }
319 
320  /* Check for read error */
321  if (SDL_strcmp(SDL_GetError(), "") != 0) {
322  was_error = SDL_TRUE;
323  goto done;
324  }
325 
326  /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
327  switch (biBitCount) {
328  case 1:
329  case 4:
330  ExpandBMP = biBitCount;
331  biBitCount = 8;
332  break;
333  case 0:
334  case 2:
335  case 3:
336  case 5:
337  case 6:
338  case 7:
339  SDL_SetError("%d-bpp BMP images are not supported", biBitCount);
340  was_error = SDL_TRUE;
341  goto done;
342  default:
343  ExpandBMP = 0;
344  break;
345  }
346 
347  /* RLE4 and RLE8 BMP compression is supported */
348  switch (biCompression) {
349  case BI_RGB:
350  /* If there are no masks, use the defaults */
351  SDL_assert(!haveRGBMasks);
352  SDL_assert(!haveAlphaMask);
353  /* Default values for the BMP format */
354  switch (biBitCount) {
355  case 15:
356  case 16:
357  Rmask = 0x7C00;
358  Gmask = 0x03E0;
359  Bmask = 0x001F;
360  break;
361  case 24:
362 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
363  Rmask = 0x000000FF;
364  Gmask = 0x0000FF00;
365  Bmask = 0x00FF0000;
366 #else
367  Rmask = 0x00FF0000;
368  Gmask = 0x0000FF00;
369  Bmask = 0x000000FF;
370 #endif
371  break;
372  case 32:
373  /* We don't know if this has alpha channel or not */
374  correctAlpha = SDL_TRUE;
375  Amask = 0xFF000000;
376  Rmask = 0x00FF0000;
377  Gmask = 0x0000FF00;
378  Bmask = 0x000000FF;
379  break;
380  default:
381  break;
382  }
383  break;
384 
385  case BI_BITFIELDS:
386  break; /* we handled this in the info header. */
387 
388  default:
389  break;
390  }
391 
392  /* Create a compatible surface, note that the colors are RGB ordered */
393  surface =
394  SDL_CreateRGBSurface(0, biWidth, biHeight, biBitCount, Rmask, Gmask,
395  Bmask, Amask);
396  if (surface == NULL) {
397  was_error = SDL_TRUE;
398  goto done;
399  }
400 
401  /* Load the palette, if any */
402  palette = (surface->format)->palette;
403  if (palette) {
404  if (SDL_RWseek(src, fp_offset+14+biSize, RW_SEEK_SET) < 0) {
406  was_error = SDL_TRUE;
407  goto done;
408  }
409 
410  /*
411  | guich: always use 1<<bpp b/c some bitmaps can bring wrong information
412  | for colorsUsed
413  */
414  /* if (biClrUsed == 0) { */
415  biClrUsed = 1 << biBitCount;
416  /* } */
417  if (biSize == 12) {
418  for (i = 0; i < (int) biClrUsed; ++i) {
419  SDL_RWread(src, &palette->colors[i].b, 1, 1);
420  SDL_RWread(src, &palette->colors[i].g, 1, 1);
421  SDL_RWread(src, &palette->colors[i].r, 1, 1);
422  palette->colors[i].a = SDL_ALPHA_OPAQUE;
423  }
424  } else {
425  for (i = 0; i < (int) biClrUsed; ++i) {
426  SDL_RWread(src, &palette->colors[i].b, 1, 1);
427  SDL_RWread(src, &palette->colors[i].g, 1, 1);
428  SDL_RWread(src, &palette->colors[i].r, 1, 1);
429  SDL_RWread(src, &palette->colors[i].a, 1, 1);
430 
431  /* According to Microsoft documentation, the fourth element
432  is reserved and must be zero, so we shouldn't treat it as
433  alpha.
434  */
435  palette->colors[i].a = SDL_ALPHA_OPAQUE;
436  }
437  }
438  palette->ncolors = biClrUsed;
439  }
440 
441  /* Read the surface pixels. Note that the bmp image is upside down */
442  if (SDL_RWseek(src, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
444  was_error = SDL_TRUE;
445  goto done;
446  }
447  if ((biCompression == BI_RLE4) || (biCompression == BI_RLE8)) {
448  was_error = (SDL_bool)readRlePixels(surface, src, biCompression == BI_RLE8);
449  if (was_error) SDL_SetError("Error reading from BMP");
450  goto done;
451  }
452  top = (Uint8 *)surface->pixels;
453  end = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
454  switch (ExpandBMP) {
455  case 1:
456  bmpPitch = (biWidth + 7) >> 3;
457  pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
458  break;
459  case 4:
460  bmpPitch = (biWidth + 1) >> 1;
461  pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
462  break;
463  default:
464  pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
465  break;
466  }
467  if (topDown) {
468  bits = top;
469  } else {
470  bits = end - surface->pitch;
471  }
472  while (bits >= top && bits < end) {
473  switch (ExpandBMP) {
474  case 1:
475  case 4:{
476  Uint8 pixel = 0;
477  int shift = (8 - ExpandBMP);
478  for (i = 0; i < surface->w; ++i) {
479  if (i % (8 / ExpandBMP) == 0) {
480  if (!SDL_RWread(src, &pixel, 1, 1)) {
481  SDL_SetError("Error reading from BMP");
482  was_error = SDL_TRUE;
483  goto done;
484  }
485  }
486  bits[i] = (pixel >> shift);
487  if (bits[i] >= biClrUsed) {
488  SDL_SetError("A BMP image contains a pixel with a color out of the palette");
489  was_error = SDL_TRUE;
490  goto done;
491  }
492  pixel <<= ExpandBMP;
493  }
494  }
495  break;
496 
497  default:
498  if (SDL_RWread(src, bits, 1, surface->pitch) != surface->pitch) {
500  was_error = SDL_TRUE;
501  goto done;
502  }
503  if (biBitCount == 8 && palette && biClrUsed < (1u << biBitCount)) {
504  for (i = 0; i < surface->w; ++i) {
505  if (bits[i] >= biClrUsed) {
506  SDL_SetError("A BMP image contains a pixel with a color out of the palette");
507  was_error = SDL_TRUE;
508  goto done;
509  }
510  }
511  }
512 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
513  /* Byte-swap the pixels if needed. Note that the 24bpp
514  case has already been taken care of above. */
515  switch (biBitCount) {
516  case 15:
517  case 16:{
518  Uint16 *pix = (Uint16 *) bits;
519  for (i = 0; i < surface->w; i++)
520  pix[i] = SDL_Swap16(pix[i]);
521  break;
522  }
523 
524  case 32:{
525  Uint32 *pix = (Uint32 *) bits;
526  for (i = 0; i < surface->w; i++)
527  pix[i] = SDL_Swap32(pix[i]);
528  break;
529  }
530  }
531 #endif
532  break;
533  }
534  /* Skip padding bytes, ugh */
535  if (pad) {
536  Uint8 padbyte;
537  for (i = 0; i < pad; ++i) {
538  SDL_RWread(src, &padbyte, 1, 1);
539  }
540  }
541  if (topDown) {
542  bits += surface->pitch;
543  } else {
544  bits -= surface->pitch;
545  }
546  }
547  if (correctAlpha) {
549  }
550  done:
551  if (was_error) {
552  if (src) {
553  SDL_RWseek(src, fp_offset, RW_SEEK_SET);
554  }
555  if (surface) {
557  }
558  surface = NULL;
559  }
560  if (freesrc && src) {
561  SDL_RWclose(src);
562  }
563  return (surface);
564 }
#define SDL_assert(condition)
Definition: SDL_assert.h:171
#define BI_RLE4
Definition: SDL_bmp.c:46
#define BI_BITFIELDS
Definition: SDL_bmp.c:47
#define BI_RGB
Definition: SDL_bmp.c:44
static void CorrectAlphaChannel(SDL_Surface *surface)
Definition: SDL_bmp.c:142
#define BI_RLE8
Definition: SDL_bmp.c:45
static int readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
Definition: SDL_bmp.c:56
#define SDL_SetError
#define SDL_GetError
#define SDL_ReadLE16
#define SDL_strncmp
#define SDL_ReadLE32
#define SDL_Error
#define SDL_RWtell
#define SDL_RWseek
#define SDL_ClearError
#define SDL_strcmp
#define SDL_CreateRGBSurface
#define SDL_FreeSurface
#define SDL_RWclose
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
Definition: SDL_endian.h:165
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
Definition: SDL_endian.h:110
@ SDL_EFSEEK
Definition: SDL_error.h:96
@ SDL_EFREAD
Definition: SDL_error.h:94
GLdouble GLdouble GLdouble GLdouble top
#define RW_SEEK_CUR
Definition: SDL_rwops.h:167
#define RW_SEEK_SET
Definition: SDL_rwops.h:166
uint16_t Uint16
Definition: SDL_stdinc.h:197
int32_t Sint32
Definition: SDL_stdinc.h:203
uint32_t Uint32
Definition: SDL_stdinc.h:209
int64_t Sint64
Definition: SDL_stdinc.h:216
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:163
int done
Definition: checkkeys.c:28
Uint8 r
Definition: SDL_pixels.h:306
Uint8 b
Definition: SDL_pixels.h:308
Uint8 a
Definition: SDL_pixels.h:309
Uint8 g
Definition: SDL_pixels.h:307
SDL_Color * colors
Definition: SDL_pixels.h:316
A collection of pixels used in software blitting.
Definition: SDL_surface.h:71
typedef int(__stdcall *FARPROC)()

References SDL_Color::a, SDL_Color::b, BI_BITFIELDS, BI_RGB, BI_RLE4, BI_RLE8, SDL_Palette::colors, CorrectAlphaChannel(), done, SDL_Color::g, i, int(), SDL_Palette::ncolors, NULL, SDL_Color::r, readRlePixels(), 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_ReadLE16, SDL_ReadLE32, SDL_RWclose, SDL_RWread, SDL_RWseek, SDL_RWtell, SDL_SetError, SDL_strcmp, SDL_strncmp, SDL_Swap16(), SDL_Swap32(), and SDL_TRUE.

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

568 {
569  Sint64 fp_offset;
570  int i, pad;
572  Uint8 *bits;
573  SDL_bool save32bit = SDL_FALSE;
574  SDL_bool saveLegacyBMP = SDL_FALSE;
575 
576  /* The Win32 BMP file header (14 bytes) */
577  char magic[2] = { 'B', 'M' };
578  Uint32 bfSize;
579  Uint16 bfReserved1;
580  Uint16 bfReserved2;
581  Uint32 bfOffBits;
582 
583  /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
584  Uint32 biSize;
585  Sint32 biWidth;
586  Sint32 biHeight;
587  Uint16 biPlanes;
588  Uint16 biBitCount;
589  Uint32 biCompression;
590  Uint32 biSizeImage;
591  Sint32 biXPelsPerMeter;
592  Sint32 biYPelsPerMeter;
593  Uint32 biClrUsed;
594  Uint32 biClrImportant;
595 
596  /* The additional header members from the Win32 BITMAPV4HEADER struct (108 bytes in total) */
597  Uint32 bV4RedMask = 0;
598  Uint32 bV4GreenMask = 0;
599  Uint32 bV4BlueMask = 0;
600  Uint32 bV4AlphaMask = 0;
601  Uint32 bV4CSType = 0;
602  Sint32 bV4Endpoints[3 * 3] = {0};
603  Uint32 bV4GammaRed = 0;
604  Uint32 bV4GammaGreen = 0;
605  Uint32 bV4GammaBlue = 0;
606 
607  /* Make sure we have somewhere to save */
608  surface = NULL;
609  if (dst) {
610 #ifdef SAVE_32BIT_BMP
611  /* We can save alpha information in a 32-bit BMP */
612  if (saveme->format->BitsPerPixel >= 8 && (saveme->format->Amask ||
613  saveme->map->info.flags & SDL_COPY_COLORKEY)) {
614  save32bit = SDL_TRUE;
615  }
616 #endif /* SAVE_32BIT_BMP */
617 
618  if (saveme->format->palette && !save32bit) {
619  if (saveme->format->BitsPerPixel == 8) {
620  surface = saveme;
621  } else {
622  SDL_SetError("%d bpp BMP files not supported",
623  saveme->format->BitsPerPixel);
624  }
625  } else if ((saveme->format->BitsPerPixel == 24) && !save32bit &&
627  (saveme->format->Rmask == 0x00FF0000) &&
628  (saveme->format->Gmask == 0x0000FF00) &&
629  (saveme->format->Bmask == 0x000000FF)
630 #else
631  (saveme->format->Rmask == 0x000000FF) &&
632  (saveme->format->Gmask == 0x0000FF00) &&
633  (saveme->format->Bmask == 0x00FF0000)
634 #endif
635  ) {
636  surface = saveme;
637  } else {
639 
640  /* If the surface has a colorkey or alpha channel we'll save a
641  32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
642  if (save32bit) {
644  } else {
646  }
647  surface = SDL_ConvertSurface(saveme, &format, 0);
648  if (!surface) {
649  SDL_SetError("Couldn't convert image to %d bpp",
650  format.BitsPerPixel);
651  }
652  }
653  } else {
654  /* Set no error here because it may overwrite a more useful message from
655  SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
656  return -1;
657  }
658 
659  if (save32bit) {
661  }
662 
663  if (surface && (SDL_LockSurface(surface) == 0)) {
664  const int bw = surface->w * surface->format->BytesPerPixel;
665 
666  /* Set the BMP file header values */
667  bfSize = 0; /* We'll write this when we're done */
668  bfReserved1 = 0;
669  bfReserved2 = 0;
670  bfOffBits = 0; /* We'll write this when we're done */
671 
672  /* Write the BMP file header values */
673  fp_offset = SDL_RWtell(dst);
674  SDL_ClearError();
675  SDL_RWwrite(dst, magic, 2, 1);
676  SDL_WriteLE32(dst, bfSize);
677  SDL_WriteLE16(dst, bfReserved1);
678  SDL_WriteLE16(dst, bfReserved2);
679  SDL_WriteLE32(dst, bfOffBits);
680 
681  /* Set the BMP info values */
682  biSize = 40;
683  biWidth = surface->w;
684  biHeight = surface->h;
685  biPlanes = 1;
686  biBitCount = surface->format->BitsPerPixel;
687  biCompression = BI_RGB;
688  biSizeImage = surface->h * surface->pitch;
689  biXPelsPerMeter = 0;
690  biYPelsPerMeter = 0;
691  if (surface->format->palette) {
692  biClrUsed = surface->format->palette->ncolors;
693  } else {
694  biClrUsed = 0;
695  }
696  biClrImportant = 0;
697 
698  /* Set the BMP info values for the version 4 header */
699  if (save32bit && !saveLegacyBMP) {
700  biSize = 108;
701  biCompression = BI_BITFIELDS;
702  /* The BMP format is always little endian, these masks stay the same */
703  bV4RedMask = 0x00ff0000;
704  bV4GreenMask = 0x0000ff00;
705  bV4BlueMask = 0x000000ff;
706  bV4AlphaMask = 0xff000000;
707  bV4CSType = LCS_WINDOWS_COLOR_SPACE;
708  bV4GammaRed = 0;
709  bV4GammaGreen = 0;
710  bV4GammaBlue = 0;
711  }
712 
713  /* Write the BMP info values */
714  SDL_WriteLE32(dst, biSize);
715  SDL_WriteLE32(dst, biWidth);
716  SDL_WriteLE32(dst, biHeight);
717  SDL_WriteLE16(dst, biPlanes);
718  SDL_WriteLE16(dst, biBitCount);
719  SDL_WriteLE32(dst, biCompression);
720  SDL_WriteLE32(dst, biSizeImage);
721  SDL_WriteLE32(dst, biXPelsPerMeter);
722  SDL_WriteLE32(dst, biYPelsPerMeter);
723  SDL_WriteLE32(dst, biClrUsed);
724  SDL_WriteLE32(dst, biClrImportant);
725 
726  /* Write the BMP info values for the version 4 header */
727  if (save32bit && !saveLegacyBMP) {
728  SDL_WriteLE32(dst, bV4RedMask);
729  SDL_WriteLE32(dst, bV4GreenMask);
730  SDL_WriteLE32(dst, bV4BlueMask);
731  SDL_WriteLE32(dst, bV4AlphaMask);
732  SDL_WriteLE32(dst, bV4CSType);
733  for (i = 0; i < 3 * 3; i++) {
734  SDL_WriteLE32(dst, bV4Endpoints[i]);
735  }
736  SDL_WriteLE32(dst, bV4GammaRed);
737  SDL_WriteLE32(dst, bV4GammaGreen);
738  SDL_WriteLE32(dst, bV4GammaBlue);
739  }
740 
741  /* Write the palette (in BGR color order) */
742  if (surface->format->palette) {
743  SDL_Color *colors;
744  int ncolors;
745 
746  colors = surface->format->palette->colors;
747  ncolors = surface->format->palette->ncolors;
748  for (i = 0; i < ncolors; ++i) {
749  SDL_RWwrite(dst, &colors[i].b, 1, 1);
750  SDL_RWwrite(dst, &colors[i].g, 1, 1);
751  SDL_RWwrite(dst, &colors[i].r, 1, 1);
752  SDL_RWwrite(dst, &colors[i].a, 1, 1);
753  }
754  }
755 
756  /* Write the bitmap offset */
757  bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
758  if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
760  }
761  SDL_WriteLE32(dst, bfOffBits);
762  if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
764  }
765 
766  /* Write the bitmap image upside down */
767  bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
768  pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
769  while (bits > (Uint8 *) surface->pixels) {
770  bits -= surface->pitch;
771  if (SDL_RWwrite(dst, bits, 1, bw) != bw) {
773  break;
774  }
775  if (pad) {
776  const Uint8 padbyte = 0;
777  for (i = 0; i < pad; ++i) {
778  SDL_RWwrite(dst, &padbyte, 1, 1);
779  }
780  }
781  }
782 
783  /* Write the BMP file size */
784  bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
785  if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
787  }
788  SDL_WriteLE32(dst, bfSize);
789  if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) {
791  }
792 
793  /* Close it up.. */
795  if (surface != saveme) {
797  }
798  }
799 
800  if (freedst && dst) {
801  SDL_RWclose(dst);
802  }
803  return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
804 }
#define SDL_COPY_COLORKEY
Definition: SDL_blit.h:40
#define LCS_WINDOWS_COLOR_SPACE
Definition: SDL_bmp.c:53
#define SDL_BYTEORDER
#define SDL_RWwrite
#define SDL_WriteLE16
#define SDL_UnlockSurface
#define SDL_GetHintBoolean
#define SDL_LockSurface
#define SDL_WriteLE32
#define SDL_ConvertSurface
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
@ SDL_EFWRITE
Definition: SDL_error.h:95
#define SDL_HINT_BMP_SAVE_LEGACY_FORMAT
Prevent SDL from using version 4 of the bitmap header when saving BMPs.
Definition: SDL_hints.h:1166
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
GLenum GLenum dst
GLboolean GLboolean g
int SDL_InitFormat(SDL_PixelFormat *format, Uint32 pixel_format)
Definition: SDL_pixels.c:544
@ SDL_PIXELFORMAT_BGR24
Definition: SDL_pixels.h:240
@ SDL_PIXELFORMAT_BGRA32
Definition: SDL_pixels.h:282
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld endif[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld_src SRC pixld MASK if DST_R else pixld DST_R endif if
SDL_BlitInfo info
Definition: SDL_blit.h:93
Uint8 BitsPerPixel
Definition: SDL_pixels.h:328
SDL_Palette * palette
Definition: SDL_pixels.h:327
SDL_PixelFormat * format
Definition: SDL_surface.h:73
struct SDL_BlitMap * map
Definition: SDL_surface.h:91
static int colors[7]
Definition: testgesture.c:41

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