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

◆ BI_RGB

#define BI_RGB   0

Definition at line 46 of file SDL_bmp.c.

◆ BI_RLE4

#define BI_RLE4   2

Definition at line 48 of file SDL_bmp.c.

◆ BI_RLE8

#define BI_RLE8   1

Definition at line 47 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 55 of file SDL_bmp.c.

◆ SAVE_32BIT_BMP

#define SAVE_32BIT_BMP

Definition at line 42 of file SDL_bmp.c.

Function Documentation

◆ CorrectAlphaChannel()

static void CorrectAlphaChannel ( SDL_Surface surface)
static

Definition at line 143 of file SDL_bmp.c.

144 {
145  /* Check to see if there is any alpha channel data */
146  SDL_bool hasAlpha = SDL_FALSE;
147 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
148  int alphaChannelOffset = 0;
149 #else
150  int alphaChannelOffset = 3;
151 #endif
152  Uint8 *alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
153  Uint8 *end = alpha + surface->h * surface->pitch;
154 
155  while (alpha < end) {
156  if (*alpha != 0) {
157  hasAlpha = SDL_TRUE;
158  break;
159  }
160  alpha += 4;
161  }
162 
163  if (!hasAlpha) {
164  alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
165  while (alpha < end) {
167  alpha += 4;
168  }
169  }
170 }

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

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

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

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

References SDL_Color::a, SDL_Color::b, BI_BITFIELDS, BI_RGB, BI_RLE4, BI_RLE8, SDL_Palette::colors, CorrectAlphaChannel(), done, SDL_Color::g, i, 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 568 of file SDL_bmp.c.

