SDL: Added support for saving indexed PNG images

From 1fa6475c90de43b378451a2cca785ab9de048f9e Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 23 Oct 2025 12:01:30 -0700
Subject: [PATCH] Added support for saving indexed PNG images

Fixes https://github.com/libsdl-org/SDL/issues/14303
---
 src/video/SDL_stb.c           |  56 +++++++++++++++---
 src/video/miniz.h             |  95 +++++++++++++++++++++++--------
 test/testautomation_surface.c | 104 ++++++++++++++++++++++++++++++----
 3 files changed, 210 insertions(+), 45 deletions(-)

diff --git a/src/video/SDL_stb.c b/src/video/SDL_stb.c
index 43b37412adbd6..1073ba658a7ab 100644
--- a/src/video/SDL_stb.c
+++ b/src/video/SDL_stb.c
@@ -383,6 +383,9 @@ SDL_Surface *SDL_LoadPNG(const char *file)
 bool SDL_SavePNG_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
 {
     bool retval = false;
+    Uint8 *plte = NULL;
+    Uint8 *trns = NULL;
+    bool free_surface = false;
 
     // Make sure we have somewhere to save
     CHECK_PARAM(!SDL_SurfaceValid(surface)) {
@@ -395,17 +398,49 @@ bool SDL_SavePNG_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
     }
 
 #ifdef SDL_HAVE_STB
-    bool free_surface = false;
-    if (surface->format != SDL_PIXELFORMAT_RGBA32) {
-        surface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
-        if (!surface) {
+    int plte_size = 0;
+    int trns_size = 0;
+
+    if (SDL_ISPIXELFORMAT_INDEXED(surface->format)) {
+        if (!surface->palette) {
+            SDL_SetError("Indexed surfaces must have a palette");
+            goto done;
+        }
+
+        if (surface->format != SDL_PIXELFORMAT_INDEX8) {
+            surface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_INDEX8);
+            if (!surface) {
+                goto done;
+            }
+            free_surface = true;
+        }
+
+        plte_size = surface->palette->ncolors * 3;
+        trns_size = surface->palette->ncolors;
+        plte = (Uint8 *)SDL_malloc(plte_size);
+        trns = (Uint8 *)SDL_malloc(trns_size);
+        if (!plte || !trns) {
             goto done;
         }
-        free_surface = true;
+        SDL_Color *colors = surface->palette->colors;
+        for (int i = 0; i < surface->palette->ncolors; ++i) {
+            plte[i * 3 + 0] = colors[i].r;
+            plte[i * 3 + 1] = colors[i].g;
+            plte[i * 3 + 2] = colors[i].b;
+            trns[i] = colors[i].a;
+        }
+    } else {
+        if (surface->format != SDL_PIXELFORMAT_RGBA32) {
+            surface = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32);
+            if (!surface) {
+                goto done;
+            }
+            free_surface = true;
+        }
     }
 
     size_t size = 0;
-    void *png = tdefl_write_image_to_png_file_in_memory(surface->pixels, surface->w, surface->h, SDL_BYTESPERPIXEL(surface->format), surface->pitch, &size);
+    void *png = tdefl_write_image_to_png_file_in_memory_ex(surface->pixels, surface->w, surface->h, SDL_BYTESPERPIXEL(surface->format), surface->pitch, &size, 6, MZ_FALSE, plte, plte_size, trns, trns_size);
     if (png) {
         if (SDL_WriteIO(dst, png, size)) {
             retval = true;
@@ -415,14 +450,17 @@ bool SDL_SavePNG_IO(SDL_Surface *surface, SDL_IOStream *dst, bool closeio)
         SDL_SetError("Failed to convert and save image");
     }
 
-    if (free_surface) {
-        SDL_DestroySurface(surface);
-    }
 #else
     SDL_SetError("SDL not built with STB image support");
 #endif
 
 done:
+    if (free_surface) {
+        SDL_DestroySurface(surface);
+    }
+    SDL_free(plte);
+    SDL_free(trns);
+
     if (dst && closeio) {
         retval &= SDL_CloseIO(dst);
     }
diff --git a/src/video/miniz.h b/src/video/miniz.h
index 4be4c73809a3d..95c67c4eb9af4 100644
--- a/src/video/miniz.h
+++ b/src/video/miniz.h
@@ -875,8 +875,10 @@ MINIZ_STATIC size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len
 //  Function returns a pointer to the compressed data, or NULL on failure.
 //  *pLen_out will be set to the size of the PNG image file.
 //  The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed.
-MINIZ_STATIC void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, int bpl, size_t *pLen_out, mz_uint level, mz_bool flip);
+MINIZ_STATIC void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, int bpl, size_t *pLen_out, mz_uint level, mz_bool flip, mz_uint8 *plte, int plte_size, mz_uint8 *trns, int trns_size);
+#ifndef MINIZ_SDL_NOUNUSED
 MINIZ_STATIC void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, int bpl, size_t *pLen_out);
