env/themes/colorscheme.c

199 lines
4.3 KiB
C

/*
* 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
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <errno.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}