SDL  2.0
SDL_bmp.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../SDL_internal.h"
22 
23 /*
24  Code to load and save surfaces in Windows BMP format.
25 
26  Why support BMP format? Well, it's a native format for Windows, and
27  most image processing programs can read and write it. It would be nice
28  to be able to have at least one image format that we can natively load
29  and save, and since PNG is so complex that it would bloat the library,
30  BMP is a good alternative.
31 
32  This code currently supports Win32 DIBs in uncompressed 8 and 24 bpp.
33 */
34 
35 #include "SDL_hints.h"
36 #include "SDL_video.h"
37 #include "SDL_assert.h"
38 #include "SDL_endian.h"
39 #include "SDL_pixels_c.h"
40 
41 #define SAVE_32BIT_BMP
42 
43 /* Compression encodings for BMP files */
44 #ifndef BI_RGB
45 #define BI_RGB 0
46 #define BI_RLE8 1
47 #define BI_RLE4 2
48 #define BI_BITFIELDS 3
49 #endif
50 
51 /* Logical color space values for BMP files */
52 #ifndef LCS_WINDOWS_COLOR_SPACE
53 /* 0x57696E20 == "Win " */
54 #define LCS_WINDOWS_COLOR_SPACE 0x57696E20
55 #endif
56 
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 }
85 
87 SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
88 {
89  SDL_bool was_error;
90  Sint64 fp_offset = 0;
91  int bmpPitch;
92  int i, pad;
94  Uint32 Rmask = 0;
95  Uint32 Gmask = 0;
96  Uint32 Bmask = 0;
97  Uint32 Amask = 0;
98  SDL_Palette *palette;
99  Uint8 *bits;
100  Uint8 *top, *end;
101  SDL_bool topDown;
102  int ExpandBMP;
103  SDL_bool haveRGBMasks = SDL_FALSE;
104  SDL_bool haveAlphaMask = SDL_FALSE;
105  SDL_bool correctAlpha = SDL_FALSE;
106 
107  /* The Win32 BMP file header (14 bytes) */
108  char magic[2];
109  /* Uint32 bfSize = 0; */
110  /* Uint16 bfReserved1 = 0; */
111  /* Uint16 bfReserved2 = 0; */
112  Uint32 bfOffBits = 0;
113 
114  /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
115  Uint32 biSize = 0;
116  Sint32 biWidth = 0;
117  Sint32 biHeight = 0;
118  /* Uint16 biPlanes = 0; */
119  Uint16 biBitCount = 0;
120  Uint32 biCompression = 0;
121  /* Uint32 biSizeImage = 0; */
122  /* Sint32 biXPelsPerMeter = 0; */
123  /* Sint32 biYPelsPerMeter = 0; */
124  Uint32 biClrUsed = 0;
125  /* Uint32 biClrImportant = 0; */
126 
127  (void) haveRGBMasks;
128  (void) haveAlphaMask;
129 
130  /* Make sure we are passed a valid data source */
131  surface = NULL;
132  was_error = SDL_FALSE;
133  if (src == NULL) {
134  was_error = SDL_TRUE;
135  goto done;
136  }
137 
138  /* Read in the BMP file header */
139  fp_offset = SDL_RWtell(src);
140  SDL_ClearError();
141  if (SDL_RWread(src, magic, 1, 2) != 2) {
143  was_error = SDL_TRUE;
144  goto done;
145  }
146  if (SDL_strncmp(magic, "BM", 2) != 0) {
147  SDL_SetError("File is not a Windows BMP file");
148  was_error = SDL_TRUE;
149  goto done;
150  }
151  /* bfSize = */ SDL_ReadLE32(src);
152  /* bfReserved1 = */ SDL_ReadLE16(src);
153  /* bfReserved2 = */ SDL_ReadLE16(src);
154  bfOffBits = SDL_ReadLE32(src);
155 
156  /* Read the Win32 BITMAPINFOHEADER */
157  biSize = SDL_ReadLE32(src);
158  if (biSize == 12) { /* really old BITMAPCOREHEADER */
159  biWidth = (Uint32) SDL_ReadLE16(src);
160  biHeight = (Uint32) SDL_ReadLE16(src);
161  /* biPlanes = */ SDL_ReadLE16(src);
162  biBitCount = SDL_ReadLE16(src);
163  biCompression = BI_RGB;
164  } else if (biSize >= 40) { /* some version of BITMAPINFOHEADER */
165  Uint32 headerSize;
166  biWidth = SDL_ReadLE32(src);
167  biHeight = SDL_ReadLE32(src);
168  /* biPlanes = */ SDL_ReadLE16(src);
169  biBitCount = SDL_ReadLE16(src);
170  biCompression = SDL_ReadLE32(src);
171  /* biSizeImage = */ SDL_ReadLE32(src);
172  /* biXPelsPerMeter = */ SDL_ReadLE32(src);
173  /* biYPelsPerMeter = */ SDL_ReadLE32(src);
174  biClrUsed = SDL_ReadLE32(src);
175  /* biClrImportant = */ SDL_ReadLE32(src);
176 
177  /* 64 == BITMAPCOREHEADER2, an incompatible OS/2 2.x extension. Skip this stuff for now. */
178  if (biSize == 64) {
179  /* ignore these extra fields. */
180  if (biCompression == BI_BITFIELDS) {
181  /* this value is actually huffman compression in this variant. */
182  SDL_SetError("Compressed BMP files not supported");
183  was_error = SDL_TRUE;
184  goto done;
185  }
186  } else {
187  /* This is complicated. If compression is BI_BITFIELDS, then
188  we have 3 DWORDS that specify the RGB masks. This is either
189  stored here in an BITMAPV2INFOHEADER (which only differs in
190  that it adds these RGB masks) and biSize >= 52, or we've got
191  these masks stored in the exact same place, but strictly
192  speaking, this is the bmiColors field in BITMAPINFO immediately
193  following the legacy v1 info header, just past biSize. */
194  if (biCompression == BI_BITFIELDS) {
195  haveRGBMasks = SDL_TRUE;
196  Rmask = SDL_ReadLE32(src);
197  Gmask = SDL_ReadLE32(src);
198  Bmask = SDL_ReadLE32(src);
199 
200  /* ...v3 adds an alpha mask. */
201  if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
202  haveAlphaMask = SDL_TRUE;
203  Amask = SDL_ReadLE32(src);
204  }
205  } else {
206  /* the mask fields are ignored for v2+ headers if not BI_BITFIELD. */
207  if (biSize >= 52) { /* BITMAPV2INFOHEADER; adds RGB masks */
208  /*Rmask = */ SDL_ReadLE32(src);
209  /*Gmask = */ SDL_ReadLE32(src);
210  /*Bmask = */ SDL_ReadLE32(src);
211  }
212  if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
213  /*Amask = */ SDL_ReadLE32(src);
214  }
215  }
216 
217  /* Insert other fields here; Wikipedia and MSDN say we're up to
218  v5 of this header, but we ignore those for now (they add gamma,
219  color spaces, etc). Ignoring the weird OS/2 2.x format, we
220  currently parse up to v3 correctly (hopefully!). */
221  }
222 
223  /* skip any header bytes we didn't handle... */
224  headerSize = (Uint32) (SDL_RWtell(src) - (fp_offset + 14));
225  if (biSize > headerSize) {
226  SDL_RWseek(src, (biSize - headerSize), RW_SEEK_CUR);
227  }
228  }
229  if (biWidth <= 0 || biHeight == 0) {
230  SDL_SetError("BMP file with bad dimensions (%dx%d)", biWidth, biHeight);
231  was_error = SDL_TRUE;
232  goto done;
233  }
234  if (biHeight < 0) {
235  topDown = SDL_TRUE;
236  biHeight = -biHeight;
237  } else {
238  topDown = SDL_FALSE;
239  }
240 
241  /* Check for read error */
242  if (SDL_strcmp(SDL_GetError(), "") != 0) {
243  was_error = SDL_TRUE;
244  goto done;
245  }
246 
247  /* Expand 1 and 4 bit bitmaps to 8 bits per pixel */
248  switch (biBitCount) {
249  case 1:
250  case 4:
251  ExpandBMP = biBitCount;
252  biBitCount = 8;
253  break;
254  case 2:
255  case 3:
256  case 5:
257  case 6:
258  case 7:
259  SDL_SetError("%d-bpp BMP images are not supported", biBitCount);
260  was_error = SDL_TRUE;
261  goto done;
262  default:
263  ExpandBMP = 0;
264  break;
265  }
266 
267  /* We don't support any BMP compression right now */
268  switch (biCompression) {
269  case BI_RGB:
270  /* If there are no masks, use the defaults */
271  SDL_assert(!haveRGBMasks);
272  SDL_assert(!haveAlphaMask);
273  /* Default values for the BMP format */
274  switch (biBitCount) {
275  case 15:
276  case 16:
277  Rmask = 0x7C00;
278  Gmask = 0x03E0;
279  Bmask = 0x001F;
280  break;
281  case 24:
282 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
283  Rmask = 0x000000FF;
284  Gmask = 0x0000FF00;
285  Bmask = 0x00FF0000;
286 #else
287  Rmask = 0x00FF0000;
288  Gmask = 0x0000FF00;
289  Bmask = 0x000000FF;
290 #endif
291  break;
292  case 32:
293  /* We don't know if this has alpha channel or not */
294  correctAlpha = SDL_TRUE;
295  Amask = 0xFF000000;
296  Rmask = 0x00FF0000;
297  Gmask = 0x0000FF00;
298  Bmask = 0x000000FF;
299  break;
300  default:
301  break;
302  }
303  break;
304 
305  case BI_BITFIELDS:
306  break; /* we handled this in the info header. */
307 
308  default:
309  SDL_SetError("Compressed BMP files not supported");
310  was_error = SDL_TRUE;
311  goto done;
312  }
313 
314  /* Create a compatible surface, note that the colors are RGB ordered */
315  surface =
316  SDL_CreateRGBSurface(0, biWidth, biHeight, biBitCount, Rmask, Gmask,
317  Bmask, Amask);
318  if (surface == NULL) {
319  was_error = SDL_TRUE;
320  goto done;
321  }
322 
323  /* Load the palette, if any */
324  palette = (surface->format)->palette;
325  if (palette) {
326  SDL_assert(biBitCount <= 8);
327  if (biClrUsed == 0) {
328  biClrUsed = 1 << biBitCount;
329  } else if (biClrUsed > (1 << biBitCount)) {
330  SDL_SetError("BMP file has an invalid number of colors");
331  was_error = SDL_TRUE;
332  goto done;
333  }
334  if ((int) biClrUsed > palette->ncolors) {
335  SDL_Color *colors;
336  int ncolors = biClrUsed;
337  colors =
338  (SDL_Color *) SDL_realloc(palette->colors,
339  ncolors *
340  sizeof(*palette->colors));
341  if (!colors) {
342  SDL_OutOfMemory();
343  was_error = SDL_TRUE;
344  goto done;
345  }
346  palette->ncolors = ncolors;
347  palette->colors = colors;
348  } else if ((int) biClrUsed < palette->ncolors) {
349  palette->ncolors = biClrUsed;
350  }
351  if (biSize == 12) {
352  for (i = 0; i < (int) biClrUsed; ++i) {
353  SDL_RWread(src, &palette->colors[i].b, 1, 1);
354  SDL_RWread(src, &palette->colors[i].g, 1, 1);
355  SDL_RWread(src, &palette->colors[i].r, 1, 1);
356  palette->colors[i].a = SDL_ALPHA_OPAQUE;
357  }
358  } else {
359  for (i = 0; i < (int) biClrUsed; ++i) {
360  SDL_RWread(src, &palette->colors[i].b, 1, 1);
361  SDL_RWread(src, &palette->colors[i].g, 1, 1);
362  SDL_RWread(src, &palette->colors[i].r, 1, 1);
363  SDL_RWread(src, &palette->colors[i].a, 1, 1);
364 
365  /* According to Microsoft documentation, the fourth element
366  is reserved and must be zero, so we shouldn't treat it as
367  alpha.
368  */
369  palette->colors[i].a = SDL_ALPHA_OPAQUE;
370  }
371  }
372  }
373 
374  /* Read the surface pixels. Note that the bmp image is upside down */
375  if (SDL_RWseek(src, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
377  was_error = SDL_TRUE;
378  goto done;
379  }
380  top = (Uint8 *)surface->pixels;
381  end = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
382  switch (ExpandBMP) {
383  case 1:
384  bmpPitch = (biWidth + 7) >> 3;
385  pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
386  break;
387  case 4:
388  bmpPitch = (biWidth + 1) >> 1;
389  pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
390  break;
391  default:
392  pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
393  break;
394  }
395  if (topDown) {
396  bits = top;
397  } else {
398  bits = end - surface->pitch;
399  }
400  while (bits >= top && bits < end) {
401  switch (ExpandBMP) {
402  case 1:
403  case 4:{
404  Uint8 pixel = 0;
405  int shift = (8 - ExpandBMP);
406  for (i = 0; i < surface->w; ++i) {
407  if (i % (8 / ExpandBMP) == 0) {
408  if (!SDL_RWread(src, &pixel, 1, 1)) {
409  SDL_SetError("Error reading from BMP");
410  was_error = SDL_TRUE;
411  goto done;
412  }
413  }
414 
415  bits[i] = (pixel >> shift);
416  if (bits[i] >= biClrUsed) {
417  SDL_SetError("A BMP image contains a pixel with a color out of the palette");
418  was_error = SDL_TRUE;
419  goto done;
420  }
421  pixel <<= ExpandBMP;
422  }
423  }
424  break;
425 
426  default:
427  if (SDL_RWread(src, bits, 1, surface->pitch) != surface->pitch) {
429  was_error = SDL_TRUE;
430  goto done;
431  }
432  if (biBitCount == 8 && palette && biClrUsed < (1 << biBitCount)) {
433  for (i = 0; i < surface->w; ++i) {
434  if (bits[i] >= biClrUsed) {
435  SDL_SetError("A BMP image contains a pixel with a color out of the palette");
436  was_error = SDL_TRUE;
437  goto done;
438  }
439  }
440  }
441 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
442  /* Byte-swap the pixels if needed. Note that the 24bpp
443  case has already been taken care of above. */
444  switch (biBitCount) {
445  case 15:
446  case 16:{
447  Uint16 *pix = (Uint16 *) bits;
448  for (i = 0; i < surface->w; i++)
449  pix[i] = SDL_Swap16(pix[i]);
450  break;
451  }
452 
453  case 32:{
454  Uint32 *pix = (Uint32 *) bits;
455  for (i = 0; i < surface->w; i++)
456  pix[i] = SDL_Swap32(pix[i]);
457  break;
458  }
459  }
460 #endif
461  break;
462  }
463  /* Skip padding bytes, ugh */
464  if (pad) {
465  Uint8 padbyte;
466  for (i = 0; i < pad; ++i) {
467  SDL_RWread(src, &padbyte, 1, 1);
468  }
469  }
470  if (topDown) {
471  bits += surface->pitch;
472  } else {
473  bits -= surface->pitch;
474  }
475  }
476  if (correctAlpha) {
477  CorrectAlphaChannel(surface);
478  }
479  done:
480  if (was_error) {
481  if (src) {
482  SDL_RWseek(src, fp_offset, RW_SEEK_SET);
483  }
484  SDL_FreeSurface(surface);
485  surface = NULL;
486  }
487  if (freesrc && src) {
488  SDL_RWclose(src);
489  }
490  return (surface);
491 }
492 
493 int
494 SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
495 {
496  Sint64 fp_offset;
497  int i, pad;
499  Uint8 *bits;
500  SDL_bool save32bit = SDL_FALSE;
501  SDL_bool saveLegacyBMP = SDL_FALSE;
502 
503  /* The Win32 BMP file header (14 bytes) */
504  char magic[2] = { 'B', 'M' };
505  Uint32 bfSize;
506  Uint16 bfReserved1;
507  Uint16 bfReserved2;
508  Uint32 bfOffBits;
509 
510  /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
511  Uint32 biSize;
512  Sint32 biWidth;
513  Sint32 biHeight;
514  Uint16 biPlanes;
515  Uint16 biBitCount;
516  Uint32 biCompression;
517  Uint32 biSizeImage;
518  Sint32 biXPelsPerMeter;
519  Sint32 biYPelsPerMeter;
520  Uint32 biClrUsed;
521  Uint32 biClrImportant;
522 
523  /* The additional header members from the Win32 BITMAPV4HEADER struct (108 bytes in total) */
524  Uint32 bV4RedMask = 0;
525  Uint32 bV4GreenMask = 0;
526  Uint32 bV4BlueMask = 0;
527  Uint32 bV4AlphaMask = 0;
528  Uint32 bV4CSType = 0;
529  Sint32 bV4Endpoints[3 * 3] = {0};
530  Uint32 bV4GammaRed = 0;
531  Uint32 bV4GammaGreen = 0;
532  Uint32 bV4GammaBlue = 0;
533 
534  /* Make sure we have somewhere to save */
535  surface = NULL;
536  if (dst) {
537 #ifdef SAVE_32BIT_BMP
538  /* We can save alpha information in a 32-bit BMP */
539  if (saveme->format->BitsPerPixel >= 8 && (saveme->format->Amask ||
540  saveme->map->info.flags & SDL_COPY_COLORKEY)) {
541  save32bit = SDL_TRUE;
542  }
543 #endif /* SAVE_32BIT_BMP */
544 
545  if (saveme->format->palette && !save32bit) {
546  if (saveme->format->BitsPerPixel == 8) {
547  surface = saveme;
548  } else {
549  SDL_SetError("%d bpp BMP files not supported",
550  saveme->format->BitsPerPixel);
551  }
552  } else if ((saveme->format->BitsPerPixel == 24) && !save32bit &&
554  (saveme->format->Rmask == 0x00FF0000) &&
555  (saveme->format->Gmask == 0x0000FF00) &&
556  (saveme->format->Bmask == 0x000000FF)
557 #else
558  (saveme->format->Rmask == 0x000000FF) &&
559  (saveme->format->Gmask == 0x0000FF00) &&
560  (saveme->format->Bmask == 0x00FF0000)
561 #endif
562  ) {
563  surface = saveme;
564  } else {
566 
567  /* If the surface has a colorkey or alpha channel we'll save a
568  32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
569  if (save32bit) {
571  } else {
573  }
574  surface = SDL_ConvertSurface(saveme, &format, 0);
575  if (!surface) {
576  SDL_SetError("Couldn't convert image to %d bpp",
577  format.BitsPerPixel);
578  }
579  }
580  } else {
581  /* Set no error here because it may overwrite a more useful message from
582  SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
583  return -1;
584  }
585 
586  if (save32bit) {
588  }
589 
590  if (surface && (SDL_LockSurface(surface) == 0)) {
591  const int bw = surface->w * surface->format->BytesPerPixel;
592 
593  /* Set the BMP file header values */
594  bfSize = 0; /* We'll write this when we're done */
595  bfReserved1 = 0;
596  bfReserved2 = 0;
597  bfOffBits = 0; /* We'll write this when we're done */
598 
599  /* Write the BMP file header values */
600  fp_offset = SDL_RWtell(dst);
601  SDL_ClearError();
602  SDL_RWwrite(dst, magic, 2, 1);
603  SDL_WriteLE32(dst, bfSize);
604  SDL_WriteLE16(dst, bfReserved1);
605  SDL_WriteLE16(dst, bfReserved2);
606  SDL_WriteLE32(dst, bfOffBits);
607 
608  /* Set the BMP info values */
609  biSize = 40;
610  biWidth = surface->w;
611  biHeight = surface->h;
612  biPlanes = 1;
613  biBitCount = surface->format->BitsPerPixel;
614  biCompression = BI_RGB;
615  biSizeImage = surface->h * surface->pitch;
616  biXPelsPerMeter = 0;
617  biYPelsPerMeter = 0;
618  if (surface->format->palette) {
619  biClrUsed = surface->format->palette->ncolors;
620  } else {
621  biClrUsed = 0;
622  }
623  biClrImportant = 0;
624 
625  /* Set the BMP info values for the version 4 header */
626  if (save32bit && !saveLegacyBMP) {
627  biSize = 108;
628  biCompression = BI_BITFIELDS;
629  /* The BMP format is always little endian, these masks stay the same */
630  bV4RedMask = 0x00ff0000;
631  bV4GreenMask = 0x0000ff00;
632  bV4BlueMask = 0x000000ff;
633  bV4AlphaMask = 0xff000000;
634  bV4CSType = LCS_WINDOWS_COLOR_SPACE;
635  bV4GammaRed = 0;
636  bV4GammaGreen = 0;
637  bV4GammaBlue = 0;
638  }
639 
640  /* Write the BMP info values */
641  SDL_WriteLE32(dst, biSize);
642  SDL_WriteLE32(dst, biWidth);
643  SDL_WriteLE32(dst, biHeight);
644  SDL_WriteLE16(dst, biPlanes);
645  SDL_WriteLE16(dst, biBitCount);
646  SDL_WriteLE32(dst, biCompression);
647  SDL_WriteLE32(dst, biSizeImage);
648  SDL_WriteLE32(dst, biXPelsPerMeter);
649  SDL_WriteLE32(dst, biYPelsPerMeter);
650  SDL_WriteLE32(dst, biClrUsed);
651  SDL_WriteLE32(dst, biClrImportant);
652 
653  /* Write the BMP info values for the version 4 header */
654  if (save32bit && !saveLegacyBMP) {
655  SDL_WriteLE32(dst, bV4RedMask);
656  SDL_WriteLE32(dst, bV4GreenMask);
657  SDL_WriteLE32(dst, bV4BlueMask);
658  SDL_WriteLE32(dst, bV4AlphaMask);
659  SDL_WriteLE32(dst, bV4CSType);
660  for (i = 0; i < 3 * 3; i++) {
661  SDL_WriteLE32(dst, bV4Endpoints[i]);
662  }
663  SDL_WriteLE32(dst, bV4GammaRed);
664  SDL_WriteLE32(dst, bV4GammaGreen);
665  SDL_WriteLE32(dst, bV4GammaBlue);
666  }
667 
668  /* Write the palette (in BGR color order) */
669  if (surface->format->palette) {
670  SDL_Color *colors;
671  int ncolors;
672 
673  colors = surface->format->palette->colors;
674  ncolors = surface->format->palette->ncolors;
675  for (i = 0; i < ncolors; ++i) {
676  SDL_RWwrite(dst, &colors[i].b, 1, 1);
677  SDL_RWwrite(dst, &colors[i].g, 1, 1);
678  SDL_RWwrite(dst, &colors[i].r, 1, 1);
679  SDL_RWwrite(dst, &colors[i].a, 1, 1);
680  }
681  }
682 
683  /* Write the bitmap offset */
684  bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
685  if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
687  }
688  SDL_WriteLE32(dst, bfOffBits);
689  if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
691  }
692 
693  /* Write the bitmap image upside down */
694  bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
695  pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
696  while (bits > (Uint8 *) surface->pixels) {
697  bits -= surface->pitch;
698  if (SDL_RWwrite(dst, bits, 1, bw) != bw) {
700  break;
701  }
702  if (pad) {
703  const Uint8 padbyte = 0;
704  for (i = 0; i < pad; ++i) {
705  SDL_RWwrite(dst, &padbyte, 1, 1);
706  }
707  }
708  }
709 
710  /* Write the BMP file size */
711  bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
712  if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
714  }
715  SDL_WriteLE32(dst, bfSize);
716  if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) {
718  }
719 
720  /* Close it up.. */
721  SDL_UnlockSurface(surface);
722  if (surface != saveme) {
723  SDL_FreeSurface(surface);
724  }
725  }
726 
727  if (freedst && dst) {
728  SDL_RWclose(dst);
729  }
730  return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
731 }
732 
733 /* vi: set ts=4 sw=4 expandtab: */
#define BI_RGB
Definition: SDL_bmp.c:45
#define SDL_ClearError
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
#define SDL_GetError
#define SDL_UnlockSurface
#define SDL_COPY_COLORKEY
Definition: SDL_blit.h:39
#define LCS_WINDOWS_COLOR_SPACE
Definition: SDL_bmp.c:54
Uint8 g
Definition: SDL_pixels.h:298
GLenum GLenum dst
#define SDL_RWwrite(ctx, ptr, size, n)
Definition: SDL_rwops.h:188
Uint8 BytesPerPixel
Definition: SDL_pixels.h:320
#define SDL_ConvertSurface
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
#define SDL_WriteLE16
uint16_t Uint16
Definition: SDL_stdinc.h:191
#define SDL_ReadLE32
#define SDL_RWread(ctx, ptr, size, n)
Definition: SDL_rwops.h:187
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
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
GLenum src
GLdouble GLdouble GLdouble GLdouble top
#define SDL_strncmp
#define SDL_Error
GLfloat GLfloat GLfloat alpha
#define SDL_GetHintBoolean
#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
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
struct SDL_BlitMap * map
Definition: SDL_surface.h:88
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
Uint8 BitsPerPixel
Definition: SDL_pixels.h:319
int done
Definition: checkkeys.c:28
#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
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
Definition: SDL_endian.h:107
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
int SDL_SaveBMP_RW(SDL_Surface *saveme, SDL_RWops *dst, int freedst)
Definition: SDL_bmp.c:494
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_LockSurface
SDL_Surface * SDL_LoadBMP_RW(SDL_RWops *src, int freesrc)
Definition: SDL_bmp.c:87
#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 SDL_WriteLE32
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
SDL_Palette * palette
Definition: SDL_pixels.h:318
#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
GLboolean GLboolean GLboolean GLboolean a
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:46
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