/* 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 #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 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), }; } 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 }; } enum { Black, Red, Green, Yellow, Blue, Magenta, Cyan, White }; static struct { struct Hsv dark[8]; struct Hsv light[8]; struct Hsv background, text, bold, selection, cursor; } scheme; 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.text = 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(struct Hsv *a, struct Hsv *b) { struct Hsv t; t = *a; *a = *b; *b = t; } static void invert(void) { swap(&scheme.dark[Black], &scheme.light[White]); swap(&scheme.light[Black], &scheme.dark[White]); } static void printHsv(struct Hsv hsv) { printf("%g,%g,%g\n", hsv.h, hsv.s, hsv.v); } static void hsv(bool ansi) { for (int i = Black; i <= White; ++i) { printHsv(scheme.dark[i]); } for (int i = Black; i <= White; ++i) { printHsv(scheme.light[i]); } if (ansi) return; printHsv(scheme.background); printHsv(scheme.text); printHsv(scheme.bold); printHsv(scheme.selection); printHsv(scheme.cursor); } static void printHex(struct Hsv hsv) { struct Rgb rgb = toRgb(hsv); printf("%02X%02X%02X\n", rgb.r, rgb.g, rgb.b); } static void hex(bool ansi) { for (int i = Black; i <= White; ++i) { printHex(scheme.dark[i]); } for (int i = Black; i <= White; ++i) { printHex(scheme.light[i]); } if (ansi) return; printHex(scheme.background); printHex(scheme.text); printHex(scheme.bold); printHex(scheme.selection); printHex(scheme.cursor); } static void printC(struct Hsv hsv) { struct Rgb rgb = toRgb(hsv); printf("\t0x%02X%02X%02X,\n", rgb.r, rgb.g, rgb.b); } static void header(void) { printf( "// This file is generated by scheme -c.\n\n" "#include \n\n" "const struct {\n" "\tuint32_t darkBlack, darkRed, darkGreen, darkYellow;\n" "\tuint32_t darkBlue, darkMagenta, darkCyan, darkWhite;\n" "\tuint32_t lightBlack, lightRed, lightGreen, lightYellow;\n" "\tuint32_t lightBlue, lightMagenta, lightCyan, lightWhite;\n" "\tuint32_t background, text, bold, selection, cursor;\n" "} Scheme = {\n" ); for (int i = Black; i <= White; ++i) { printC(scheme.dark[i]); } for (int i = Black; i <= White; ++i) { printC(scheme.light[i]); } printC(scheme.background); printC(scheme.text); printC(scheme.bold); printC(scheme.selection); printC(scheme.cursor); printf("};\n"); } static void console(void) { for (int i = Black; i <= White; ++i) { struct Rgb rgb = toRgb(scheme.dark[i]); printf("\x1B]P%X%02X%02X%02X", i, rgb.r, rgb.g, rgb.b); } for (int i = Black; i <= White; ++i) { struct Rgb rgb = toRgb(scheme.dark[i]); printf("\x1B]P%X%02X%02X%02X", 8 + i, rgb.r, rgb.g, rgb.b); } } static void printMintty(const char *key, struct Hsv hsv) { struct Rgb rgb = toRgb(hsv); printf("%s=%d,%d,%d\n", key, rgb.r, rgb.g, rgb.b); } static void mintty(void) { printMintty("Black", scheme.dark[Black]); printMintty("Red", scheme.dark[Red]); printMintty("Green", scheme.dark[Green]); printMintty("Yellow", scheme.dark[Yellow]); printMintty("Blue", scheme.dark[Blue]); printMintty("Magenta", scheme.dark[Magenta]); printMintty("Cyan", scheme.dark[Cyan]); printMintty("White", scheme.dark[White]); printMintty("BoldBlack", scheme.light[Black]); printMintty("BoldRed", scheme.light[Red]); printMintty("BoldGreen", scheme.light[Green]); printMintty("BoldYellow", scheme.light[Yellow]); printMintty("BoldBlue", scheme.light[Blue]); printMintty("BoldMagenta", scheme.light[Magenta]); printMintty("BoldCyan", scheme.light[Cyan]); printMintty("BoldWhite", scheme.light[White]); printMintty("BackgroundColour", scheme.background); printMintty("ForegroundColour", scheme.text); printMintty("CursorColour", scheme.cursor); } 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(const struct Hsv *hsv, size_t len) { if (len > 256) len = 256; uint32_t swatchWidth = 64; uint32_t swatchHeight = 64; uint32_t columns = 8; uint32_t rows = (len + columns - 1) / columns; uint32_t width = swatchWidth * columns; uint32_t height = swatchHeight * rows; pngWrite("\x89PNG\r\n\x1A\n", 8); pngChunk("IHDR", 13); pngInt(width); pngInt(height); pngWrite("\x08\x03\0\0\0", 5); pngInt(crc); pngChunk("PLTE", 3 * len); for (size_t i = 0; i < len; ++i) { struct Rgb rgb = toRgb(hsv[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 (size_t i = 0; i < len; ++i) { uint32_t y = swatchHeight * (i / columns); uint32_t x = swatchWidth * (i % columns); data[y][1 + x] = x ? 1 : i; } 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); } int main(int argc, char *argv[]) { generate(); bool ansi = true; char out = 'x'; int opt; while (0 < (opt = getopt(argc, argv, "acghilmtx"))) { switch (opt) { break; case 'a': ansi = true; break; case 'i': invert(); break; case 't': ansi = false; break; case '?': return EX_USAGE; break; default: out = opt; } } switch (out) { break; case 'c': header(); break; case 'g': png((struct Hsv *)&scheme, (ansi ? 16 : 21)); break; case 'h': hsv(ansi); break; case 'l': console(); break; case 'm': mintty(); break; case 'x': hex(ansi); } return EX_OK; }