+#endif
 
 // Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
 typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
@@ -2911,29 +2913,27 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int
 // Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at
 // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
 // This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck.
-MINIZ_STATIC void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, int bpl, size_t *pLen_out, mz_uint level, mz_bool flip)
+MINIZ_STATIC void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, int bpl, size_t *pLen_out, mz_uint level, mz_bool flip, mz_uint8 *plte, int plte_size, mz_uint8 *trns, int trns_size)
 {
   // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined.
   static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32,  16, 32, 128, 256,  512, 768, 1500 };
-  tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, y, z; mz_uint32 c; *pLen_out = 0;
+  tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, y, z = 0; mz_uint32 c; *pLen_out = 0; size_t data_start, data_size;
   if (!pComp) return NULL;
-  MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; }
-  // write dummy header
-  for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
-  // compress image data
-  tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
-  for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); }
-  if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
-  // write real header
-  *pLen_out = out_buf.m_size-41;
+  MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE;
+  out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h);
+  if (plte_size > 0)
+    out_buf.m_capacity += 12+plte_size;
+  if (trns_size > 0)
+    out_buf.m_capacity += 12+trns_size;
+  if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; }
+  // write header
   {
     static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
 
-    mz_uint8 pnghdr[41]={ 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,
+    mz_uint8 pnghdr[33]={ 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,
                           0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
                           0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-                          0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-                          0x00,0x00,0x00,0x00,0x49,0x44,0x41,0x54};
+                          0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 
     pnghdr[18] = (mz_uint8)(w>>8);
     pnghdr[19] = (mz_uint8)(w>>0);
@@ -2941,31 +2941,76 @@ MINIZ_STATIC void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage
     pnghdr[22] = (mz_uint8)(h>>8);
     pnghdr[23] = (mz_uint8)(h>>0);
 
-    pnghdr[25] = (chans[num_chans]);
-
-    pnghdr[33] = (mz_uint8)(*pLen_out>>24);
-    pnghdr[34] = (mz_uint8)(*pLen_out>>16);
-    pnghdr[35] = (mz_uint8)(*pLen_out>> 8);
-    pnghdr[36] = (mz_uint8)(*pLen_out>> 0);
+    if (num_chans == 1 && plte_size > 0)
+      pnghdr[25] = 3;
+    else
+      pnghdr[25] = (chans[num_chans]);
 
     c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17);
     for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i] = (mz_uint8)(c>>24);