569 {
570  Sint64 fp_offset;
571  int i, pad;
573  Uint8 *bits;
574  SDL_bool save32bit = SDL_FALSE;
575  SDL_bool saveLegacyBMP = SDL_FALSE;
576 
577  /* The Win32 BMP file header (14 bytes) */
578  char magic[2] = { 'B', 'M' };
579  Uint32 bfSize;
580  Uint16 bfReserved1;
581  Uint16 bfReserved2;
582  Uint32 bfOffBits;
583 
584  /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
585  Uint32 biSize;
586  Sint32 biWidth;
587  Sint32 biHeight;
588  Uint16 biPlanes;
589  Uint16 biBitCount;
590  Uint32 biCompression;
591  Uint32 biSizeImage;
592  Sint32 biXPelsPerMeter;
593  Sint32 biYPelsPerMeter;
594  Uint32 biClrUsed;
595  Uint32 biClrImportant;
596 
597  /* The additional header members from the Win32 BITMAPV4HEADER struct (108 bytes in total) */
598  Uint32 bV4RedMask = 0;
599  Uint32 bV4GreenMask = 0;
600  Uint32 bV4BlueMask = 0;
601  Uint32 bV4AlphaMask = 0;
602  Uint32 bV4CSType = 0;
603  Sint32 bV4Endpoints[3 * 3] = {0};
604  Uint32 bV4GammaRed = 0;
605  Uint32 bV4GammaGreen = 0;
606  Uint32 bV4GammaBlue = 0;
607 
608  /* Make sure we have somewhere to save */
609  surface = NULL;
610  if (dst) {
611 #ifdef SAVE_32BIT_BMP
612  /* We can save alpha information in a 32-bit BMP */
613  if (saveme->format->BitsPerPixel >= 8 && (saveme->format->Amask ||
614  saveme->map->info.flags & SDL_COPY_COLORKEY)) {
615  save32bit = SDL_TRUE;
616  }
617 #endif /* SAVE_32BIT_BMP */
618 
619  if (saveme->format->palette && !save32bit) {
620  if (saveme->format->BitsPerPixel == 8) {
621  surface = saveme;
622  } else {
623  SDL_SetError("%d bpp BMP files not supported",
624  saveme->format->BitsPerPixel);
625  }
626  } else if ((saveme->format->BitsPerPixel == 24) && !save32bit &&
628  (saveme->format->Rmask == 0x00FF0000) &&
629  (saveme->format->Gmask == 0x0000FF00) &&
630  (saveme->format->Bmask == 0x000000FF)
631 #else
632  (saveme->format->Rmask == 0x000000FF) &&
633  (saveme->format->Gmask == 0x0000FF00) &&
634  (saveme->format->Bmask == 0x00FF0000)
635 #endif
636  ) {
637  surface = saveme;
638  } else {
640 
641  /* If the surface has a colorkey or alpha channel we'll save a
642  32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
643  if (save32bit) {
645  } else {
647  }
648  surface = SDL_ConvertSurface(saveme, &format, 0);
649  if (!surface) {
650  SDL_SetError("Couldn't convert image to %d bpp",
651  format.BitsPerPixel);
652  }
653  }
654  } else {
655  /* Set no error here because it may overwrite a more useful message from
656  SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
657  return -1;
658  }
659 
660  if (save32bit) {
662  }
663 
664  if (surface && (SDL_LockSurface(surface) == 0)) {
665  const int bw = surface->w * surface->format->BytesPerPixel;
666 
667  /* Set the BMP file header values */
668  bfSize = 0; /* We'll write this when we're done */
669  bfReserved1 = 0;
670  bfReserved2 = 0;
671  bfOffBits = 0; /* We'll write this when we're done */
672 
673  /* Write the BMP file header values */
674  fp_offset = SDL_RWtell(dst);
675  SDL_ClearError();
676  SDL_RWwrite(dst, magic, 2, 1);
677  SDL_WriteLE32(dst, bfSize);
678  SDL_WriteLE16(dst, bfReserved1);
679  SDL_WriteLE16(dst, bfReserved2);
680  SDL_WriteLE32(dst, bfOffBits);
681 
682  /* Set the BMP info values */
683  biSize = 40;
684  biWidth = surface->w;
685  biHeight = surface->h;
686  biPlanes = 1;
687  biBitCount = surface->format->BitsPerPixel;
688  biCompression = BI_RGB;
689  biSizeImage = surface->h * surface->pitch;
690  biXPelsPerMeter = 0;
691  biYPelsPerMeter = 0;
692  if (surface->format->palette) {
693  biClrUsed = surface->format->palette->ncolors;
694  } else {
695  biClrUsed = 0;
696  }
697  biClrImportant = 0;
698 
699  /* Set the BMP info values for the version 4 header */
700  if (save32bit && !saveLegacyBMP) {
701  biSize = 108;
702  biCompression = BI_BITFIELDS;
703  /* The BMP format is always little endian, these masks stay the same */
704  bV4RedMask = 0x00ff0000;
705  bV4GreenMask = 0x0000ff00;
706  bV4BlueMask = 0x000000ff;
707  bV4AlphaMask = 0xff000000;
708  bV4CSType = LCS_WINDOWS_COLOR_SPACE;
709  bV4GammaRed = 0;
710  bV4GammaGreen = 0;
711  bV4GammaBlue = 0;
712  }
713 
714  /* Write the BMP info values */
715  SDL_WriteLE32(dst, biSize);
716  SDL_WriteLE32(dst, biWidth);
717  SDL_WriteLE32(dst, biHeight);
718  SDL_WriteLE16(dst, biPlanes);
719  SDL_WriteLE16(dst, biBitCount);
720  SDL_WriteLE32(dst, biCompression);
721  SDL_WriteLE32(dst, biSizeImage);
722  SDL_WriteLE32(dst, biXPelsPerMeter);
723  SDL_WriteLE32(dst, biYPelsPerMeter);
724  SDL_WriteLE32(dst, biClrUsed);
725  SDL_WriteLE32(dst, biClrImportant);
726 
727  /* Write the BMP info values for the version 4 header */
728  if (save32bit && !saveLegacyBMP) {
729  SDL_WriteLE32(dst, bV4RedMask);
730  SDL_WriteLE32(dst, bV4GreenMask);
731  SDL_WriteLE32(dst, bV4BlueMask);
732  SDL_WriteLE32(dst, bV4AlphaMask);
733  SDL_WriteLE32(dst, bV4CSType);
734  for (i = 0; i < 3 * 3; i++) {
735  SDL_WriteLE32(dst, bV4Endpoints[i]);
736  }
737  SDL_WriteLE32(dst, bV4GammaRed);
738  SDL_WriteLE32(dst, bV4GammaGreen);
739  SDL_WriteLE32(dst, bV4GammaBlue);
740  }
741 
742  /* Write the palette (in BGR color order) */
743  if (surface->format->palette) {
744  SDL_Color *colors;
745  int ncolors;
746 
747  colors = surface->format->palette->colors;
748  ncolors = surface->format->palette->ncolors;
749  for (i = 0; i < ncolors; ++i) {
750  SDL_RWwrite(dst, &colors[i].b, 1, 1);
751  SDL_RWwrite(dst, &colors[i].g, 1, 1);
752  SDL_RWwrite(dst, &colors[i].r, 1, 1);
753  SDL_RWwrite(dst, &colors[i].a, 1, 1);
754  }
755  }
756 
757  /* Write the bitmap offset */
758  bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
759  if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
761  }
762  SDL_WriteLE32(dst, bfOffBits);
763  if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
765  }
766 
767  /* Write the bitmap image upside down */
768  bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
769  pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
770  while (bits > (Uint8 *) surface->pixels) {
771  bits -= surface->pitch;
772  if (SDL_RWwrite(dst, bits, 1, bw) != bw) {
774  break;
775  }
776  if (pad) {
777  const Uint8 padbyte = 0;
778  for (i = 0; i < pad; ++i) {
779  SDL_RWwrite(dst, &padbyte, 1, 1);
780  }
781  }
782  }
783 
784  /* Write the BMP file size */
785  bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
786  if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
788  }
789  SDL_WriteLE32(dst, bfSize);
790  if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) {
792  }
793 
794  /* Close it up.. */
796  if (surface != saveme) {
798  }
799  }
800 
801  if (freedst && dst) {
802  SDL_RWclose(dst);
803  }
804  return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
805 }

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.

