199 lines
4.3 KiB
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;
|
|
}
|