245 lines
6.5 KiB
C
245 lines
6.5 KiB
C
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#define ASCII_ZERO 48
|
|
#define ASCII_NINE 57
|
|
#define MIN_CONTRAST 0.5
|
|
//html = _dec_colors.sub(lambda match: _dec_spans[int(match.group(1))], qstr)
|
|
// this is an extremely fancy if not confusing way to say
|
|
// the single number that isn't an x, right after a ^
|
|
// is an index to an array of strings.
|
|
//html = _hex_colors.sub(hex_repl, html)
|
|
// the next 3 letters after after ^x is digits for rgb
|
|
// the verdict is:
|
|
// regex is not needed
|
|
// do the hex replacement first, then do the dec replacement
|
|
|
|
// instead of concatenating strings, they will be printed in parts.
|
|
|
|
// can either be RGB or HLS
|
|
struct Rgb {
|
|
int r, g, b;
|
|
};
|
|
|
|
struct Hls {
|
|
int h;
|
|
float l, s;
|
|
};
|
|
|
|
void cvt_rgb(struct Rgb *dest, const struct Hls const *src) {
|
|
if ((0 > src -> h || src -> h > 360) ||
|
|
(0 > src -> s && src -> s > 1) ||
|
|
(0 > src -> l && src -> l > 1)) {
|
|
return;
|
|
}
|
|
float hue = src -> h;
|
|
float r, g, b;
|
|
float chroma = (1 - fabs(2 * (src -> l) - 1)) * (src -> s);
|
|
float x = chroma * (1 - fabs((int)(hue/60) % 2 - 1));
|
|
float m = (src -> l) - chroma/2;
|
|
if (0 <= hue && hue < 60) {
|
|
r = chroma;
|
|
g = x;
|
|
b = 0;
|
|
} else if (60 <= hue && hue < 120) {
|
|
r = x;
|
|
g = chroma;
|
|
b = 0;
|
|
} else if (120 <= hue && hue < 180) {
|
|
r = 0;
|
|
g = chroma;
|
|
b = x;
|
|
} else if (180 <= hue && hue < 240) {
|
|
r = 0;
|
|
g = x;
|
|
b = chroma;
|
|
} else if (240 <= hue && hue < 300) {
|
|
r = x;
|
|
g = 0;
|
|
b = chroma;
|
|
} else if (300 <= hue && hue < 360) {
|
|
r = chroma;
|
|
g = 0;
|
|
b = x;
|
|
} else {
|
|
r = 0;
|
|
g = 0;
|
|
b = 0;
|
|
}
|
|
dest -> r = (r + m) * 255;
|
|
dest -> g = (g + m) * 255;
|
|
dest -> b = (b + m) * 255;
|
|
}
|
|
|
|
void cvt_hls(struct Hls *dest, const struct Rgb const *src) {
|
|
if (src == NULL || dest == NULL) {
|
|
return;
|
|
}
|
|
float r = src -> r / 255.0f;
|
|
float g = src -> g / 255.0f;
|
|
float b = src -> b / 255.0f;
|
|
float min = fmin(fmin(r, g), b);
|
|
float max = fmax(fmax(r, g), b);
|
|
dest -> l = (max + min)/2; //bi-hexcone model.
|
|
if (max == min) { // neutral color.
|
|
dest -> h = 0; // undefined.
|
|
dest -> s = 0.0f;
|
|
} else {
|
|
float chroma = max - min;
|
|
dest -> s = (dest -> l > 0.5) ? (chroma/(2 - max - min)) : (chroma/(max + min));
|
|
//piecewise function..
|
|
float hue;
|
|
if (max == r) {
|
|
hue = (int)((g - b)/chroma) + (g < b ? 6 : 0); // % 6 will break magenta (255, 0, 255)
|
|
} else if (max == g) {
|
|
hue = ((b - r)/chroma) + 2.0f;
|
|
} else {
|
|
hue = ((r - g)/chroma) + 4.0f;
|
|
}
|
|
dest -> h = (int)(hue * 60);
|
|
}
|
|
}
|
|
|
|
void dec(const int d) {
|
|
switch(d) {
|
|
case 0:
|
|
printf("<span style='color:rgb(128,128,128)'>");
|
|
break;
|
|
case 1:
|
|
printf("<span style='color:rgb(255,0,0)'>");
|
|
break;
|
|
case 2:
|
|
printf("<span style='color:rgb(51,255,0)'>");
|
|
break;
|
|
case 3:
|
|
printf("<span style='color:rgb(255,255,0)'>");
|
|
break;
|
|
case 4:
|
|
printf("<span style='color:rgb(51,102,255)'>");
|
|
break;
|
|
case 5:
|
|
printf("<span style='color:rgb(51,255,255)'>");
|
|
break;
|
|
case 6:
|
|
printf("<span style='color:rgb(255,51,102)'>");
|
|
break;
|
|
case 7:
|
|
printf("<span style='color:rgb(255,255,255)'>");
|
|
break;
|
|
case 8:
|
|
printf("<span style='color:rgb(153,153,153)'>");
|
|
break;
|
|
case 9:
|
|
printf("<span style='color:rgb(128,128,128)'>");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void hex(const char *str) {
|
|
const char h1[2] = {str[0], '\0'};
|
|
const char h2[2] = {str[1], '\0'};
|
|
const char h3[2] = {str[2], '\0'};
|
|
struct Rgb nrgb;
|
|
nrgb.r = strtol(h1, NULL, 16);
|
|
nrgb.g = strtol(h2, NULL, 16);
|
|
nrgb.b = strtol(h3, NULL, 16);
|
|
struct Hls nhls;
|
|
cvt_hls(&nhls, &nrgb);
|
|
if (nhls.l < MIN_CONTRAST) {
|
|
nhls.l = MIN_CONTRAST;
|
|
cvt_rgb(&nrgb, &nhls);
|
|
}
|
|
printf("<span style=\"color:rgb(%d,%d,%d)\">", nrgb.r, nrgb.g, nrgb.b);
|
|
}
|
|
|
|
void b(char * const str) {
|
|
#define IS_DIGIT(x) (x >= ASCII_ZERO && x <= ASCII_NINE)
|
|
char *token = strtok(str, "^");
|
|
char c;
|
|
while (token) {
|
|
c = token[0];
|
|
if (IS_DIGIT(c)) {
|
|
dec(c - ASCII_ZERO);
|
|
printf("%s", token + 1);
|
|
} else if (c == 'x' && strlen(token) > 4) {
|
|
hex(token + 1); //exclude x
|
|
printf("%s", token + 4);
|
|
} else {
|
|
printf("%s", token);
|
|
}
|
|
token = strtok(NULL, "^");
|
|
}
|
|
printf("</span>");
|
|
}
|
|
|
|
// O(n)
|
|
void a(const char* str) {
|
|
//find instance of ^^
|
|
//replace with ^
|
|
//concatenate with rest of the string
|
|
char *copy;
|
|
copy = calloc(strlen(str) + 1, sizeof(char));
|
|
strcpy(copy, str);
|
|
char *pos = copy;
|
|
while (pos = strstr(pos, "^^")) {
|
|
strcpy(pos, (pos + 1));
|
|
}
|
|
b(copy);
|
|
free(copy);
|
|
}
|
|
|
|
void testconversion(int r, int g, int b) {
|
|
struct Rgb x;
|
|
x.r = r;
|
|
x.g = g;
|
|
x.b = b;
|
|
struct Hls y;
|
|
cvt_hls(&y, &x);
|
|
printf("%d %f %f\n", y.h, y.s, y.l);
|
|
}
|
|
|
|
void testconvhls(int h, float s, float l) {
|
|
struct Hls x;
|
|
x.h = h;
|
|
x.s = s;
|
|
x.l = l;
|
|
struct Rgb y;
|
|
cvt_rgb(&y, &x);
|
|
printf("%d %d %d\n", y.r, y.g, y.b);
|
|
}
|
|
|
|
int main() {
|
|
/* a("^xf00Unregistered Player^7");
|
|
a("^9[^1S^9]^x469Kom^0ier^7");
|
|
a("^9sjn^5|^9F^5e^9tus^7");
|
|
a("^0[^7>>^0]^xaefdizzy^7"); */
|
|
/* testconversion(10, 15, 12);
|
|
testconversion(5, 5, 5);
|
|
testconversion(3, 15, 10);
|
|
testconversion(7, 8, 9);
|
|
testconvhls(144, 0.20, 0.5);
|
|
testconvhls(0, 0, 0.2);
|
|
testconvhls(154, 0.67, 0.035);
|
|
testconvhls(210, 0.125, 0.03);
|
|
testconvhls(60, 1, 0.25);
|
|
testconvhls(180, 1, 0.25);
|
|
testconvhls(240, 1, 0.25); */
|
|
testconversion(0, 0, 0);
|
|
testconversion(255, 255, 255);
|
|
testconversion(255, 0, 0);
|
|
testconversion(0, 255, 0);
|
|
testconversion(0, 0, 255);
|
|
testconversion(255, 255, 0);
|
|
testconversion(0, 255, 255);
|
|
testconversion(255, 0, 255);
|
|
testconversion(192, 192, 192);
|
|
testconversion(128, 128, 128);
|
|
testconversion(128, 0, 0);
|
|
testconversion(128, 128, 0);
|
|
testconversion(0, 128, 0);
|
|
testconversion(128, 0, 128);
|
|
testconversion(128, 0, 128);
|
|
testconversion(0, 128, 128);
|
|
testconversion(0, 0, 128);
|
|
} |