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;