From d99493cb685f80aa13b3135d461fcde554fe121f Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 29 Nov 2022 20:41:07 -0500 Subject: [PATCH] Add a funky dithered 16-colour mode to ewmhicon. This adds a new option, --w32vga, which generates icons targeting the 16-colour "VGA" palette used by Windows. This is the 8 combinations of 0/max RGB values, plus the same set with the values halved, plus a light gray. This option enables a hand-coded pattern that approximates the desired colours, and gives much more pleasing results in low colour modes. --- t/ewmhicon.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 165 insertions(+), 4 deletions(-) diff --git a/t/ewmhicon.c b/t/ewmhicon.c index 6983cf9..d7c6aea 100644 --- a/t/ewmhicon.c +++ b/t/ewmhicon.c @@ -33,10 +33,17 @@ #include "colour.h" #include "help.h" +enum { + SOPT_MAX = UCHAR_MAX, + LOPT_W32VGA, + LOPT_MAX +}; + static const char *progname = "ewmhicon"; static const char sopts[] = "c:VH"; static const struct option lopts[] = { { "colourseq", 1, NULL, 'c' }, + { "w32vga", 0, NULL, LOPT_W32VGA }, { "version", 0, NULL, 'V' }, { "help", 0, NULL, 'H' }, { 0 } @@ -48,11 +55,11 @@ static const struct option lopts[] = { 0xff000000 | (r << 16) | (g << 8) | b, \ S8TO16(r), S8TO16(g), S8TO16(b) } -#define COLOUR_SYS_EWMHICON(r, g, b) \ +#define COLOUR_SYS_XCOLOR(r, g, b) \ RGB8(0x ## r ## ul, 0x ## g ## ul, 0x ## b ## ul) #undef COLOUR_SYSTEM -#define COLOUR_SYSTEM EWMHICON +#define COLOUR_SYSTEM XCOLOR #define COLOURTAB_(n) { n ## _PRIMARY, n ## _DARK, n ## _LIGHT } #define COLOURTAB(n) COLOURTAB_(COLOUR ## n) @@ -99,6 +106,152 @@ static void print_version(void) puts("There is NO WARRANTY, to the extent permitted by law."); } + +#define COLOUR_SYS_HEX(r, g, b) 0x ## r ## g ## b ## ul + +#undef COLOUR_SYSTEM +#define COLOUR_SYSTEM HEX + +/* + * Returns true iff this pixel is an "edge" -- that is, either there + * is no pixel to the right or below or those pixels are a different + * colour. + */ +static int is_edge(unsigned x, unsigned y, unsigned w, unsigned h, + unsigned long *p, unsigned long colour) +{ + return y+1 >= h || x+1 >= w + || (p[1] & 0xffffff) != colour + || (p[w] & 0xffffff) != colour; +} + +static void print_xpm_w32vga(unsigned long size, unsigned long *icon_buf) +{ + unsigned w = size & 0xffff, h = (size >> 16) & 0xffff; + unsigned x, y, i, j, n; + + const char colourchars[16] = "#rgybmc-+RGYBMC "; + unsigned long palette[16] = { + 0x000000, 0x800000, 0x008000, 0x808000, + 0x000080, 0x800080, 0x008080, 0xc0c0c0, + 0x808080, 0xff0000, 0x00ff00, 0xffff00, + 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff + }; + + unsigned long prev_colour = 0; + unsigned used_colours, v; + + size = (unsigned long) w * h; + for (i = 0; i < size; i++) { + unsigned long *p = &icon_buf[i]; + char *c; + + x = i%w, y=i/w; + + switch (*p & 0xffffff) { + /* red */ + case COLOUR0_PRIMARY: + *p = y&1 ? ( x&1 ? 'r' : 'm' ) : ( x&1 ? 'y' : 'r' ); + break; + case COLOUR0_LIGHT: + *p = (x^y)&1 ? '+' : 'r'; + break; + case COLOUR0_DARK: + *p = 'r'; + break; + /* orange */ + case COLOUR1_PRIMARY: + *p = y&1 ? 'y' : x&1 ? '+' : 'R'; + break; + case COLOUR1_LIGHT: + *p = (x^y)&1 ? '+' : 'y'; + break; + case COLOUR1_DARK: + *p = (x^y)&1 ? 'r' : 'y'; + break; + /* yellow */ + case COLOUR2_PRIMARY: + *p = (x^y)&1 ? '+' : 'Y'; + break; + case COLOUR2_LIGHT: + *p = (x^y)&1 ? '-' : 'Y'; + break; + case COLOUR2_DARK: + *p = (x^y)&1 ? '+' : 'Y'; + if (is_edge(x, y, w, h, p, COLOUR2_DARK)) + *p = (x^y)&1 ? '+' : 'y'; + break; + /* green */ + case COLOUR3_PRIMARY: + *p = y&1 ? 'g' : x&1 ? '+' : 'g'; + break; + case COLOUR3_LIGHT: + *p = (x^y)&1 ? '+' : 'g'; + break; + case COLOUR3_DARK: + *p = 'g'; + if (is_edge(x, y, w, h, p, COLOUR3_DARK)) + *p = (x^y)&1 ? '#' : 'g'; + break; + /* blue */ + case COLOUR4_PRIMARY: + *p = (x^y)&1 ? 'b' : 'c'; + break; + case COLOUR4_LIGHT: + *p = 'c'; + if (is_edge(x, y, w, h, p, COLOUR4_LIGHT)) + *p = (x^y)&1 ? 'b' : 'c'; + break; + case COLOUR4_DARK: + *p = 'b'; + if (is_edge(x, y, w, h, p, COLOUR4_DARK)) + *p = (x^y)&1 ? '#' : 'b'; + break; + /* white */ + case COLOUR5_PRIMARY: + *p = (x^y)&1 ? '-' : ' '; + break; + case COLOUR5_LIGHT: + *p = ' '; + break; + case COLOUR5_DARK: + *p = (x^y)&1 ? '+' : ' '; + break; + /* dummy */ + case 0xff0000: *p = 'R'; break; + case 0x00ff00: *p = 'G'; break; + case 0x0000ff: *p = 'B'; break; + } + + c = strchr(colourchars, *p); + assert(c && c - colourchars < 16); + used_colours |= 1u << (c-colourchars); + } + + for (n = 0, v = used_colours; v; n++) + v &= v-1; + + puts("/* XPM */"); + puts("static char *icon[] = {"); + printf("\"%u %u %u 1\",\n", w, h, n); + for (i = 0; i < sizeof colourchars; i++) { + if (!(used_colours & (1u << i))) + continue; + + printf("\"%c c #%.6lx\",\n", colourchars[i], palette[i]); + } + + for (y = 0; y < h; y++) { + putchar('"'); + for (x = 0; x < w; x++) { + putchar(icon_buf[y*h+x]); + } + printf("\"%.*s\n", y+1 0) @@ -270,6 +424,9 @@ int main(int argc, char **argv) if (decode_colourseq(colourseq, optarg) != 0) return EXIT_FAILURE; break; + case LOPT_W32VGA: + w32vga = 1; + break; case 'H': print_help(); return EXIT_SUCCESS; @@ -302,7 +459,11 @@ int main(int argc, char **argv) if (!icon) return EXIT_FAILURE; - print_xpm(colourseq, size, icon); + if (w32vga) { + print_xpm_w32vga(size, icon); + } else { + print_xpm(colourseq, size, icon); + } free(ewmhicon); return 0; -- 2.43.2