nyancat

Unnamed repository; edit this file 'description' to name the repository.
git clone https://git.inz.fi/nyancat
Log | Files | Refs | README

commit 41cefd3da9852be69c40139eda82ed24b7a59d31
parent 27ed7c32a15c28ff85a91f55190972b00d1fbcac
Author: Santtu Lakkala <inz@inz.fi>
Date:   Mon, 20 Jul 2020 10:48:59 +0300

Implement 256 and 16 color modes

Diffstat:
Mnyancat.c | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 107 insertions(+), 12 deletions(-)

diff --git a/nyancat.c b/nyancat.c @@ -48,6 +48,7 @@ struct lolcat { bool was_bold; bool was_reverse; bool was_underline; + enum { TRUECOLOR, INDEXED256, INDEXED16 } mode; void (*write)(const char *buffer, size_t buflen, void *data); void *write_data; @@ -137,6 +138,7 @@ struct lolcat *lolcat_init(void (*write_cb)(const char *buffer, size_t buflen, rv->write_data = cbdata; rv->fg = 0xc0c0c0; rv->bg = 0x000000; + rv->mode = TRUECOLOR; return rv; } @@ -222,6 +224,52 @@ static int _add(int a, int b, double amount) CLAMP(bl, 0, 255); } +static inline uint8_t absd(uint8_t a, uint8_t b) +{ + if (a > b) + return a - b; + return b - a; +} + +static inline int _index16(uint32_t col, bool *bright) +{ + uint8_t r = col >> 16; + uint8_t g = (col >> 8) & 255; + uint8_t b = col & 255; + + uint8_t ri = ((uint16_t)r + 64) * 2 / 256; + uint8_t gi = ((uint16_t)g + 64) * 2 / 256; + uint8_t bi = ((uint16_t)b + 64) * 2 / 256; + + if (ri == 2 || gi == 2 || bi == 2) { + ri = r > 127U; + gi = g > 127U; + bi = b > 127U; + *bright = true; + } else { + *bright = false; + } + + return ri | bi << 1 | gi << 2; +} + +static inline int _index256(uint32_t col) +{ + uint8_t r = col >> 16; + uint8_t g = (col >> 8) & 255; + uint8_t b = col & 255; + uint8_t cr = r < 28 ? 0 : (r - 28) * 5 / 228 + 1; + uint8_t cb = b < 28 ? 0 : (b - 28) * 5 / 228 + 1; + uint8_t cg = g < 28 ? 0 : (g - 28) * 5 / 228 + 1; + + uint8_t gs = ((uint16_t)r + g + b) / 3 * 32 / 256; + + if (absd(cr * 40 + !!cr * 55, r) + absd(cg * 40 + !!cg * 55, g) + absd(cb + 40 + !!cb * 55, b) < + absd(gs, r) + absd(gs, g) + absd(gs, b)) + return cr * 36 + cg * 6 + cb + 16; + return g + 232; +} + static void _lc_colorize(struct lolcat *lc, const char *u8_char, size_t len) { char buffer[128] = "\x1b["; @@ -234,6 +282,17 @@ static void _lc_colorize(struct lolcat *lc, const char *u8_char, size_t len) return; } + if (lc->bold) + col = _bold(lc->fg); + else + col = lc->fg; + col = _add(rainbow(0.03, nyan(lc->x, lc->y)), col, 0.5); + + if (lc->mode == INDEXED16) + col = _index16(col, &lc->bold); + else if (lc->mode == INDEXED256) + col = _index256(col); + if ((lc->was_bold && !lc->bold) || (lc->was_reverse && !lc->reverse)) { lc->was_underline = false; @@ -260,16 +319,17 @@ static void _lc_colorize(struct lolcat *lc, const char *u8_char, size_t len) lc->was_reverse = true; } - if (lc->bold) - col = _bold(lc->fg); + if (lc->mode == INDEXED16) + bw += sprintf(bw, "3%dm%.*s", + col, (int)len, u8_char); + else if (lc->mode == INDEXED256) + bw += sprintf(bw, "38;5;%dm%.*s", + col, (int)len, u8_char); else - col = lc->fg; - col = _add(rainbow(0.03, nyan(lc->x, lc->y)), col, 0.5); - - bw += sprintf(bw, "38;2;%d;%d;%dm%.*s", - col >> 16, - (col >> 8) & 255, - col & 255, (int)len, u8_char); + bw += sprintf(bw, "38;2;%d;%d;%dm%.*s", + col >> 16, + (col >> 8) & 255, + col & 255, (int)len, u8_char); lc->write(buffer, bw - buffer, lc->write_data); } @@ -489,13 +549,19 @@ void lolcat_set_size(struct lolcat *lc, int w, int h) lc->h = h; } +static void usage() +{ + fprintf(stderr, "Usage: nyancat [-t2] [file...]\n"); + exit(0); +} + int main(int argc, char **argv) { struct lolcat *lc = lolcat_init(_write, stdout); char buffer[2048]; size_t used = 0; struct termios old_tio = { 0 }, new_tio; - int i; + int i = 1; struct winsize ws = { 0 }; @@ -503,7 +569,36 @@ int main(int argc, char **argv) !ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)) lolcat_set_size(lc, ws.ws_col, ws.ws_row); - if (argc < 2) { + while (i < argc) { + const char *opt; + if (argv[i][0] != '-' || argv[i][1] == '\0') + break; + if (argv[i][1] == '-' && argv[i][2] == '\0') { + i++; + break; + } + opt = &argv[i++][1]; + + while (*opt) { + switch (*opt++) { + case 't': + lc->mode = TRUECOLOR; + break; + case '1': + lc->mode = INDEXED16; + break; + case '2': + lc->mode = INDEXED256; + break; + case 'h': + default: + usage(); + break; + } + } + } + + if (i >= argc) { tcgetattr(STDIN_FILENO, &old_tio); new_tio = old_tio; @@ -533,7 +628,7 @@ int main(int argc, char **argv) fflush(stdout); tcsetattr(STDIN_FILENO, TCSANOW, &old_tio); } else { - for (i = 1; i < argc; i++) { + for (; i < argc; i++) { int fd; if (!strcmp(argv[i], "-")) fd = STDIN_FILENO;