shithub: rgbds

Download patch

ref: b8af100c637cf7c6eae2ab1f17f12df6714afc30
parent: 30759453670ba7e6e6119236826fd5af4fe14a0a
author: obskyr <powpowd@gmail.com>
date: Thu Feb 15 10:03:19 EST 2018

Handle grayscale images as expected

Signed-off-by: obskyr <powpowd@gmail.com>

--- a/src/gfx/makepng.c
+++ b/src/gfx/makepng.c
@@ -18,7 +18,7 @@
 static struct RawIndexedImage *grayscale_png_to_raw(struct PNGImage *img);
 static struct RawIndexedImage *truecolor_png_to_raw(struct PNGImage *img);
 static void get_text(const struct PNGImage *img,
-                     struct ImageOptions* png_options);
+                     struct ImageOptions *png_options);
 static void set_text(const struct PNGImage *img,
                      const struct ImageOptions *png_options);
 static void free_png_data(const struct PNGImage *png);
@@ -333,19 +333,9 @@
 	               PNG_USER_WILL_FREE_DATA, PNG_FREE_PLTE);
 }
 
-/* A combined struct is needed to sort colors in order of luminance. */
-struct ColorWithLuminance {
-	png_color color;
-	int luminance;
-};
+static int fit_grayscale_palette(png_color *palette, int *num_colors);
+static void order_color_palette(png_color *palette, int num_colors);
 
-static int compare_luminance(const void *a,const void *b)
-{
-	struct ColorWithLuminance *x = (struct ColorWithLuminance *) a;
-	struct ColorWithLuminance *y = (struct ColorWithLuminance *) b;
-	return y->luminance - x->luminance;
-}
-
 static void rgba_build_palette(struct PNGImage *img,
 							   png_color **palette_ptr_ptr, int *num_colors)
 {
@@ -353,9 +343,9 @@
 	int y, value_index, i;
 	png_color cur_pixel_color;
 	png_byte cur_alpha;
+	bool only_grayscale = true;
 	bool color_exists;
 	png_color cur_palette_color;
-	struct ColorWithLuminance *palette_with_luminance;
 
 	/*
 	 * By filling the palette up with black by default, if the image
@@ -381,6 +371,12 @@
 				continue;
 			}
 
+			if (only_grayscale &&
+			    !(cur_pixel_color.red == cur_pixel_color.green &&
+				  cur_pixel_color.red == cur_pixel_color.blue)) {
+				only_grayscale = false;
+			}
+
 			color_exists = false;
 			for (i = 0; i < *num_colors; i++) {
 				cur_palette_color = palette[i];
@@ -402,9 +398,79 @@
 		}
 	}
 
-	palette_with_luminance =
-		malloc(sizeof(struct ColorWithLuminance) * colors);
+	/* In order not to count 100% transparent images as grayscale. */
+	only_grayscale = *num_colors ? only_grayscale : false;
+
+	if (!only_grayscale || !fit_grayscale_palette(palette, num_colors)) {
+		order_color_palette(palette, *num_colors);
+	}
+}
+
+static int fit_grayscale_palette(png_color *palette, int *num_colors)
+{
+	int i, shade_index;
+	int interval = 256 / colors;
+	png_color *fitted_palette = malloc(sizeof(png_color) * colors);
+	bool *set_indices = calloc(colors, sizeof(bool));
+
+	fitted_palette[0].red   = 0xFF;
+	fitted_palette[0].green = 0xFF;
+	fitted_palette[0].blue  = 0xFF;
+	fitted_palette[colors - 1].red   = 0;
+	fitted_palette[colors - 1].green = 0;
+	fitted_palette[colors - 1].blue  = 0;
+	if (colors == 4) {
+		fitted_palette[1].red   = 0xA9;
+		fitted_palette[1].green = 0xA9;
+		fitted_palette[1].blue  = 0xA9;
+		fitted_palette[2].red   = 0x55;
+		fitted_palette[2].green = 0x55;
+		fitted_palette[2].blue  = 0x55;
+	}
+
+	for (i = 0; i < *num_colors; i++) {
+		shade_index = colors - 1 - palette[i].red / interval;
+		if (set_indices[shade_index]) {
+			free(fitted_palette);
+			free(set_indices);
+			return false;
+		}
+		fitted_palette[shade_index] = palette[i];
+		set_indices[shade_index] = true;
+	}
+
 	for (i = 0; i < colors; i++) {
+		palette[i] = fitted_palette[i];
+	}
+
+	*num_colors = colors;
+
+	free(fitted_palette);
+	free(set_indices);
+	return true;
+}
+
+/* A combined struct is needed to sort csolors in order of luminance. */
+struct ColorWithLuminance {
+	png_color color;
+	int luminance;
+};
+
+static int compare_luminance(const void *a, const void *b)
+{
+	struct ColorWithLuminance *x = (struct ColorWithLuminance *) a;
+	struct ColorWithLuminance *y = (struct ColorWithLuminance *) b;
+	return y->luminance - x->luminance;
+}
+
+static void order_color_palette(png_color *palette, int num_colors)
+{
+	int i;
+	struct ColorWithLuminance *palette_with_luminance;
+
+	palette_with_luminance =
+		malloc(sizeof(struct ColorWithLuminance) * num_colors);
+	for (i = 0; i < num_colors; i++) {
 		/*
 		 * Normally this would be done with floats, but since it's only
 		 * used for comparison, we might as well use integer math.
@@ -414,9 +480,9 @@
 		                                      7152 * palette[i].green +
 											   722 * palette[i].blue;
 	}
-	qsort(palette_with_luminance, colors,
+	qsort(palette_with_luminance, num_colors,
 			sizeof(struct ColorWithLuminance), compare_luminance);
-	for (i = 0; i < colors; i++) {
+	for (i = 0; i < num_colors; i++) {
 		palette[i] = palette_with_luminance[i].color;
 	}
 	free(palette_with_luminance);
@@ -538,7 +604,7 @@
 }
 
 static void get_text(const struct PNGImage *img,
-                     struct ImageOptions* png_options)
+                     struct ImageOptions *png_options)
 {
 	png_text *text;
 	int i, numtxts, numremoved;