Atlas - SDL_bmp.c

Home / ext / SDL2 / src / video Lines: 1 | Size: 23021 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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 57static void CorrectAlphaChannel(SDL_Surface *surface) 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 86SDL_Surface * 87SDL_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; 93 SDL_Surface *surface; 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) { 142 SDL_Error(SDL_EFREAD); 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) { 359 SDL_Error(SDL_EFSEEK); 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) { 406 SDL_Error(SDL_EFREAD); 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 462int 463SDL_SaveBMP_RW(SDL_Surface * saveme, SDL_RWops * dst, int freedst) 464{ 465 Sint64 fp_offset; 466 int i, pad; 467 SDL_Surface *surface; 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 && 522#if SDL_BYTEORDER == SDL_LIL_ENDIAN 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 { 534 SDL_PixelFormat format; 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) { 539 SDL_InitFormat(&format, SDL_PIXELFORMAT_BGRA32); 540 } else { 541 SDL_InitFormat(&format, SDL_PIXELFORMAT_BGR24); 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) { 556 saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, SDL_FALSE); 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) { 655 SDL_Error(SDL_EFSEEK); 656 } 657 SDL_WriteLE32(dst, bfOffBits); 658 if (SDL_RWseek(dst, fp_offset + bfOffBits, RW_SEEK_SET) < 0) { 659 SDL_Error(SDL_EFSEEK); 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) { 668 SDL_Error(SDL_EFWRITE); 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) { 682 SDL_Error(SDL_EFSEEK); 683 } 684 SDL_WriteLE32(dst, bfSize); 685 if (SDL_RWseek(dst, fp_offset + bfSize, RW_SEEK_SET) < 0) { 686 SDL_Error(SDL_EFSEEK); 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: */ 703
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.