/* Copyright (C) 2018 Curtis McEnroe * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include static const struct HSV { double h, s, v; } R = { 0.0, 1.0, 1.0 }, Y = { 60.0, 1.0, 1.0 }, G = { 120.0, 1.0, 1.0 }, C = { 180.0, 1.0, 1.0 }, B = { 240.0, 1.0, 1.0 }, M = { 300.0, 1.0, 1.0 }; static struct RGB { uint8_t r, g, b; } toRGB(struct HSV hsv) { double c = hsv.v * hsv.s; double h = hsv.h / 60.0; double x = c * (1.0 - fabs(fmod(h, 2.0) - 1.0)); double m = hsv.v - c; double r = m, g = m, b = m; if (h <= 1.0) { r += c; g += x; } else if (h <= 2.0) { r += x; g += c; } else if (h <= 3.0) { g += c; b += x; } else if (h <= 4.0) { g += x; b += c; } else if (h <= 5.0) { r += x; b += c; } else if (h <= 6.0) { r += c; b += x; } return (struct RGB) { r * 255.0, g * 255.0, b * 255.0 }; } static struct HSV x(struct HSV o, double hd, double sf, double vf) { return (struct HSV) { fmod(o.h + hd, 360.0), fmin(o.s * sf, 1.0), fmin(o.v * vf, 1.0), }; } enum { Black, Red, Green, Yellow, Blue, Magenta, Cyan, White, Dark = 0, Light = 8, Background = 16, Foreground, Bold, Selection, Cursor, SchemeLen, }; static struct HSV scheme[SchemeLen]; static void generate(void) { scheme[Light + Black] = x(R, +45.0, 0.3, 0.3); scheme[Light + Red] = x(R, +10.0, 0.9, 0.8); scheme[Light + Green] = x(G, -55.0, 0.8, 0.6); scheme[Light + Yellow] = x(Y, -20.0, 0.8, 0.8); scheme[Light + Blue] = x(B, -55.0, 0.4, 0.5); scheme[Light + Magenta] = x(M, +45.0, 0.4, 0.6); scheme[Light + Cyan] = x(C, -60.0, 0.3, 0.6); scheme[Light + White] = x(R, +45.0, 0.3, 0.8); scheme[Dark + Black] = x(scheme[Light + Black], 0.0, 1.0, 0.3); scheme[Dark + White] = x(scheme[Light + White], 0.0, 1.0, 0.6); for (int i = Red; i < White; ++i) { scheme[Dark + i] = x(scheme[Light + i], 0.0, 1.0, 0.8); } scheme[Background] = x(scheme[Dark + Black], 0.0, 1.0, 0.9); scheme[Foreground] = x(scheme[Light + White], 0.0, 1.0, 0.9); scheme[Bold] = x(scheme[Light + White], 0.0, 1.0, 1.0); scheme[Selection] = x(scheme[Light + Red], +10.0, 1.0, 0.8); scheme[Cursor] = x(scheme[Dark + White], 0.0, 1.0, 0.8); } static void swap(int a, int b) { struct HSV t = scheme[a]; scheme[a] = scheme[b]; scheme[b] = t; } static void invert(void) { swap(Dark + Black, Light + White); swap(Light + Black, Dark + White); } static void printHSV(int n) { printf("%g,%g,%g\n", scheme[n].h, scheme[n].s, scheme[n].v); } static void printRGB(int n) { struct RGB rgb = toRGB(scheme[n]); printf("%02X%02X%02X\n", rgb.r, rgb.g, rgb.b); } static const char *CNames[SchemeLen] = { [Dark + Black] = "DarkBlack", [Dark + Red] = "DarkRed", [Dark + Green] = "DarkGreen", [Dark + Yellow] = "DarkYellow", [Dark + Blue] = "DarkBlue", [Dark + Magenta] = "DarkMagenta", [Dark + Cyan] = "DarkCyan", [Dark + White] = "DarkWhite", [Light + Black] = "LightBlack", [Light + Red] = "LightRed", [Light + Green] = "LightGreen", [Light + Yellow] = "LightYellow", [Light + Blue] = "LightBlue", [Light + Magenta] = "LightMagenta", [Light + Cyan] = "LightCyan", [Light + White] = "LightWhite", [Background] = "Background", [Foreground] = "Foreground", [Bold] = "Bold", [Selection] = "Selection", [Cursor] = "Cursor", }; static void printCHead(void) { printf("enum {\n"); } static void printC(int n) { struct RGB rgb = toRGB(scheme[n]); printf("\t%s = 0x%02X%02X%02X,\n", CNames[n], rgb.r, rgb.g, rgb.b); } static void printCTail(void) { printf("};\n"); } static void printLinux(int n) { struct RGB rgb = toRGB(scheme[n]); printf("\x1B]P%X%02X%02X%02X", n, rgb.r, rgb.g, rgb.b); } static const char *MinttyNames[SchemeLen] = { [Dark + Black] = "Black", [Dark + Red] = "Red", [Dark + Green] = "Green", [Dark + Yellow] = "Yellow", [Dark + Blue] = "Blue", [Dark + Magenta] = "Magenta", [Dark + Cyan] = "Cyan", [Dark + White] = "White", [Light + Black] = "BoldBlack", [Light + Red] = "BoldRed", [Light + Green] = "BoldGreen", [Light + Yellow] = "BoldYellow", [Light + Blue] = "BoldBlue", [Light + Magenta] = "BoldMagenta", [Light + Cyan] = "BoldCyan", [Light + White] = "BoldWhite", [Background] = "BackgroundColour", [Foreground] = "ForegroundColour", [Cursor] = "CursorColour", }; static void printMintty(int n) { if (!MinttyNames[n]) return; struct RGB rgb = toRGB(scheme[n]); printf("%s=%d,%d,%d\n", MinttyNames[n], rgb.r, rgb.g, rgb.b); } static uint32_t crc; static void pngWrite(const void *ptr, size_t size) { fwrite(ptr, size, 1, stdout); if (ferror(stdout)) err(EX_IOERR, "(stdout)"); crc = crc32(crc, ptr, size); } static void pngInt(uint32_t host) { uint32_t net = htonl(host); pngWrite(&net, 4); } static void pngChunk(const char *type, uint32_t size) { pngInt(size); crc = crc32(0, Z_NULL, 0); pngWrite(type, 4); } static void png(int at, int to) { if (to - at > 256) to = at + 256; uint32_t len = to - at; uint32_t swatchWidth = 64; uint32_t swatchHeight = 64; uint32_t cols = 8; uint32_t rows = (len + cols - 1) / cols; uint32_t width = swatchWidth * cols; uint32_t height = swatchHeight * rows; pngWrite("\x89PNG\r\n\x1A\n", 8); pngChunk("IHDR", 13); pngInt(width); pngInt(height); pngWrite("\x08\x03\x00\x00\x00", 5); pngInt(crc); pngChunk("PLTE", 3 * len); for (int i = at; i < to; ++i) { struct RGB rgb = toRGB(scheme[i]); pngWrite(&rgb, 3); } pngInt(crc); uint8_t data[height][1 + width]; memset(data, 0, sizeof(data)); for (uint32_t y = 0; y < height; ++y) { enum { None, Sub, Up, Average, Paeth }; data[y][0] = (y % swatchHeight) ? Up : Sub; } for (int i = at; i < to; ++i) { int p = i - at; uint32_t y = swatchHeight * (p / cols); uint32_t x = swatchWidth * (p % cols); data[y][1 + x] = x ? 1 : p; } uLong size = compressBound(sizeof(data)); uint8_t deflate[size]; int error = compress(deflate, &size, (Byte *)data, sizeof(data)); if (error != Z_OK) errx(EX_SOFTWARE, "compress: %d", error); pngChunk("IDAT", size); pngWrite(deflate, size); pngInt(crc); pngChunk("IEND", 0); pngInt(crc); } static void print(void (*fn)(int), int at, int to) { for (int i = at; i < to; ++i) { fn(i); } } int main(int argc, char *argv[]) { generate(); int at = 0; int to = Background; char out = 'x'; int opt; while (0 < (opt = getopt(argc, argv, "acghilmp:tx"))) { switch (opt) { break; case 'a': to = Background; break; case 'i': invert(); break; case 'p': at = strtoul(optarg, NULL, 0); to = at + 1; break; case 't': to = SchemeLen; break; case '?': return EX_USAGE; break; default: out = opt; } } switch (out) { break; case 'c': printCHead(); print(printC, at, to); printCTail(); break; case 'g': png(at, to); break; case 'h': print(printHSV, at, to); break; case 'l': print(printLinux, at, to); break; case 'm': print(printMintty, at, to); break; case 'x': print(printRGB, at, to); } return EX_OK; }