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 (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 }
486 
487 int
488 SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
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 }
726 
727 /* 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
#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
uint32_t Uint32
Definition: SDL_stdinc.h:181
#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:157
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:819
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
Definition: SDL_endian.h:107
int32_t Sint32
Definition: SDL_stdinc.h:175
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:488
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:139
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
#define SDL_WriteLE32
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
uint16_t Uint16
Definition: SDL_stdinc.h:169
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:188
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