SDL_ttf: Convert color images to grayscale if needed

From 95d700dbd4baffbf58f143363398ab9eb019f9ac Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 29 Jan 2025 10:43:37 -0800
Subject: [PATCH] Convert color images to grayscale if needed

Fixes https://github.com/libsdl-org/SDL_ttf/issues/489
---
 src/SDL_ttf.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index aca390da..1f7b5b2f 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -2638,7 +2638,7 @@ static bool Load_Glyph(TTF_Font *font, c_glyph *cached, int want, int translatio
         // Compute pitch: glyph is padded right to be able to read an 'aligned' size expanding on the right
         dst->pitch = dst->width + alignment;
 #if TTF_USE_COLOR
-        if (src->pixel_mode == FT_PIXEL_MODE_BGRA) {
+        if (src->pixel_mode == FT_PIXEL_MODE_BGRA && (want & CACHED_COLOR)) {
             dst->pitch += 3 * dst->width;
         }
 #endif
@@ -2816,7 +2816,27 @@ static bool Load_Glyph(TTF_Font *font, c_glyph *cached, int want, int translatio
                     NORMAL_GRAY4(remainder);
 #if TTF_USE_COLOR
                 } else if (src->pixel_mode == FT_PIXEL_MODE_BGRA) {
-                    SDL_memcpy(dstp, srcp, 4 * src->width);
+                    if (want & CACHED_COLOR) {
+                        SDL_memcpy(dstp, srcp, 4 * src->width);
+                    } else {
+                        // Convert to grayscale
+                        while (quotient--) {
+                            Uint8 r, g, b, a;
+                            b = *srcp++;
+                            g = *srcp++;
+                            r = *srcp++;
+                            a = *srcp++;
+                            if (a != 0) {
+                                // Technically we should do this in linear colorspace
+                                // Y = 0.2126 * R + 0.7152 * G + 0.0722 * B
+                                *dstp++ = 255 - (Uint8)(((int)r * 54) / 255 +
+                                                        ((int)g * 182) / 255 +
+                                                        ((int)b * 18) / 255);
+                            } else {
+                                *dstp++ = 0;
+                            }
+                        }
+                    }
 #endif
                 } else if (src->pixel_mode == FT_PIXEL_MODE_LCD) {
                     while (quotient--) {
@@ -2871,7 +2891,7 @@ static bool Load_Glyph(TTF_Font *font, c_glyph *cached, int want, int translatio
         }
 
 #if TTF_USE_COLOR
-        if (src->pixel_mode == FT_PIXEL_MODE_BGRA) {
+        if (src->pixel_mode == FT_PIXEL_MODE_BGRA && (want & CACHED_COLOR)) {
             dst->is_color = 1;
         } else {
             dst->is_color = 0;