The repository formerly known as dotfiles
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
6.6KB

  1. /* Copyright (C) 2018, 2019 C. McEnroe <june@causal.agency>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU Affero General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <err.h>
  17. #include <math.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <sysexits.h>
  22. #include <unistd.h>
  23. #include "png.h"
  24. typedef unsigned uint;
  25. typedef unsigned char byte;
  26. struct HSV {
  27. double h, s, v;
  28. };
  29. struct RGB {
  30. byte r, g, b;
  31. };
  32. static struct RGB convert(struct HSV o) {
  33. double c = o.v * o.s;
  34. double h = o.h / 60.0;
  35. double x = c * (1.0 - fabs(fmod(h, 2.0) - 1.0));
  36. double m = o.v - c;
  37. double r = m, g = m, b = m;
  38. if (h <= 1.0) { r += c; g += x; }
  39. else if (h <= 2.0) { r += x; g += c; }
  40. else if (h <= 3.0) { g += c; b += x; }
  41. else if (h <= 4.0) { g += x; b += c; }
  42. else if (h <= 5.0) { r += x; b += c; }
  43. else if (h <= 6.0) { r += c; b += x; }
  44. return (struct RGB) { r * 255.0, g * 255.0, b * 255.0 };
  45. }
  46. static const struct HSV
  47. R = { 0.0, 1.0, 1.0 },
  48. Y = { 60.0, 1.0, 1.0 },
  49. G = { 120.0, 1.0, 1.0 },
  50. C = { 180.0, 1.0, 1.0 },
  51. B = { 240.0, 1.0, 1.0 },
  52. M = { 300.0, 1.0, 1.0 };
  53. static struct HSV x(struct HSV o, double hd, double sf, double vf) {
  54. return (struct HSV) {
  55. fmod(o.h + hd, 360.0),
  56. fmin(o.s * sf, 1.0),
  57. fmin(o.v * vf, 1.0),
  58. };
  59. }
  60. enum {
  61. Black, Red, Green, Yellow, Blue, Magenta, Cyan, White,
  62. Dark = 0,
  63. Light = 8,
  64. Background = 16,
  65. Foreground,
  66. Bold,
  67. Selection,
  68. Cursor,
  69. SchemeLen,
  70. };
  71. static struct HSV scheme[SchemeLen];
  72. static struct HSV *dark = &scheme[Dark];
  73. static struct HSV *light = &scheme[Light];
  74. static void generate(void) {
  75. light[Black] = x(R, +45.0, 0.3, 0.3);
  76. light[Red] = x(R, +10.0, 0.9, 0.8);
  77. light[Green] = x(G, -55.0, 0.8, 0.6);
  78. light[Yellow] = x(Y, -20.0, 0.8, 0.8);
  79. light[Blue] = x(B, -55.0, 0.4, 0.5);
  80. light[Magenta] = x(M, +45.0, 0.4, 0.6);
  81. light[Cyan] = x(C, -60.0, 0.3, 0.6);
  82. light[White] = x(R, +45.0, 0.3, 0.8);
  83. dark[Black] = x(light[Black], 0.0, 1.0, 0.3);
  84. dark[White] = x(light[White], 0.0, 1.0, 0.7);
  85. for (uint i = Red; i < White; ++i) {
  86. dark[i] = x(light[i], 0.0, 1.0, 0.8);
  87. }
  88. scheme[Background] = x(dark[Black], 0.0, 1.0, 0.9);
  89. scheme[Foreground] = x(light[White], 0.0, 1.0, 0.9);
  90. scheme[Bold] = x(light[White], 0.0, 1.0, 1.0);
  91. scheme[Selection] = x(light[Red], +10.0, 1.0, 0.8);
  92. scheme[Cursor] = x(dark[White], 0.0, 1.0, 0.8);
  93. }
  94. static void swap(struct HSV *a, struct HSV *b) {
  95. struct HSV c = *a;
  96. *a = *b;
  97. *b = c;
  98. }
  99. static void invert(void) {
  100. swap(&dark[Black], &light[White]);
  101. swap(&dark[White], &light[Black]);
  102. }
  103. typedef void OutputFn(const struct HSV *hsv, uint len);
  104. static void outputHSV(const struct HSV *hsv, uint len) {
  105. for (uint i = 0; i < len; ++i) {
  106. printf("%g,%g,%g\n", hsv[i].h, hsv[i].s, hsv[i].v);
  107. }
  108. }
  109. #define FORMAT_RGB "%02hhX%02hhX%02hhX"
  110. static void outputRGB(const struct HSV *hsv, uint len) {
  111. for (uint i = 0; i < len; ++i) {
  112. struct RGB rgb = convert(hsv[i]);
  113. printf(FORMAT_RGB "\n", rgb.r, rgb.g, rgb.b);
  114. }
  115. }
  116. static void outputLinux(const struct HSV *hsv, uint len) {
  117. for (uint i = 0; i < len; ++i) {
  118. struct RGB rgb = convert(hsv[i]);
  119. printf("\x1B]P%X" FORMAT_RGB, i, rgb.r, rgb.g, rgb.b);
  120. }
  121. }
  122. static const char *Enum[SchemeLen] = {
  123. "DarkBlack", "DarkRed", "DarkGreen", "DarkYellow",
  124. "DarkBlue", "DarkMagenta", "DarkCyan", "DarkWhite",
  125. "LightBlack", "LightRed", "LightGreen", "LightYellow",
  126. "LightBlue", "LightMagenta", "LightCyan", "LightWhite",
  127. "Background", "Foreground", "Bold", "Selection", "Cursor",
  128. };
  129. static void outputEnum(const struct HSV *hsv, uint len) {
  130. printf("enum {\n");
  131. for (uint i = 0; i < len; ++i) {
  132. struct RGB rgb = convert(hsv[i]);
  133. printf("\t%s = 0x" FORMAT_RGB ",\n", Enum[i], rgb.r, rgb.g, rgb.b);
  134. }
  135. printf("};\n");
  136. }
  137. static const char *Mintty[SchemeLen] = {
  138. "Black", "Red", "Green", "Yellow",
  139. "Blue", "Magenta", "Cyan", "White",
  140. "BoldBlack", "BoldRed", "BoldGreen", "BoldYellow",
  141. "BoldBlue", "BoldMagenta", "BoldCyan", "BoldWhite",
  142. [Background] = "BackgroundColour",
  143. [Foreground] = "ForegroundColour",
  144. [Cursor] = "CursorColour",
  145. };
  146. static void outputMintty(const struct HSV *hsv, uint len) {
  147. for (uint i = 0; i < len; ++i) {
  148. if (!Mintty[i]) continue;
  149. struct RGB rgb = convert(hsv[i]);
  150. printf("%s=%hhu,%hhu,%hhu\n", Mintty[i], rgb.r, rgb.g, rgb.b);
  151. }
  152. }
  153. static void outputCSS(const struct HSV *hsv, uint len) {
  154. for (uint i = 0; i < len; ++i) {
  155. struct RGB rgb = convert(hsv[i]);
  156. printf(
  157. ".fg%u { color: #" FORMAT_RGB "; }\n"
  158. ".bg%u { background-color: #" FORMAT_RGB "; }\n",
  159. i, rgb.r, rgb.g, rgb.b,
  160. i, rgb.r, rgb.g, rgb.b
  161. );
  162. }
  163. }
  164. enum {
  165. SwatchWidth = 64,
  166. SwatchHeight = 64,
  167. SwatchCols = 8,
  168. };
  169. static void outputPNG(const struct HSV *hsv, uint len) {
  170. uint rows = (len + SwatchCols - 1) / SwatchCols;
  171. uint width = SwatchWidth * SwatchCols;
  172. uint height = SwatchHeight * rows;
  173. pngHead(stdout, width, height, 8, PNGIndexed);
  174. struct RGB pal[len];
  175. for (uint i = 0; i < len; ++i) {
  176. pal[i] = convert(hsv[i]);
  177. }
  178. pngPalette(stdout, (byte *)pal, sizeof(pal));
  179. byte data[height][1 + width];
  180. memset(data, 0, sizeof(data));
  181. for (uint y = 0; y < height; ++y) {
  182. data[y][0] = (y % SwatchHeight ? PNGUp : PNGSub);
  183. }
  184. for (uint i = 0; i < len; ++i) {
  185. uint y = SwatchHeight * (i / SwatchCols);
  186. uint x = SwatchWidth * (i % SwatchCols);
  187. data[y][1 + x] = (x ? 1 : i);
  188. }
  189. pngData(stdout, (byte *)data, sizeof(data));
  190. pngTail(stdout);
  191. }
  192. int main(int argc, char *argv[]) {
  193. generate();
  194. OutputFn *output = outputRGB;
  195. const struct HSV *hsv = scheme;
  196. uint len = 16;
  197. int opt;
  198. while (0 < (opt = getopt(argc, argv, "acghilmp:stx"))) {
  199. switch (opt) {
  200. break; case 'a': len = 16;
  201. break; case 'c': output = outputEnum;
  202. break; case 'g': output = outputPNG;
  203. break; case 'h': output = outputHSV;
  204. break; case 'i': invert();
  205. break; case 'l': output = outputLinux;
  206. break; case 'm': output = outputMintty;
  207. break; case 'p': {
  208. uint p = strtoul(optarg, NULL, 0);
  209. if (p >= SchemeLen) return EX_USAGE;
  210. hsv = &scheme[p];
  211. len = 1;
  212. }
  213. break; case 's': output = outputCSS;
  214. break; case 't': len = SchemeLen;
  215. break; case 'x': output = outputRGB;
  216. break; default: return EX_USAGE;
  217. }
  218. }
  219. output(hsv, len);
  220. }