/* * env * Written in 2019 by Lucas * CC0 1.0 Universal/Public domain - No rights reserved * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. You should have received a copy of the CC0 Public Domain * Dedication along with this software. If not, see * . */ #include #include #include #include #include #include #define LENGTH 50 #define INRANGE(x, a, b) ((a) <= (x) && (x) <= (b)) static void hsvtorgb(double hsv[3], uint8_t rgb[3]) { double c, hh, m, x; double r, g, b; c = hsv[2] * hsv[1]; hh = hsv[0] / 60.0; x = c * (1.0 - fabs(fmod(hh, 2.0) - 1.0)); switch ((int)floor(hh == 6.0 ? 0.0 : hh)) { case 0: r = c; g = x; b = 0; break; case 1: r = x; g = c; b = 0; break; case 2: r = 0; g = c; b = x; break; case 3: r = 0; g = x; b = c; break; case 4: r = x; g = 0; b = c; break; case 5: r = c; g = 0; b = x; break; } m = hsv[2] - c; r += m; g += m; b += m; rgb[0] = round(255 * r); rgb[1] = round(255 * g); rgb[2] = round(255 * b); } static void hsltorgb(double hsl[3], uint8_t rgb[3]) { double c, hh, m, x; double r, g, b; c = (1.0 - fabs(2.0 * hsl[2] - 1.0)) * hsl[1]; hh = hsl[0] / 60.0; x = c * (1.0 - fabs(fmod(hh, 2.0) - 1.0)); switch ((int)floor(hh == 6.0 ? 0.0 : hh)) { case 0: r = c; g = x; b = 0; break; case 1: r = x; g = c; b = 0; break; case 2: r = 0; g = c; b = x; break; case 3: r = 0; g = x; b = c; break; case 4: r = x; g = 0; b = c; break; case 5: r = c; g = 0; b = x; break; } m = hsl[2] - c / 2.0; r += m; g += m; b += m; rgb[0] = round(255 * r); rgb[1] = round(255 * g); rgb[2] = round(255 * b); } static void parsecolorline(const char *s, size_t n, uint8_t rgb[3]) { double d[3]; unsigned int u[3]; if (sscanf(s, "hsv %lf %lf %lf", &d[0], &d[1], &d[2]) == 3) { if (!INRANGE(d[0], 0, 360) || !INRANGE(d[1], 0, 1) || !INRANGE(d[2], 0, 1)) goto err; hsvtorgb(d, rgb); } else if (sscanf(s, "hsl %lf %lf %lf", &d[0], &d[1], &d[2]) == 3) { if (!INRANGE(d[0], 0, 360) || !INRANGE(d[1], 0, 1) || !INRANGE(d[2], 0, 1)) goto err; hsltorgb(d, rgb); } else if (sscanf(s, "rgb %u %u %u", &u[0], &u[1], &u[2]) == 3) { if (!INRANGE(u[0], 0, 255) || !INRANGE(u[1], 0, 255) || !INRANGE(u[2], 0, 255)) goto err; rgb[0] = u[0]; rgb[1] = u[1]; rgb[2] = u[2]; } else if (sscanf(s, "rgbhex %x %x %x", &u[0], &u[1], &u[2]) == 3) { if (!INRANGE(u[0], 0, 255) || !INRANGE(u[1], 0, 255) || !INRANGE(u[2], 0, 255)) goto err; rgb[0] = u[0]; rgb[1] = u[1]; rgb[2] = u[2]; } else { err: fprintf(stderr, "Invalid input: \"%s\".", s); exit(1); } } static void readcolorscheme(uint8_t colorscheme[18][3]) { char *line = NULL; size_t linesize = 0; ssize_t linelen; int nlines = 0; while ((linelen = getline(&line, &linesize, stdin)) != -1 && nlines < 18) { if (linelen == 0 || line[0] == '\n' || line[0] == '#') continue; parsecolorline(line, linelen, colorscheme[nlines]); nlines++; } free(line); if (ferror(stdin)) { fputs("Input error.\n", stderr); exit(1); } if (nlines < 18) { fputs("Not enought colors.\n", stderr); exit(1); } } static void writecolor(uint8_t rgb[3], int l) { int i; for (i = 0; i < l; i++) { if (fwrite(rgb, sizeof(rgb[0]), 3, stdout) != 3) { fputs("Short write.\n", stderr); exit(1); } } } static void do_image(uint8_t colorscheme[18][3]) { int i, n; printf("P6\n%u %u 255\n", 9 * LENGTH, 2 * LENGTH); for (i = 0; i < LENGTH; i++) for (n = 0; n < 9; n++) writecolor(colorscheme[n], LENGTH); for (i = 0; i < LENGTH; i++) for (n = 9; n < 18; n++) writecolor(colorscheme[n], LENGTH); } static void do_colors(uint8_t colorscheme[18][3]) { int n; for (n = 0; n < 18; n++) printf("#%02x%02x%02x\n", colorscheme[n][0], colorscheme[n][1], colorscheme[n][2]); } int main(int argc, char *argv[]) { uint8_t colorscheme[18][3]; int iflag = 0; if (argc > 2) goto usage; if (argc == 2) { if (strncmp(argv[1], "-i", 3) != 0) goto usage; iflag = 1; } readcolorscheme(colorscheme); if (iflag) do_image(colorscheme); else do_colors(colorscheme); return 0; usage: fprintf(stderr, "Usage: %s [-i]\n", argv[0]); return 1; }