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.

scheme.c 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /* Copyright (C) 2018 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. static const struct HSV
  30. R = { 0.0, 1.0, 1.0 },
  31. Y = { 60.0, 1.0, 1.0 },
  32. G = { 120.0, 1.0, 1.0 },
  33. C = { 180.0, 1.0, 1.0 },
  34. B = { 240.0, 1.0, 1.0 },
  35. M = { 300.0, 1.0, 1.0 };
  36. struct RGB {
  37. byte r, g, b;
  38. };
  39. static struct RGB rgb(struct HSV hsv) {
  40. double c = hsv.v * hsv.s;
  41. double h = hsv.h / 60.0;
  42. double x = c * (1.0 - fabs(fmod(h, 2.0) - 1.0));
  43. double m = hsv.v - c;
  44. double r = m, g = m, b = m;
  45. if (h <= 1.0) { r += c; g += x; }
  46. else if (h <= 2.0) { r += x; g += c; }
  47. else if (h <= 3.0) { g += c; b += x; }
  48. else if (h <= 4.0) { g += x; b += c; }
  49. else if (h <= 5.0) { r += x; b += c; }
  50. else if (h <= 6.0) { r += c; b += x; }
  51. return (struct RGB) { r * 255.0, g * 255.0, b * 255.0 };
  52. }
  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, Light = 8,
  63. Background = 16, Foreground, Bold, Selection, Cursor,
  64. SchemeLen,
  65. };
  66. static struct HSV scheme[SchemeLen];
  67. static void generate(void) {
  68. scheme[Light + Black] = x(R, +45.0, 0.3, 0.3);
  69. scheme[Light + Red] = x(R, +10.0, 0.9, 0.8);
  70. scheme[Light + Green] = x(G, -55.0, 0.8, 0.6);
  71. scheme[Light + Yellow] = x(Y, -20.0, 0.8, 0.8);
  72. scheme[Light + Blue] = x(B, -55.0, 0.4, 0.5);
  73. scheme[Light + Magenta] = x(M, +45.0, 0.4, 0.6);
  74. scheme[Light + Cyan] = x(C, -60.0, 0.3, 0.6);
  75. scheme[Light + White] = x(R, +45.0, 0.3, 0.8);
  76. scheme[Dark + Black] = x(scheme[Light + Black], 0.0, 1.0, 0.3);
  77. scheme[Dark + White] = x(scheme[Light + White], 0.0, 1.0, 0.6);
  78. for (uint i = Red; i < White; ++i) {
  79. scheme[Dark + i] = x(scheme[Light + i], 0.0, 1.0, 0.8);
  80. }
  81. scheme[Background] = x(scheme[Dark + Black], 0.0, 1.0, 0.9);
  82. scheme[Foreground] = x(scheme[Light + White], 0.0, 1.0, 0.9);
  83. scheme[Bold] = x(scheme[Light + White], 0.0, 1.0, 1.0);
  84. scheme[Selection] = x(scheme[Light + Red], +10.0, 1.0, 0.8);
  85. scheme[Cursor] = x(scheme[Dark + White], 0.0, 1.0, 0.8);
  86. }
  87. static void swap(uint a, uint b) {
  88. struct HSV t = scheme[a];
  89. scheme[a] = scheme[b];
  90. scheme[b] = t;
  91. }
  92. static void invert(void) {
  93. swap(Dark + Black, Light + White);
  94. swap(Light + Black, Dark + White);
  95. }
  96. static void printHSV(uint n) {
  97. printf("%g,%g,%g\n", scheme[n].h, scheme[n].s, scheme[n].v);
  98. }
  99. static void printRGB(uint n) {
  100. printf(
  101. "%02hhX%02hhX%02hhX\n",
  102. rgb(scheme[n]).r, rgb(scheme[n]).g, rgb(scheme[n]).b
  103. );
  104. }
  105. static const char *CNames[SchemeLen] = {
  106. [Dark + Black] = "DarkBlack",
  107. [Dark + Red] = "DarkRed",
  108. [Dark + Green] = "DarkGreen",
  109. [Dark + Yellow] = "DarkYellow",
  110. [Dark + Blue] = "DarkBlue",
  111. [Dark + Magenta] = "DarkMagenta",
  112. [Dark + Cyan] = "DarkCyan",
  113. [Dark + White] = "DarkWhite",
  114. [Light + Black] = "LightBlack",
  115. [Light + Red] = "LightRed",
  116. [Light + Green] = "LightGreen",
  117. [Light + Yellow] = "LightYellow",
  118. [Light + Blue] = "LightBlue",
  119. [Light + Magenta] = "LightMagenta",
  120. [Light + Cyan] = "LightCyan",
  121. [Light + White] = "LightWhite",
  122. [Background] = "Background",
  123. [Foreground] = "Foreground",
  124. [Bold] = "Bold",
  125. [Selection] = "Selection",
  126. [Cursor] = "Cursor",
  127. };
  128. static void printCHead(void) {
  129. printf("enum {\n");
  130. }
  131. static void printC(uint n) {
  132. printf(
  133. "\t%s = 0x%02hhX%02hhX%02hhX,\n",
  134. CNames[n], rgb(scheme[n]).r, rgb(scheme[n]).g, rgb(scheme[n]).b
  135. );
  136. }
  137. static void printCTail(void) {
  138. printf("};\n");
  139. }
  140. static void printLinux(uint n) {
  141. printf(
  142. "\x1B]P%X%02hhX%02hhX%02hhX",
  143. n, rgb(scheme[n]).r, rgb(scheme[n]).g, rgb(scheme[n]).b
  144. );
  145. }
  146. static const char *MinttyNames[SchemeLen] = {
  147. [Dark + Black] = "Black",
  148. [Dark + Red] = "Red",
  149. [Dark + Green] = "Green",
  150. [Dark + Yellow] = "Yellow",
  151. [Dark + Blue] = "Blue",
  152. [Dark + Magenta] = "Magenta",
  153. [Dark + Cyan] = "Cyan",
  154. [Dark + White] = "White",
  155. [Light + Black] = "BoldBlack",
  156. [Light + Red] = "BoldRed",
  157. [Light + Green] = "BoldGreen",
  158. [Light + Yellow] = "BoldYellow",
  159. [Light + Blue] = "BoldBlue",
  160. [Light + Magenta] = "BoldMagenta",
  161. [Light + Cyan] = "BoldCyan",
  162. [Light + White] = "BoldWhite",
  163. [Background] = "BackgroundColour",
  164. [Foreground] = "ForegroundColour",
  165. [Cursor] = "CursorColour",
  166. };
  167. static void printMintty(uint n) {
  168. if (!MinttyNames[n]) return;
  169. printf(
  170. "%s=%hhu,%hhu,%hhu\n",
  171. MinttyNames[n], rgb(scheme[n]).r, rgb(scheme[n]).g, rgb(scheme[n]).b
  172. );
  173. }
  174. static void png(uint at, uint to) {
  175. if (to - at > 256) to = at + 256;
  176. uint len = to - at;
  177. uint swatchWidth = 64;
  178. uint swatchHeight = 64;
  179. uint cols = 8;
  180. uint rows = (len + cols - 1) / cols;
  181. uint width = swatchWidth * cols;
  182. uint height = swatchHeight * rows;
  183. pngHead(stdout, width, height, 8, PNGIndexed);
  184. struct RGB pal[len];
  185. for (uint i = 0; i < len; ++i) {
  186. pal[i] = rgb(scheme[at + i]);
  187. }
  188. pngPalette(stdout, (byte *)pal, sizeof(pal));
  189. uint8_t data[height][1 + width];
  190. memset(data, 0, sizeof(data));
  191. for (uint32_t y = 0; y < height; ++y) {
  192. data[y][0] = (y % swatchHeight) ? PNGUp : PNGSub;
  193. }
  194. for (uint i = at; i < to; ++i) {
  195. uint p = i - at;
  196. uint32_t y = swatchHeight * (p / cols);
  197. uint32_t x = swatchWidth * (p % cols);
  198. data[y][1 + x] = x ? 1 : p;
  199. }
  200. pngData(stdout, (byte *)data, sizeof(data));
  201. pngTail(stdout);
  202. }
  203. static void print(void fn(uint), uint at, uint to) {
  204. for (uint i = at; i < to; ++i) {
  205. fn(i);
  206. }
  207. }
  208. int main(int argc, char *argv[]) {
  209. generate();
  210. uint at = 0;
  211. uint to = Background;
  212. char out = 'x';
  213. int opt;
  214. while (0 < (opt = getopt(argc, argv, "acghilmp:tx"))) {
  215. switch (opt) {
  216. break; case 'a': to = Background;
  217. break; case 'i': invert();
  218. break; case 'p': at = strtoul(optarg, NULL, 0); to = at + 1;
  219. break; case 't': to = SchemeLen;
  220. break; case '?': return EX_USAGE;
  221. break; default: out = opt;
  222. }
  223. }
  224. switch (out) {
  225. break; case 'c': printCHead(); print(printC, at, to); printCTail();
  226. break; case 'g': png(at, to);
  227. break; case 'h': print(printHSV, at, to);
  228. break; case 'l': print(printLinux, at, to);
  229. break; case 'm': print(printMintty, at, to);
  230. break; case 'x': print(printRGB, at, to);
  231. }
  232. return EX_OK;
  233. }