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  default:
250  ExpandBMP = 0;
251  break;
252  }
253 
254  /* We don't support any BMP compression right now */
255  switch (biCompression) {
256  case BI_RGB:
257  /* If there are no masks, use the defaults */
258  SDL_assert(!haveRGBMasks);
259  SDL_assert(!haveAlphaMask);
260  /* Default values for the BMP format */
261  switch (biBitCount) {
262  case 15:
263  case 16:
264  Rmask = 0x7C00;
265  Gmask = 0x03E0;
266  Bmask = 0x001F;
267  break;
268  case 24:
269 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
270  Rmask = 0x000000FF;
271  Gmask = 0x0000FF00;
272  Bmask = 0x00FF0000;
273 #else
274  Rmask = 0x00FF0000;
275  Gmask = 0x0000FF00;
276  Bmask = 0x000000FF;
277 #endif
278  break;
279  case 32:
280  /* We don't know if this has alpha channel or not */
281  correctAlpha = SDL_TRUE;
282  Amask = 0xFF000000;
283  Rmask = 0x00FF0000;
284  Gmask = 0x0000FF00;
285  Bmask = 0x000000FF;
286  break;
287  default:
288  break;
289  }
290  break;
291 
292  case BI_BITFIELDS:
293  break; /* we handled this in the info header. */
294 
295  default:
296  SDL_SetError("Compressed BMP files not supported");
297  was_error = SDL_TRUE;
298  goto done;
299  }
300 
301  /* Create a compatible surface, note that the colors are RGB ordered */
302  surface =
303  SDL_CreateRGBSurface(0, biWidth, biHeight, biBitCount, Rmask, Gmask,
304  Bmask, Amask);
305  if (surface == NULL) {
306  was_error = SDL_TRUE;
307  goto done;
308  }
309 
310  /* Load the palette, if any */
311  palette = (surface->format)->palette;
312  if (palette) {
313  SDL_assert(biBitCount <= 8);
314  if (biClrUsed == 0) {
315  biClrUsed = 1 << biBitCount;
316  }
317  if ((int) biClrUsed > palette->ncolors) {
318  SDL_Color *colors;
319  int ncolors = biClrUsed;
320  colors =
321  (SDL_Color *) SDL_realloc(palette->colors,
322  ncolors *
323  sizeof(*palette->colors));
324  if (!colors) {
325  SDL_OutOfMemory();
326  was_error = SDL_TRUE;
327  goto done;
328  }
329  palette->ncolors = ncolors;
330  palette->colors = colors;
331  } else if ((int) biClrUsed < palette->ncolors) {
332  palette->ncolors = biClrUsed;
333  }
334  if (biSize == 12) {
335  for (i = 0; i < (int) biClrUsed; ++i) {
336  SDL_RWread(src, &palette->colors[i].b, 1, 1);
337  SDL_RWread(src, &palette->colors[i].g, 1, 1);
338  SDL_RWread(src, &palette->colors[i].r, 1, 1);
339  palette->colors[i].a = SDL_ALPHA_OPAQUE;
340  }
341  } else {
342  for (i = 0; i < (int) biClrUsed; ++i) {
343  SDL_RWread(src, &palette->colors[i].b, 1, 1);
344  SDL_RWread(src, &palette->colors[i].g, 1, 1);
345  SDL_RWread(src, &palette->colors[i].r, 1, 1);
346  SDL_RWread(src, &palette->colors[i].a, 1, 1);
347 
348  /* According to Microsoft documentation, the fourth element
349  is reserved and must be zero, so we shouldn't treat it as
350  alpha.
351  */
352  palette->colors[i].a = SDL_ALPHA_OPAQUE;
353  }
354  }
355  }
356 
357  /* Read the surface pixels. Note that the bmp image is upside down */
358  if (SDL_RWseek(src, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
360  was_error = SDL_TRUE;
361  goto done;
362  }
363  top = (Uint8 *)surface->pixels;
364  end = (Uint8 *)surface->pixels+(surface->h*surface->pitch);
365  switch (ExpandBMP) {
366  case 1:
367  bmpPitch = (biWidth + 7) >> 3;
368  pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
369  break;
370  case 4:
371  bmpPitch = (biWidth + 1) >> 1;
372  pad = (((bmpPitch) % 4) ? (4 - ((bmpPitch) % 4)) : 0);
373  break;
374  default:
375  pad = ((surface->pitch % 4) ? (4 - (surface->pitch % 4)) : 0);
376  break;
377  }
378  if (topDown) {
379  bits = top;
380  } else {
381  bits = end - surface->pitch;
382  }
383  while (bits >= top && bits < end) {
384  switch (ExpandBMP) {
385  case 1:
386  case 4:{
387  Uint8 pixel = 0;
388  int shift = (8 - ExpandBMP);
389  for (i = 0; i < surface->w; ++i) {
390  if (i % (8 / ExpandBMP) == 0) {
391  if (!SDL_RWread(src, &pixel, 1, 1)) {
392  SDL_SetError("Error reading from BMP");
393  was_error = SDL_TRUE;
394  goto done;
395  }
396  }
397  *(bits + i) = (pixel >> shift);
398  pixel <<= ExpandBMP;
399  }
400  }
401  break;
402 
403  default:
404  if (SDL_RWread(src, bits, 1, surface->pitch)
405  != surface->pitch) {
407  was_error = SDL_TRUE;
408  goto done;
409  }
410 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
411  /* Byte-swap the pixels if needed. Note that the 24bpp
412  case has already been taken care of above. */
413  switch (biBitCount) {
414  case 15:
415  case 16:{
416  Uint16 *pix = (Uint16 *) bits;
417  for (i = 0; i < surface->w; i++)
418  pix[i] = SDL_Swap16(pix[i]);
419  break;
420  }
421 
422  case 32:{
423  Uint32 *pix = (Uint32 *) bits;
424  for (i = 0; i < surface->w; i++)
425  pix[i] = SDL_Swap32(pix[i]);
426  break;
427  }
428  }
429 #endif
430  break;
431  }
432  /* Skip padding bytes, ugh */
433  if (pad) {
434  Uint8 padbyte;
435  for (i = 0; i < pad; ++i) {
436  SDL_RWread(src, &padbyte, 1, 1);
437  }
438  }
439  if (topDown) {
440  bits += surface->pitch;
441  } else {
442  bits -= surface->pitch;
443  }
444  }
445  if (correctAlpha) {
446  CorrectAlphaChannel(surface);
447  }
448  done:
449  if (was_error) {
450  if (src) {
451  SDL_RWseek(src, fp_offset, RW_SEEK_SET);
452  }
453  SDL_FreeSurface(surface);
454  surface = NULL;
455  }
456  if (freesrc && src) {
457  SDL_RWclose(src);
458  }
459  return (surface);
460 }
461 
462 int
463 SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
464 {
465  Sint64 fp_offset;
466  int i, pad;
468  Uint8 *bits;
469  SDL_bool save32bit = SDL_FALSE;
470  SDL_bool saveLegacyBMP = SDL_FALSE;
471 
472  /* The Win32 BMP file header (14 bytes) */
473  char magic[2] = { 'B', 'M' };
474  Uint32 bfSize;
475  Uint16 bfReserved1;
476  Uint16 bfReserved2;
477  Uint32 bfOffBits;
478 
479  /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
480  Uint32 biSize;
481  Sint32 biWidth;
482  Sint32 biHeight;
483  Uint16 biPlanes;
484  Uint16 biBitCount;
485  Uint32 biCompression;
486  Uint32 biSizeImage;
487  Sint32 biXPelsPerMeter;
488  Sint32 biYPelsPerMeter;
489  Uint32 biClrUsed;
490  Uint32 biClrImportant;
491 
492  /* The additional header members from the Win32 BITMAPV4HEADER struct (108 bytes in total) */
493  Uint32 bV4RedMask = 0;
494  Uint32 bV4GreenMask = 0;
495  Uint32 bV4BlueMask = 0;
496  Uint32 bV4AlphaMask = 0;
497  Uint32 bV4CSType = 0;
498  Sint32 bV4Endpoints[3 * 3] = {0};
499  Uint32 bV4GammaRed = 0;
500  Uint32 bV4GammaGreen = 0;
501  Uint32 bV4GammaBlue = 0;
502 
503  /* Make sure we have somewhere to save */
504  surface = NULL;
505  if (dst) {
506 #ifdef SAVE_32BIT_BMP
507  /* We can save alpha information in a 32-bit BMP */
508  if (saveme->format->BitsPerPixel >= 8 && (saveme->format->Amask ||
509  saveme->map->info.flags & SDL_COPY_COLORKEY)) {
510  save32bit = SDL_TRUE;
511  }
512 #endif /* SAVE_32BIT_BMP */
513 
514  if (saveme->format->palette && !save32bit) {
515  if (saveme->format->BitsPerPixel == 8) {
516  surface = saveme;
517  } else {
518  SDL_SetError("%d bpp BMP files not supported",
519  saveme->format->BitsPerPixel);
520  }
521  } else if ((saveme->format->BitsPerPixel == 24) && !save32bit &&
523  (saveme->format->Rmask == 0x00FF0000) &&
524  (saveme->format->Gmask == 0x0000FF00) &&
525  (saveme->format->Bmask == 0x000000FF)
526 #else
527  (saveme->format->Rmask == 0x000000FF) &&
528  (saveme->format->Gmask == 0x0000FF00) &&
529  (saveme->format->Bmask == 0x00FF0000)
530 #endif
531  ) {
532  surface = saveme;
533  } else {
535 
536  /* If the surface has a colorkey or alpha channel we'll save a
537  32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
538  if (save32bit) {
540  } else {
542  }
543  surface = SDL_ConvertSurface(saveme, &format, 0);
544  if (!surface) {
545  SDL_SetError("Couldn't convert image to %d bpp",
546  format.BitsPerPixel);
547  }
548  }
549  } else {
550  /* Set no error here because it may overwrite a more useful message from
551  SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
552  return -1;
553  }
554 
555  if (save32bit) {
557  }
558 
559  if (surface && (SDL_LockSurface(surface) == 0)) {
560  const int bw = surface->w * surface->format->BytesPerPixel;
561 
562  /* Set the BMP file header values */
563  bfSize = 0; /* We'll write this when we're done */
564  bfReserved1 = 0;
565  bfReserved2 = 0;
566  bfOffBits = 0; /* We'll write this when we're done */
567 
568  /* Write the BMP file header values */
569  fp_offset = SDL_RWtell(dst);
570  SDL_ClearError();
571  SDL_RWwrite(dst, magic, 2, 1);
572  SDL_WriteLE32(dst, bfSize);
573  SDL_WriteLE16(dst, bfReserved1);
574  SDL_WriteLE16(dst, bfReserved2);
575  SDL_WriteLE32(dst, bfOffBits);
576 
577  /* Set the BMP info values */
578  biSize = 40;
579  biWidth = surface->w;
580  biHeight = surface->h;
581  biPlanes = 1;
582  biBitCount = surface->format->BitsPerPixel;
583  biCompression = BI_RGB;
584  biSizeImage = surface->h * surface->pitch;
585  biXPelsPerMeter = 0;
586  biYPelsPerMeter = 0;
587  if (surface->format->palette) {
588  biClrUsed = surface->format->palette->ncolors;
589  } else {
590  biClrUsed = 0;
591  }
592  biClrImportant = 0;
593 
594  /* Set the BMP info values for the version 4 header */
595  if (save32bit && !saveLegacyBMP) {
596  biSize = 108;
597  biCompression = BI_BITFIELDS;
598  /* The BMP format is always little endian, these masks stay the same */
599  bV4RedMask = 0x00ff0000;
600  bV4GreenMask = 0x0000ff00;
601  bV4BlueMask = 0x000000ff;
602  bV4AlphaMask = 0xff000000;
603  bV4CSType = LCS_WINDOWS_COLOR_SPACE;
604  bV4GammaRed = 0;
605  bV4GammaGreen = 0;
606  bV4GammaBlue = 0;
607  }
608 
609  /* Write the BMP info values */
610  SDL_WriteLE32(dst, biSize);
611  SDL_WriteLE32(dst, biWidth);
612  SDL_WriteLE32(dst, biHeight);
613  SDL_WriteLE16(dst, biPlanes);
614  SDL_WriteLE16(dst, biBitCount);
615  SDL_WriteLE32(dst, biCompression);
616  SDL_WriteLE32(dst, biSizeImage);
617  SDL_WriteLE32(dst, biXPelsPerMeter);
618  SDL_WriteLE32(dst, biYPelsPerMeter);
619  SDL_WriteLE32(dst, biClrUsed);
620  SDL_WriteLE32(dst, biClrImportant);
621 
622  /* Write the BMP info values for the version 4 header */
623  if (save32bit && !saveLegacyBMP) {
624  SDL_WriteLE32(dst, bV4RedMask);
625  SDL_WriteLE32(dst, bV4GreenMask);
626  SDL_WriteLE32(dst, bV4BlueMask);
627  SDL_WriteLE32(dst, bV4AlphaMask);
628  SDL_WriteLE32(dst, bV4CSType);
629  for (i = 0; i < 3 * 3; i++) {
630  SDL_WriteLE32(dst, bV4Endpoints[i]);
631  }
632  SDL_WriteLE32(dst, bV4GammaRed);
633  SDL_WriteLE32(dst, bV4GammaGreen);
634  SDL_WriteLE32(dst, bV4GammaBlue);
635  }
636 
637  /* Write the palette (in BGR color order) */
638  if (surface->format->palette) {
639  SDL_Color *colors;
640  int ncolors;
641 
642  colors = surface->format->palette->colors;
643  ncolors = surface->format->palette->ncolors;
644  for (i = 0; i < ncolors; ++i) {
645  SDL_RWwrite(dst, &colors[i].b, 1, 1);
646  SDL_RWwrite(dst, &colors[i].g, 1, 1);
647  SDL_RWwrite(dst, &colors[i].r, 1, 1);
648  SDL_RWwrite(dst, &colors[i].a, 1, 1);
649  }
650  }
651 
652  /* Write the bitmap offset */
653  bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
654  if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
656  }
657  SDL_WriteLE32(dst, bfOffBits);
658  if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
660  }
661 
662  /* Write the bitmap image upside down */
663  bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
664  pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
665  while (bits > (Uint8 *) surface->pixels) {
666  bits -= surface->pitch;
667  if (SDL_RWwrite(dst, bits, 1, bw) != bw) {
669  break;
670  }
671  if (pad) {
672  const Uint8 padbyte = 0;
673  for (i = 0; i < pad; ++i) {
674  SDL_RWwrite(dst, &padbyte, 1, 1);
675  }
676  }
677  }
678 
679  /* Write the BMP file size */
680  bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
681  if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
683  }
684  SDL_WriteLE32(dst, bfSize);
685  if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) {
687  }
688 
689  /* Close it up.. */
690  SDL_UnlockSurface(surface);
691  if (surface != saveme) {
692  SDL_FreeSurface(surface);
693  }
694  }
695 
696  if (freedst && dst) {
697  SDL_RWclose(dst);
698  }
699  return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
700 }
701 
702 /* 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:463
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