-    memcpy(out_buf.m_pBuf, pnghdr, 41);
+    if (!tdefl_output_buffer_putter(pnghdr, sizeof(pnghdr), &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+  }
+  // write PLTE chunk
+  if (plte_size > 0)
+  {
+    mz_uint8 hdr[8]={0x00,0x00,0x00,0x00,0x50,0x4c,0x54,0x45};
+
+    hdr[0] = (mz_uint8)(plte_size>>24);
+    hdr[1] = (mz_uint8)(plte_size>>16);
+    hdr[2] = (mz_uint8)(plte_size>> 8);
+    hdr[3] = (mz_uint8)(plte_size>> 0);
+    if (!tdefl_output_buffer_putter(hdr, sizeof(hdr), &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+    data_start = out_buf.m_size;
+    if (!tdefl_output_buffer_putter(plte, plte_size, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+    if (!tdefl_output_buffer_putter("\0\0\0\0", 4, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+    c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+data_start-4, plte_size+4);
+    for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-4)[i] = (mz_uint8)(c >> 24);
+  }
+  // write tRNS chunk
+  if (trns_size > 0)
+  {
+    mz_uint8 hdr[8]={0x00,0x00,0x00,0x00,0x74,0x52,0x4E,0x53};
+
+    hdr[0] = (mz_uint8)(trns_size>>24);
+    hdr[1] = (mz_uint8)(trns_size>>16);
+    hdr[2] = (mz_uint8)(trns_size>> 8);
+    hdr[3] = (mz_uint8)(trns_size>> 0);
+    if (!tdefl_output_buffer_putter(hdr, sizeof(hdr), &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+    data_start = out_buf.m_size;
+    if (!tdefl_output_buffer_putter(trns, trns_size, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+    if (!tdefl_output_buffer_putter("\0\0\0\0", 4, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+    c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+data_start-4, trns_size+4);
+    for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-4)[i] = (mz_uint8)(c >> 24);
   }
+  // write IDAT chunk
+  if (!tdefl_output_buffer_putter("\0\0\0\0\x49\x44\x41\x54", 8, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+  data_start = out_buf.m_size;
+  // compress image data
+  tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
+  for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); }
+  if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
+  // write IDAT size
+  data_size = out_buf.m_size-data_start;
+  (out_buf.m_pBuf+data_start-8)[0] = (mz_uint8)(data_size>>24);
+  (out_buf.m_pBuf+data_start-8)[1] = (mz_uint8)(data_size>>16);
+  (out_buf.m_pBuf+data_start-8)[2] = (mz_uint8)(data_size>> 8);
+  (out_buf.m_pBuf+data_start-8)[3] = (mz_uint8)(data_size>> 0);
   // write footer (IDAT CRC-32, followed by IEND chunk)
   if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
-  c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4);
+  c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+data_start-4, data_size+4);
   for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24);
   // compute final size of file, grab compressed data buffer and return
-  *pLen_out += 57;
+  *pLen_out = out_buf.m_size;
   MZ_FREE(pComp);
   return out_buf.m_pBuf;
 }
+#ifndef MINIZ_SDL_NOUNUSED
 MINIZ_STATIC void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, int bpl, size_t *pLen_out)
 {
   // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out)
-  return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, bpl, pLen_out, 6, MZ_FALSE);
+  return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, bpl, pLen_out, 6, MZ_FALSE, NULL, 0, NULL, 0);
 }
+#endif
 
 #ifdef _MSC_VER
 #pragma warning (pop)
diff --git a/test/testautomation_surface.c b/test/testautomation_surface.c
index e1713dbd4af32..ffa170cb908c1 100644
--- a/test/testautomation_surface.c
+++ b/test/testautomation_surface.c
@@ -3,14 +3,6 @@
  * Adapted/rewritten for test lib by Andreas Schiffler
  */
 
-/* Suppress C4996 VS compiler warnings for unlink() */
-#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
-#define _CRT_SECURE_NO_DEPRECATE
-#endif
-#if defined(_MSC_VER) && !defined(_CRT_NONSTDC_NO_DEPRECATE)
-#define _CRT_NONSTDC_NO_DEPRECATE
-#endif
-
 #include <stdio.h>
 #ifndef _MSC_VER
 #include <unistd.h>
@@ -337,6 +329,13 @@ static int SDLCALL surface_testSaveLoad(void *arg)
     const char *sampleFilename = "testSaveLoad.tmp";
     SDL_Surface *face;
     SDL_Surface *rface;
+    SDL_Palette *palette;
+    SDL_Color colors[] = {
+        { 255, 0, 0, SDL_ALPHA_OPAQUE },    /* Red */
+        { 0, 255, 0, SDL_ALPHA_OPAQUE }     /* Green */
+    };
+    SDL_IOStream *stream;
+    Uint8 r, g, b, a;
 
     /* Create sample surface */
     face = SDLTest_ImageFace();
@@ -346,7 +345,7 @@ static int SDLCALL surface_testSaveLoad(void *arg)
     }
 
     /* Delete test file; ignore errors */
-    unlink(sampleFilename);
+    SDL_RemovePath(sampleFilename);
 
     /* Save a BMP surface */
     ret = SDL_SaveBMP(face, sampleFilename);
@@ -366,7 +365,7 @@ static int SDLCALL surface_testSaveLoad(void *arg)
     }
 
     /* Delete test file; ignore errors */
-    unlink(sampleFilename);
+    SDL_RemovePath(sampleFilename);
 
     /* Save a PNG surface */
     ret = SDL_SavePNG(face, sampleFilename);
@@ -386,12 +385,95 @@ static int SDLCALL surface_testSaveLoad(void *arg)
     }
 
     /* Delete test file; ignore errors */
-    unlink(sampleFilename);
+    SDL_RemovePath(sampleFilename);
 
     /* Clean up */
     SDL_DestroySurface(face);
     face = NULL;
 
