|
|
@@ -591,6 +591,78 @@ done:
|
|
|
return surface;
|
|
|
}
|
|
|
|
|
|
+typedef struct {
|
|
|
+ SDL_Surface *surface;
|
|
|
+ SDL_Surface *intermediate_surface;
|
|
|
+ bool save32bit;
|
|
|
+ bool saveLegacyBMP;
|
|
|
+} BMPSaveState;
|
|
|
+
|
|
|
+static void FreeBMPSaveState(BMPSaveState *state)
|
|
|
+{
|
|
|
+ if (state->intermediate_surface && state->intermediate_surface != state->surface) {
|
|
|
+ SDL_DestroySurface(state->intermediate_surface);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static bool InitBMPSaveState(BMPSaveState *state, SDL_Surface *surface)
|
|
|
+{
|
|
|
+ state->surface = surface;
|
|
|
+ state->intermediate_surface = NULL;
|
|
|
+ state->save32bit = false;
|
|
|
+ state->saveLegacyBMP = false;
|
|
|
+
|
|
|
+ CHECK_PARAM(!SDL_SurfaceValid(surface)) {
|
|
|
+ return SDL_InvalidParamError("surface");
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef SAVE_32BIT_BMP
|
|
|
+ // We can save alpha information in a 32-bit BMP
|
|
|
+ if (SDL_BITSPERPIXEL(surface->format) >= 8 &&
|
|
|
+ (SDL_ISPIXELFORMAT_ALPHA(surface->format) ||
|
|
|
+ (surface->map.info.flags & SDL_COPY_COLORKEY))) {
|
|
|
+ state->save32bit = true;
|
|
|
+ }
|
|
|
+#endif // SAVE_32BIT_BMP
|
|
|
+
|
|
|
+ if (surface->palette && !state->save32bit) {
|
|
|
+ if (SDL_BITSPERPIXEL(surface->format) == 8) {
|
|
|
+ state->intermediate_surface = surface;
|
|
|
+ } else {
|
|
|
+ SDL_SetError("%u bpp BMP files not supported",
|
|
|
+ SDL_BITSPERPIXEL(surface->format));
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ } else if ((surface->format == SDL_PIXELFORMAT_BGR24 && !state->save32bit) ||
|
|
|
+ (surface->format == SDL_PIXELFORMAT_BGRA32 && state->save32bit)) {
|
|
|
+ state->intermediate_surface = surface;
|
|
|
+ } else {
|
|
|
+ SDL_PixelFormat pixel_format;
|
|
|
+
|
|
|
+ /* If the surface has a colorkey or alpha channel we'll save a
|
|
|
+ 32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
|
|
|
+ if (state->save32bit) {
|
|
|
+ pixel_format = SDL_PIXELFORMAT_BGRA32;
|
|
|
+ } else {
|
|
|
+ pixel_format = SDL_PIXELFORMAT_BGR24;
|
|
|
+ }
|
|
|
+ state->intermediate_surface = SDL_ConvertSurface(surface, pixel_format);
|
|
|
+ if (!state->intermediate_surface) {
|
|
|
+ SDL_SetError("Couldn't convert image to %d bpp",
|
|
|
+ (int)SDL_BITSPERPIXEL(pixel_format));
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (state->save32bit) {
|
|
|
+ state->saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, false);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+error:
|
|
|
+ FreeBMPSaveState(state);
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
SDL_Surface *SDL_LoadBMP(const char *file)
|
|
|
{
|
|
|
SDL_IOStream *stream = SDL_IOFromFile(file, "rb");
|
|
|
@@ -599,16 +671,12 @@ SDL_Surface *SDL_LoadBMP(const char *file)
|
|
|
}
|
|
|
return SDL_LoadBMP_IO(stream, true);
|
|
|
}
|
|
|
-
|
|
|
-bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
|
|
|
+static bool SDL_SaveBMP_IO_Internal(BMPSaveState *state, SDL_IOStream *dst, bool closeio)
|
|
|
{
|
|
|
bool was_error = true;
|
|
|
Sint64 fp_offset, new_offset;
|
|
|
int i, pad;
|
|
|
- SDL_Surface *intermediate_surface = NULL;
|
|
|
Uint8 *bits;
|
|
|
- bool save32bit = false;
|
|
|
- bool saveLegacyBMP = false;
|
|
|
|
|
|
// The Win32 BMP file header (14 bytes)
|
|
|
char magic[2] = { 'B', 'M' };
|
|
|
@@ -647,60 +715,8 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
|
|
|
Uint32 bV5ProfileSize = 0;
|
|
|
Uint32 bV5Reserved = 0;
|
|
|
|
|
|
- // Make sure we have somewhere to save
|
|
|
- CHECK_PARAM(!SDL_SurfaceValid(surface)) {
|
|
|
- SDL_InvalidParamError("surface");
|
|
|
- goto done;
|
|
|
- }
|
|
|
- CHECK_PARAM(!dst) {
|
|
|
- SDL_InvalidParamError("dst");
|
|
|
- goto done;
|
|
|
- }
|
|
|
-
|
|
|
-#ifdef SAVE_32BIT_BMP
|
|
|
- // We can save alpha information in a 32-bit BMP
|
|
|
- if (SDL_BITSPERPIXEL(surface->format) >= 8 &&
|
|
|
- (SDL_ISPIXELFORMAT_ALPHA(surface->format) ||
|
|
|
- surface->map.info.flags & SDL_COPY_COLORKEY)) {
|
|
|
- save32bit = true;
|
|
|
- }
|
|
|
-#endif // SAVE_32BIT_BMP
|
|
|
-
|
|
|
- if (surface->palette && !save32bit) {
|
|
|
- if (SDL_BITSPERPIXEL(surface->format) == 8) {
|
|
|
- intermediate_surface = surface;
|
|
|
- } else {
|
|
|
- SDL_SetError("%u bpp BMP files not supported",
|
|
|
- SDL_BITSPERPIXEL(surface->format));
|
|
|
- goto done;
|
|
|
- }
|
|
|
- } else if ((surface->format == SDL_PIXELFORMAT_BGR24 && !save32bit) ||
|
|
|
- (surface->format == SDL_PIXELFORMAT_BGRA32 && save32bit)) {
|
|
|
- intermediate_surface = surface;
|
|
|
- } else {
|
|
|
- SDL_PixelFormat pixel_format;
|
|
|
-
|
|
|
- /* If the surface has a colorkey or alpha channel we'll save a
|
|
|
- 32-bit BMP with alpha channel, otherwise save a 24-bit BMP. */
|
|
|
- if (save32bit) {
|
|
|
- pixel_format = SDL_PIXELFORMAT_BGRA32;
|
|
|
- } else {
|
|
|
- pixel_format = SDL_PIXELFORMAT_BGR24;
|
|
|
- }
|
|
|
- intermediate_surface = SDL_ConvertSurface(surface, pixel_format);
|
|
|
- if (!intermediate_surface) {
|
|
|
- SDL_SetError("Couldn't convert image to %d bpp",
|
|
|
- (int)SDL_BITSPERPIXEL(pixel_format));
|
|
|
- goto done;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (save32bit) {
|
|
|
- saveLegacyBMP = SDL_GetHintBoolean(SDL_HINT_BMP_SAVE_LEGACY_FORMAT, false);
|
|
|
- }
|
|
|
-
|
|
|
- if (SDL_LockSurface(intermediate_surface)) {
|
|
|
- const size_t bw = intermediate_surface->w * intermediate_surface->fmt->bytes_per_pixel;
|
|
|
+ if (SDL_LockSurface(state->intermediate_surface)) {
|
|
|
+ const size_t bw = state->intermediate_surface->w * state->intermediate_surface->fmt->bytes_per_pixel;
|
|
|
|
|
|
// Set the BMP file header values
|
|
|
bfSize = 0; // We'll write this when we're done
|
|
|
@@ -723,23 +739,23 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
|
|
|
|
|
|
// Set the BMP info values
|
|
|
biSize = 40;
|
|
|
- biWidth = intermediate_surface->w;
|
|
|
- biHeight = intermediate_surface->h;
|
|
|
+ biWidth = state->intermediate_surface->w;
|
|
|
+ biHeight = state->intermediate_surface->h;
|
|
|
biPlanes = 1;
|
|
|
- biBitCount = intermediate_surface->fmt->bits_per_pixel;
|
|
|
+ biBitCount = state->intermediate_surface->fmt->bits_per_pixel;
|
|
|
biCompression = BI_RGB;
|
|
|
- biSizeImage = intermediate_surface->h * intermediate_surface->pitch;
|
|
|
+ biSizeImage = state->intermediate_surface->h * state->intermediate_surface->pitch;
|
|
|
biXPelsPerMeter = 0;
|
|
|
biYPelsPerMeter = 0;
|
|
|
- if (intermediate_surface->palette) {
|
|
|
- biClrUsed = intermediate_surface->palette->ncolors;
|
|
|
+ if (state->intermediate_surface->palette) {
|
|
|
+ biClrUsed = state->intermediate_surface->palette->ncolors;
|
|
|
} else {
|
|
|
biClrUsed = 0;
|
|
|
}
|
|
|
biClrImportant = 0;
|
|
|
|
|
|
// Set the BMP info values
|
|
|
- if (save32bit && !saveLegacyBMP) {
|
|
|
+ if (state->save32bit && !state->saveLegacyBMP) {
|
|
|
biSize = 124;
|
|
|
// Version 4 values
|
|
|
biCompression = BI_BITFIELDS;
|
|
|
@@ -775,7 +791,7 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
|
|
|
}
|
|
|
|
|
|
// Write the BMP info values
|
|
|
- if (save32bit && !saveLegacyBMP) {
|
|
|
+ if (state->save32bit && !state->saveLegacyBMP) {
|
|
|
// Version 4 values
|
|
|
if (!SDL_WriteU32LE(dst, bV4RedMask) ||
|
|
|
!SDL_WriteU32LE(dst, bV4GreenMask) ||
|
|
|
@@ -804,12 +820,12 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
|
|
|
}
|
|
|
|
|
|
// Write the palette (in BGR color order)
|
|
|
- if (intermediate_surface->palette) {
|
|
|
+ if (state->intermediate_surface->palette) {
|
|
|
SDL_Color *colors;
|
|
|
int ncolors;
|
|
|
|
|
|
- colors = intermediate_surface->palette->colors;
|
|
|
- ncolors = intermediate_surface->palette->ncolors;
|
|
|
+ colors = state->intermediate_surface->palette->colors;
|
|
|
+ ncolors = state->intermediate_surface->palette->ncolors;
|
|
|
for (i = 0; i < ncolors; ++i) {
|
|
|
if (!SDL_WriteU8(dst, colors[i].b) ||
|
|
|
!SDL_WriteU8(dst, colors[i].g) ||
|
|
|
@@ -833,10 +849,10 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
|
|
|
}
|
|
|
|
|
|
// Write the bitmap image upside down
|
|
|
- bits = (Uint8 *)intermediate_surface->pixels + (intermediate_surface->h * intermediate_surface->pitch);
|
|
|
+ bits = (Uint8 *)state->intermediate_surface->pixels + (state->intermediate_surface->h * state->intermediate_surface->pitch);
|
|
|
pad = ((bw % 4) ? (4 - (bw % 4)) : 0);
|
|
|
- while (bits > (Uint8 *)intermediate_surface->pixels) {
|
|
|
- bits -= intermediate_surface->pitch;
|
|
|
+ while (bits > (Uint8 *)state->intermediate_surface->pixels) {
|
|
|
+ bits -= state->intermediate_surface->pitch;
|
|
|
if (SDL_WriteIO(dst, bits, bw) != bw) {
|
|
|
goto done;
|
|
|
}
|
|
|
@@ -867,15 +883,12 @@ bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
|
|
|
}
|
|
|
|
|
|
// Close it up..
|
|
|
- SDL_UnlockSurface(intermediate_surface);
|
|
|
+ SDL_UnlockSurface(state->intermediate_surface);
|
|
|
|
|
|
was_error = false;
|
|
|
}
|
|
|
|
|
|
done:
|
|
|
- if (intermediate_surface && intermediate_surface != surface) {
|
|
|
- SDL_DestroySurface(intermediate_surface);
|
|
|
- }
|
|
|
if (closeio && dst) {
|
|
|
if (!SDL_CloseIO(dst)) {
|
|
|
was_error = true;
|
|
|
@@ -887,11 +900,36 @@ done:
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+bool SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
|
|
|
+{
|
|
|
+ bool result = true;
|
|
|
+ BMPSaveState state;
|
|
|
+ if (!InitBMPSaveState(&state, surface)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ CHECK_PARAM(!dst) {
|
|
|
+ result = SDL_InvalidParamError("dst");
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ result = SDL_SaveBMP_IO_Internal(&state, dst, closeio);
|
|
|
+done:
|
|
|
+ FreeBMPSaveState(&state);
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
bool SDL_SaveBMP(SDL_Surface *surface, const char *file)
|
|
|
{
|
|
|
+ BMPSaveState state;
|
|
|
+ if (!InitBMPSaveState(&state, surface)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
SDL_IOStream *stream = SDL_IOFromFile(file, "wb");
|
|
|
if (!stream) {
|
|
|
return false;
|
|
|
}
|
|
|
- return SDL_SaveBMP_IO(surface, stream, true);
|
|
|
+
|
|
|
+ bool result = SDL_SaveBMP_IO_Internal(&state, stream, true);
|
|
|
+ FreeBMPSaveState(&state);
|
|
|
+ return result;
|
|
|
}
|