SDL_UnlockSurface
#define SDL_UnlockSurface
Definition: SDL_dynapi_overrides.h:449
format
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179
SDL_GetError
#define SDL_GetError
Definition: SDL_dynapi_overrides.h:113
Sint32
int32_t Sint32
Definition: SDL_stdinc.h:197
Sint64
int64_t Sint64
Definition: SDL_stdinc.h:210
SDL_PixelFormat::BitsPerPixel
Uint8 BitsPerPixel
Definition: SDL_pixels.h:322
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
SDL_Palette::ncolors
int ncolors
Definition: SDL_pixels.h:309
SDL_Color::b
Uint8 b
Definition: SDL_pixels.h:302
SDL_Surface
A collection of pixels used in software blitting.
Definition: SDL_surface.h:71
SDL_ClearError
#define SDL_ClearError
Definition: SDL_dynapi_overrides.h:114
end
GLuint GLuint end
Definition: SDL_opengl.h:1571
NULL
#define NULL
Definition: begin_code.h:167
surface
EGLSurface surface
Definition: eglext.h:248
SDL_ALPHA_OPAQUE
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:46
BI_RLE8
#define BI_RLE8
Definition: SDL_bmp.c:46
b
GLboolean GLboolean GLboolean b
Definition: SDL_opengl_glext.h:1112
endif
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
Definition: pixman-arm-neon-asm.h:549
SDL_Swap16
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
Definition: SDL_endian.h:110
g
GLboolean GLboolean g
Definition: SDL_opengl_glext.h:1112
SDL_WriteLE16
#define SDL_WriteLE16
Definition: SDL_dynapi_overrides.h:364
SDL_Color::r
Uint8 r
Definition: SDL_pixels.h:300
r
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
SDL_ConvertSurface
#define SDL_ConvertSurface
Definition: SDL_dynapi_overrides.h:463
top
GLdouble GLdouble GLdouble GLdouble top
Definition: SDL_opengl_glext.h:6106
SDL_COPY_COLORKEY
#define SDL_COPY_COLORKEY
Definition: SDL_blit.h:40
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_BlitMap::info
SDL_BlitInfo info
Definition: SDL_blit.h:93
SDL_RWread
#define SDL_RWread
Definition: SDL_dynapi_overrides.h:723
SDL_strncmp
#define SDL_strncmp
Definition: SDL_dynapi_overrides.h:418
SDL_PixelFormat::Rmask
Uint32 Rmask
Definition: SDL_pixels.h:325
a
GLboolean GLboolean GLboolean GLboolean a
Definition: SDL_opengl_glext.h:1112
SDL_ReadLE32
#define SDL_ReadLE32
Definition: SDL_dynapi_overrides.h:359
readRlePixels
static int readRlePixels(SDL_Surface *surface, SDL_RWops *src, int isRle8)
Definition: SDL_bmp.c:57
SDL_Color::a
Uint8 a
Definition: SDL_pixels.h:303
alpha
GLfloat GLfloat GLfloat alpha
Definition: SDL_opengl_glext.h:415
dst
GLenum GLenum dst
Definition: SDL_opengl_glext.h:1740
COPY_PIXEL
#define COPY_PIXEL(x)
SDL_Error
#define SDL_Error
Definition: SDL_dynapi_overrides.h:115
SDL_RWwrite
#define SDL_RWwrite
Definition: SDL_dynapi_overrides.h:724
SDL_LIL_ENDIAN
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
SDL_GetHintBoolean
#define SDL_GetHintBoolean
Definition: SDL_dynapi_overrides.h:608
done
int done
Definition: checkkeys.c:28
SDL_ReadLE16
#define SDL_ReadLE16
Definition: SDL_dynapi_overrides.h:357
SDL_Palette::colors
SDL_Color * colors
Definition: SDL_pixels.h:310
SDL_Color::g
Uint8 g
Definition: SDL_pixels.h:301
SDL_PIXELFORMAT_BGRA32
@ SDL_PIXELFORMAT_BGRA32
Definition: SDL_pixels.h:276
height
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
SDL_RWseek
#define SDL_RWseek
Definition: SDL_dynapi_overrides.h:721
SDL_FreeSurface
#define SDL_FreeSurface
Definition: SDL_dynapi_overrides.h:446
SDL_PixelFormat::palette
SDL_Palette * palette
Definition: SDL_pixels.h:321
SDL_Swap32
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
Definition: SDL_endian.h:165
LCS_WINDOWS_COLOR_SPACE
#define LCS_WINDOWS_COLOR_SPACE
Definition: SDL_bmp.c:54
SDL_PixelFormat::Amask
Uint32 Amask
Definition: SDL_pixels.h:328
SDL_Surface::map
struct SDL_BlitMap * map
Definition: SDL_surface.h:89
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_PixelFormat
Definition: SDL_pixels.h:319
SDL_HINT_BMP_SAVE_LEGACY_FORMAT
#define SDL_HINT_BMP_SAVE_LEGACY_FORMAT
Prevent SDL from using version 4 of the bitmap header when saving BMPs.
Definition: SDL_hints.h:1035
SDL_PixelFormat::Gmask
Uint32 Gmask
Definition: SDL_pixels.h:326
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
start
GLuint start
Definition: SDL_opengl.h:1571
CorrectAlphaChannel
static void CorrectAlphaChannel(SDL_Surface *surface)
Definition: SDL_bmp.c:143
BI_RGB
#define BI_RGB
Definition: SDL_bmp.c:45
SDL_LockSurface
#define SDL_LockSurface
Definition: SDL_dynapi_overrides.h:448
SDL_CreateRGBSurface
#define SDL_CreateRGBSurface
Definition: SDL_dynapi_overrides.h:444
SDL_RWtell
#define SDL_RWtell
Definition: SDL_dynapi_overrides.h:722
SDL_PixelFormat::Bmask
Uint32 Bmask
Definition: SDL_pixels.h:327
SDL_Palette
Definition: SDL_pixels.h:308
src
GLenum src
Definition: SDL_opengl_glext.h:1740
RW_SEEK_SET
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_RWclose
#define SDL_RWclose
Definition: SDL_dynapi_overrides.h:725
RW_SEEK_CUR
#define RW_SEEK_CUR
Definition: SDL_rwops.h:175
SDL_Color
Definition: SDL_pixels.h:299
SDL_PIXELFORMAT_BGR24
@ SDL_PIXELFORMAT_BGR24
Definition: SDL_pixels.h:236
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_BlitInfo::flags
int flags
Definition: SDL_blit.h:69
SDL_WriteLE32
#define SDL_WriteLE32
Definition: SDL_dynapi_overrides.h:366
bits
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
Definition: SDL_opengl_glext.h:6179
BI_RLE4
#define BI_RLE4
Definition: SDL_bmp.c:47
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_EFSEEK
@ SDL_EFSEEK
Definition: SDL_error.h:60
SDL_strcmp
#define SDL_strcmp
Definition: SDL_dynapi_overrides.h:417
SDL_BYTEORDER
#define SDL_BYTEORDER
Definition: SDL_config_pandora.h:37
BI_BITFIELDS
#define BI_BITFIELDS
Definition: SDL_bmp.c:48
SDL_Surface::format
SDL_PixelFormat * format
Definition: SDL_surface.h:73
i
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
SDL_EFWRITE
@ SDL_EFWRITE
Definition: SDL_error.h:59
SDL_EFREAD
@ SDL_EFREAD
Definition: SDL_error.h:58
colors
static int colors[7]
Definition: testgesture.c:41
SDL_InitFormat
int SDL_InitFormat(SDL_PixelFormat *format, Uint32 pixel_format)
Definition: SDL_pixels.c:544