SDL 2.0
SDL_bmp.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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) {
81 alpha += 4;
82 }
83 }
84}
85
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);
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 > (Uint32)(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) {
336 int ncolors = biClrUsed;
337 colors =
338 (SDL_Color *) SDL_realloc(palette->colors,
339 ncolors *
340 sizeof(*palette->colors));
341 if (!colors) {
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 bits[i] = (pixel >> shift);
415 if (bits[i] >= biClrUsed) {
416 SDL_SetError("A BMP image contains a pixel with a color out of the palette");
417 was_error = SDL_TRUE;
418 goto done;
419 }
420 pixel <<= ExpandBMP;
421 }
422 }
423 break;
424
425 default:
426 if (SDL_RWread(src, bits, 1, surface->pitch) != surface->pitch) {
428 was_error = SDL_TRUE;
429 goto done;
430 }
431 if (biBitCount == 8 && palette && biClrUsed < (Uint32)(1 << biBitCount)) {
432 for (i = 0; i < surface->w; ++i) {
433 if (bits[i] >= biClrUsed) {
434 SDL_SetError("A BMP image contains a pixel with a color out of the palette");
435 was_error = SDL_TRUE;
436 goto done;
437 }
438 }
439 }
440#if SDL_BYTEORDER == SDL_BIG_ENDIAN
441 /* Byte-swap the pixels if needed. Note that the 24bpp
442 case has already been taken care of above. */
443 switch (biBitCount) {
444 case 15:
445 case 16:{
446 Uint16 *pix = (Uint16 *) bits;
447 for (i = 0; i < surface->w; i++)
448 pix[i] = SDL_Swap16(pix[i]);
449 break;
450 }
451
452 case 32:{
453 Uint32 *pix = (Uint32 *) bits;
454 for (i = 0; i < surface->w; i++)
455 pix[i] = SDL_Swap32(pix[i]);
456 break;
457 }
458 }
459#endif
460 break;
461 }
462 /* Skip padding bytes, ugh */
463 if (pad) {
464 Uint8 padbyte;
465 for (i = 0; i < pad; ++i) {
466 SDL_RWread(src, &padbyte, 1, 1);
467 }
468 }
469 if (topDown) {
470 bits += surface->pitch;
471 } else {
472 bits -= surface->pitch;
473 }
474 }
475 if (correctAlpha) {
477 }
478 done:
479 if (was_error) {
480 if (src) {
481 SDL_RWseek(src, fp_offset, RW_SEEK_SET);
482 }
484 surface = NULL;
485 }
486 if (freesrc && src) {
488 }
489 return (surface);
490}
491
492int
493SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst)
494{
495 Sint64 fp_offset;
496 int i, pad;
498 Uint8 *bits;
499 SDL_bool save32bit = SDL_FALSE;
500 SDL_bool saveLegacyBMP = SDL_FALSE;
501
502 /* The Win32 BMP file header (14 bytes) */
503 char magic[2] = { 'B', 'M' };
504 Uint32 bfSize;
505 Uint16 bfReserved1;
506 Uint16 bfReserved2;
507 Uint32 bfOffBits;
508
509 /* The Win32 BITMAPINFOHEADER struct (40 bytes) */
510 Uint32 biSize;
511 Sint32 biWidth;
512 Sint32 biHeight;
513 Uint16 biPlanes;
514 Uint16 biBitCount;
515 Uint32 biCompression;
516 Uint32 biSizeImage;
517 Sint32 biXPelsPerMeter;
518 Sint32 biYPelsPerMeter;
519 Uint32 biClrUsed;
520 Uint32 biClrImportant;
521
522 /* The additional header members from the Win32 BITMAPV4HEADER struct (108 bytes in total) */
523 Uint32 bV4RedMask = 0;
524 Uint32 bV4GreenMask = 0;
525 Uint32 bV4BlueMask = 0;
526 Uint32 bV4AlphaMask = 0;
527 Uint32 bV4CSType = 0;
528 Sint32 bV4Endpoints[3 * 3] = {0};
529 Uint32 bV4GammaRed = 0;
530 Uint32 bV4GammaGreen = 0;
531 Uint32 bV4GammaBlue = 0;
532
533 /* Make sure we have somewhere to save */
534 surface = NULL;
535 if (dst) {
536#ifdef SAVE_32BIT_BMP
537 /* We can save alpha information in a 32-bit BMP */
538 if (saveme->format->BitsPerPixel >= 8 && (saveme->format->Amask ||
539 saveme->map->info.flags & SDL_COPY_COLORKEY)) {
540 save32bit = SDL_TRUE;
541 }
542#endif /* SAVE_32BIT_BMP */
543
544 if (saveme->format->palette && !save32bit) {
545 if (saveme->format->BitsPerPixel == 8) {
546 surface = saveme;
547 } else {
548 SDL_SetError("%d bpp BMP files not supported",
549 saveme->format->BitsPerPixel);
550 }
551 } else if ((saveme->format->BitsPerPixel == 24) && !save32bit &&
553 (saveme->format->Rmask == 0x00FF0000) &&
554 (saveme->format->Gmask == 0x0000FF00) &&
555 (saveme->format->Bmask == 0x000000FF)
556#else
557 (saveme->format->Rmask == 0x000000FF) &&
558 (saveme->format->Gmask == 0x0000FF00) &&
559 (saveme->format->Bmask == 0x00FF0000)
560#endif
561 ) {
562 surface = saveme;
563 } else {
565
566 /* If the surface has a colorkey or alpha channel we'll save a
567 32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
568 if (save32bit) {
570 } else {
572 }
573 surface = SDL_ConvertSurface(saveme, &format, 0);
574 if (!surface) {
575 SDL_SetError("Couldn't convert image to %d bpp",
576 format.BitsPerPixel);
577 }
578 }
579 } else {
580 /* Set no error here because it may overwrite a more useful message from
581 SDL_RWFromFile() if SDL_SaveBMP_RW() is called from SDL_SaveBMP(). */
582 return -1;
583 }
584
585 if (save32bit) {
587 }
588
589 if (surface && (SDL_LockSurface(surface) == 0)) {
590 const int bw = surface->w * surface->format->BytesPerPixel;
591
592 /* Set the BMP file header values */
593 bfSize = 0; /* We'll write this when we're done */
594 bfReserved1 = 0;
595 bfReserved2 = 0;
596 bfOffBits = 0; /* We'll write this when we're done */
597
598 /* Write the BMP file header values */
599 fp_offset = SDL_RWtell(dst);
601 SDL_RWwrite(dst, magic, 2, 1);
602 SDL_WriteLE32(dst, bfSize);
603 SDL_WriteLE16(dst, bfReserved1);
604 SDL_WriteLE16(dst, bfReserved2);
605 SDL_WriteLE32(dst, bfOffBits);
606
607 /* Set the BMP info values */
608 biSize = 40;
609 biWidth = surface->w;
610 biHeight = surface->h;
611 biPlanes = 1;
612 biBitCount = surface->format->BitsPerPixel;
613 biCompression = BI_RGB;
614 biSizeImage = surface->h * surface->pitch;
615 biXPelsPerMeter = 0;
616 biYPelsPerMeter = 0;
617 if (surface->format->palette) {
618 biClrUsed = surface->format->palette->ncolors;
619 } else {
620 biClrUsed = 0;
621 }
622 biClrImportant = 0;
623
624 /* Set the BMP info values for the version 4 header */
625 if (save32bit && !saveLegacyBMP) {
626 biSize = 108;
627 biCompression = BI_BITFIELDS;
628 /* The BMP format is always little endian, these masks stay the same */
629 bV4RedMask = 0x00ff0000;
630 bV4GreenMask = 0x0000ff00;
631 bV4BlueMask = 0x000000ff;
632 bV4AlphaMask = 0xff000000;
633 bV4CSType = LCS_WINDOWS_COLOR_SPACE;
634 bV4GammaRed = 0;
635 bV4GammaGreen = 0;
636 bV4GammaBlue = 0;
637 }
638
639 /* Write the BMP info values */
640 SDL_WriteLE32(dst, biSize);
641 SDL_WriteLE32(dst, biWidth);
642 SDL_WriteLE32(dst, biHeight);
643 SDL_WriteLE16(dst, biPlanes);
644 SDL_WriteLE16(dst, biBitCount);
645 SDL_WriteLE32(dst, biCompression);
646 SDL_WriteLE32(dst, biSizeImage);
647 SDL_WriteLE32(dst, biXPelsPerMeter);
648 SDL_WriteLE32(dst, biYPelsPerMeter);
649 SDL_WriteLE32(dst, biClrUsed);
650 SDL_WriteLE32(dst, biClrImportant);
651
652 /* Write the BMP info values for the version 4 header */
653 if (save32bit && !saveLegacyBMP) {
654 SDL_WriteLE32(dst, bV4RedMask);
655 SDL_WriteLE32(dst, bV4GreenMask);
656 SDL_WriteLE32(dst, bV4BlueMask);
657 SDL_WriteLE32(dst, bV4AlphaMask);
658 SDL_WriteLE32(dst, bV4CSType);
659 for (i = 0; i < 3 * 3; i++) {
660 SDL_WriteLE32(dst, bV4Endpoints[i]);
661 }
662 SDL_WriteLE32(dst, bV4GammaRed);
663 SDL_WriteLE32(dst, bV4GammaGreen);
664 SDL_WriteLE32(dst, bV4GammaBlue);
665 }
666
667 /* Write the palette (in BGR color order) */
668 if (surface->format->palette) {
670 int ncolors;
671
672 colors = surface->format->palette->colors;
673 ncolors = surface->format->palette->ncolors;
674 for (i = 0; i < ncolors; ++i) {
675 SDL_RWwrite(dst, &colors[i].b, 1, 1);
676 SDL_RWwrite(dst, &colors[i].g, 1, 1);
677 SDL_RWwrite(dst, &colors[i].r, 1, 1);
678 SDL_RWwrite(dst, &colors[i].a, 1, 1);
679 }
680 }
681
682 /* Write the bitmap offset */
683 bfOffBits = (Uint32)(SDL_RWtell(dst) - fp_offset);
684 if (SDL_RWseek(dst, fp_offset + 10, RW_SEEK_SET) < 0) {
686 }
687 SDL_WriteLE32(dst, bfOffBits);
688 if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) {
690 }
691
692 /* Write the bitmap image upside down */
693 bits = (Uint8 *) surface->pixels + (surface->h * surface->pitch);
694 pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
695 while (bits > (Uint8 *) surface->pixels) {
696 bits -= surface->pitch;
697 if (SDL_RWwrite(dst, bits, 1, bw) != bw) {
699 break;
700 }
701 if (pad) {
702 const Uint8 padbyte = 0;
703 for (i = 0; i < pad; ++i) {
704 SDL_RWwrite(dst, &padbyte, 1, 1);
705 }
706 }
707 }
708
709 /* Write the BMP file size */
710 bfSize = (Uint32)(SDL_RWtell(dst) - fp_offset);
711 if (SDL_RWseek(dst, fp_offset + 2, RW_SEEK_SET) < 0) {
713 }
714 SDL_WriteLE32(dst, bfSize);
715 if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) {
717 }
718
719 /* Close it up.. */
721 if (surface != saveme) {
723 }
724 }
725
726 if (freedst && dst) {
728 }
729 return ((SDL_strcmp(SDL_GetError(), "") == 0) ? 0 : -1);
730}
731
732/* vi: set ts=4 sw=4 expandtab: */
#define SDL_assert(condition)
Definition: SDL_assert.h:169
#define SDL_COPY_COLORKEY
Definition: SDL_blit.h:39
#define BI_BITFIELDS
Definition: SDL_bmp.c:48
int SDL_SaveBMP_RW(SDL_Surface *saveme, SDL_RWops *dst, int freedst)
Definition: SDL_bmp.c:493
#define BI_RGB
Definition: SDL_bmp.c:45
SDL_Surface * SDL_LoadBMP_RW(SDL_RWops *src, int freesrc)
Definition: SDL_bmp.c:87
static void CorrectAlphaChannel(SDL_Surface *surface)
Definition: SDL_bmp.c:57
#define LCS_WINDOWS_COLOR_SPACE
Definition: SDL_bmp.c:54
#define SDL_BYTEORDER
#define SDL_SetError
#define SDL_GetError
#define SDL_ReadLE16
#define SDL_strncmp
#define SDL_ReadLE32
#define SDL_Error
#define SDL_RWwrite
#define SDL_RWtell
#define SDL_WriteLE16
#define SDL_RWread
#define SDL_realloc
#define SDL_RWseek
#define SDL_ClearError
#define SDL_UnlockSurface
#define SDL_strcmp
#define SDL_GetHintBoolean
#define SDL_LockSurface
#define SDL_CreateRGBSurface
#define SDL_FreeSurface
#define SDL_WriteLE32
#define SDL_RWclose
#define SDL_ConvertSurface
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
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
Definition: SDL_endian.h:162
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
Definition: SDL_endian.h:107
#define SDL_LIL_ENDIAN
Definition: SDL_endian.h:37
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
@ SDL_EFSEEK
Definition: SDL_error.h:60
@ SDL_EFWRITE
Definition: SDL_error.h:59
@ SDL_EFREAD
Definition: SDL_error.h:58
#define SDL_HINT_BMP_SAVE_LEGACY_FORMAT
Prevent SDL from using version 4 of the bitmap header when saving BMPs.
Definition: SDL_hints.h:951
GLuint GLuint end
Definition: SDL_opengl.h:1571
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
GLboolean GLboolean GLboolean b
GLdouble GLdouble GLdouble GLdouble top
GLenum src
GLboolean GLboolean GLboolean GLboolean a
GLenum GLenum dst
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
GLboolean GLboolean g
GLfloat GLfloat GLfloat alpha
int SDL_InitFormat(SDL_PixelFormat *format, Uint32 pixel_format)
Definition: SDL_pixels.c:537
#define SDL_ALPHA_OPAQUE
Definition: SDL_pixels.h:46
@ SDL_PIXELFORMAT_BGR24
Definition: SDL_pixels.h:233
@ SDL_PIXELFORMAT_BGRA32
Definition: SDL_pixels.h:273
#define RW_SEEK_CUR
Definition: SDL_rwops.h:175
#define RW_SEEK_SET
Definition: SDL_rwops.h:174
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
uint32_t Uint32
Definition: SDL_stdinc.h:203
int32_t Sint32
Definition: SDL_stdinc.h:197
uint16_t Uint16
Definition: SDL_stdinc.h:191
uint8_t Uint8
Definition: SDL_stdinc.h:179
int64_t Sint64
Definition: SDL_stdinc.h:210
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
int done
Definition: checkkeys.c:28
EGLSurface surface
Definition: eglext.h:248
SDL_BlitInfo info
Definition: SDL_blit.h:92
Uint8 r
Definition: SDL_pixels.h:297
Uint8 b
Definition: SDL_pixels.h:299
Uint8 a
Definition: SDL_pixels.h:300
Uint8 g
Definition: SDL_pixels.h:298
SDL_Color * colors
Definition: SDL_pixels.h:307
Uint8 BitsPerPixel
Definition: SDL_pixels.h:319
SDL_Palette * palette
Definition: SDL_pixels.h:318
A collection of pixels used in software blitting.
Definition: SDL_surface.h:71
SDL_PixelFormat * format
Definition: SDL_surface.h:73
struct SDL_BlitMap * map
Definition: SDL_surface.h:89
static int colors[7]
Definition: testgesture.c:41