SDL_image: Use 8-bit surface with grayscale palette for grayscale images

From e67e06b7d44ab700a1b68aca9f28aa28e1d2fa02 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 29 Jul 2022 22:14:07 -0700
Subject: [PATCH] Use 8-bit surface with grayscale palette for grayscale images

Fixes https://github.com/libsdl-org/SDL_image/issues/294
---
 IMG_stb.c | 58 +++++++++++++++++++++++++++++--------------------------
 1 file changed, 31 insertions(+), 27 deletions(-)

diff --git a/IMG_stb.c b/IMG_stb.c
index 79826381..d4864ee4 100644
--- a/IMG_stb.c
+++ b/IMG_stb.c
@@ -113,16 +113,30 @@ SDL_Surface *IMG_LoadSTB_RW(SDL_RWops *src)
         return NULL;
     }
 
-    if (format == STBI_rgb || format == STBI_rgb_alpha) {
+    if (format == STBI_grey || format == STBI_rgb || format == STBI_rgb_alpha) {
         surface = SDL_CreateRGBSurfaceWithFormatFrom(
             pixels,
             w,
             h,
             8 * format,
             w * format,
-            (format == STBI_rgb) ? SDL_PIXELFORMAT_RGB24 : SDL_PIXELFORMAT_RGBA32
+            (format == STBI_rgb_alpha) ? SDL_PIXELFORMAT_RGBA32 :
+            (format == STBI_rgb) ? SDL_PIXELFORMAT_RGB24 :
+            SDL_PIXELFORMAT_INDEX8
         );
         if (surface) {
+            /* Set a grayscale palette for gray images */
+            SDL_Palette *palette = surface->format->palette;
+            if (palette) {
+                int i;
+
+                for (i = 0; i < palette->ncolors; i++) {
+                    palette->colors[i].r = (Uint8)i;
+                    palette->colors[i].g = (Uint8)i;
+                    palette->colors[i].b = (Uint8)i;
+                }
+            }
+
             /* FIXME: This sucks. It'd be better to allocate the surface first, then
              * write directly to the pixel buffer:
              * https://github.com/nothings/stb/issues/58
@@ -131,45 +145,35 @@ SDL_Surface *IMG_LoadSTB_RW(SDL_RWops *src)
             surface->flags &= ~SDL_PREALLOC;
         }
 
-    } else if (format == STBI_grey || format == STBI_grey_alpha) {
+    } else if (format == STBI_grey_alpha) {
         surface = SDL_CreateRGBSurfaceWithFormat(
             0,
             w,
             h,
-            8 * (2 + format),
-            (format == STBI_grey) ? SDL_PIXELFORMAT_RGB24 : SDL_PIXELFORMAT_RGBA32
+            32,
+            SDL_PIXELFORMAT_RGBA32
         );
         if (surface) {
             Uint8 *src = pixels;
             Uint8 *dst = (Uint8 *)surface->pixels;
-            int skip = surface->pitch - (surface->w * (2 + format));
+            int skip = surface->pitch - (surface->w * 4);
             int row, col;
 
-            if (format == STBI_grey) {
-                for (row = 0; row < h; ++row) {
-                    for (col = 0; col < w; ++col) {
-                        Uint8 c = *src++;
-                        *dst++ = c;
-                        *dst++ = c;
-                        *dst++ = c;
-                    }
-                    dst += skip;
-                }
-            } else {
-                for (row = 0; row < h; ++row) {
-                    for (col = 0; col < w; ++col) {
-                        Uint8 c = *src++;
-                        Uint8 a = *src++;
-                        *dst++ = c;
-                        *dst++ = c;
-                        *dst++ = c;
-                        *dst++ = a;
-                    }
-                    dst += skip;
+            for (row = 0; row < h; ++row) {
+                for (col = 0; col < w; ++col) {
+                    Uint8 c = *src++;
+                    Uint8 a = *src++;
+                    *dst++ = c;
+                    *dst++ = c;
+                    *dst++ = c;
+                    *dst++ = a;
                 }
+                dst += skip;
             }
             stbi_image_free(pixels);
         }
+    } else {
+        IMG_SetError("Unknown image format: %d", format);
     }
 
     if (!surface) {