+    /* Create an 8-bit image */
+    face = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_INDEX8);
+    SDLTest_AssertCheck(face != NULL, "Verify 8-bit surface is not NULL");
+    if (face == NULL) {
+        return TEST_ABORTED;
+    }
+
+    palette = SDL_CreatePalette(2);
+    SDLTest_AssertCheck(palette != NULL, "Verify palette is not NULL");
+    if (palette == NULL) {
+        return TEST_ABORTED;
+    }
+    SDL_SetPaletteColors(palette, colors, 0, SDL_arraysize(colors));
+    SDL_SetSurfacePalette(face, palette);
+    SDL_DestroyPalette(palette);
+
+    /* Set a green pixel */
+    *(Uint8 *)face->pixels = 1;
+
+    /* Save and reload as a BMP */
+    stream = SDL_IOFromDynamicMem();
+    SDLTest_AssertCheck(stream != NULL, "Verify iostream is not NULL");
+    if (stream == NULL) {
+        return TEST_ABORTED;
+    }
+    ret = SDL_SaveBMP_IO(face, stream, false);
+    SDLTest_AssertPass("Call to SDL_SaveBMP()");
+    SDLTest_AssertCheck(ret == true, "Verify result from SDL_SaveBMP, expected: true, got: %i", ret);
+    SDL_SeekIO(stream, 0, SDL_IO_SEEK_SET);
+    rface = SDL_LoadBMP_IO(stream, false);
+    SDLTest_AssertPass("Call to SDL_LoadBMP()");
+    SDLTest_AssertCheck(rface != NULL, "Verify result from SDL_LoadBMP is not NULL");
+    if (rface != NULL) {
+        SDLTest_AssertCheck(face->w == rface->w, "Verify width of loaded surface, expected: %i, got: %i", face->w, rface->w);
+        SDLTest_AssertCheck(face->h == rface->h, "Verify height of loaded surface, expected: %i, got: %i", face->h, rface->h);
+        SDLTest_AssertCheck(rface->format == SDL_PIXELFORMAT_INDEX8, "Verify format of loaded surface, expected: %s, got: %s", SDL_GetPixelFormatName(face->format), SDL_GetPixelFormatName(rface->format));
+        SDL_ReadSurfacePixel(rface, 0, 0, &r, &g, &b, &a);
+        SDLTest_AssertCheck(r == colors[1].r &&
+                            g == colors[1].g &&
+                            b == colors[1].b &&
+                            a == colors[1].a,
+                            "Verify color of loaded surface, expected: %d,%d,%d,%d, got: %d,%d,%d,%d",
+                            r, g, b, a,
+                            colors[1].r, colors[1].g, colors[1].b, colors[1].a);
+        SDL_DestroySurface(rface);
+        rface = NULL;
+    }
+    SDL_CloseIO(stream);
+    stream = NULL;
+
+    /* Save and reload as a PNG */
+    stream = SDL_IOFromDynamicMem();
+    SDLTest_AssertCheck(stream != NULL, "Verify iostream is not NULL");
+    if (stream == NULL) {
+        return TEST_ABORTED;
+    }
+    ret = SDL_SavePNG_IO(face, stream, false);
+    SDLTest_AssertPass("Call to SDL_SavePNG()");
+    SDLTest_AssertCheck(ret == true, "Verify result from SDL_SavePNG, expected: true, got: %i", ret);
+    SDL_SeekIO(stream, 0, SDL_IO_SEEK_SET);
+    rface = SDL_LoadPNG_IO(stream, false);
+    SDLTest_AssertPass("Call to SDL_LoadPNG()");
+    SDLTest_AssertCheck(rface != NULL, "Verify result from SDL_LoadPNG is not NULL");
+    if (rface != NULL) {
+        SDLTest_AssertCheck(face->w == rface->w, "Verify width of loaded surface, expected: %i, got: %i", face->w, rface->w);
+        SDLTest_AssertCheck(face->h == rface->h, "Verify height of loaded surface, expected: %i, got: %i", face->h, rface->h);
+        SDLTest_AssertCheck(rface->format == SDL_PIXELFORMAT_INDEX8, "Verify format of loaded surface, expected: %s, got: %s", SDL_GetPixelFormatName(face->format), SDL_GetPixelFormatName(rface->format));
+        SDL_ReadSurfacePixel(rface, 0, 0, &r, &g, &b, &a);
+        SDLTest_AssertCheck(r == colors[1].r &&
+                            g == colors[1].g &&
+                            b == colors[1].b &&
+                            a == colors[1].a,
+                            "Verify color of loaded surface, expected: %d,%d,%d,%d, got: %d,%d,%d,%d",
+                            r, g, b, a,
+                            colors[1].r, colors[1].g, colors[1].b, colors[1].a);
+        SDL_DestroySurface(rface);
+        rface = NULL;
+    }
+    SDL_CloseIO(stream);
+    stream = NULL;
+
+    SDL_DestroySurface(face);
+
     return TEST_COMPLETED;
 }