2021-01-18 19:33:19 (UTC-03:00)
Marcel Rodrigues <marcelgmr@gmail.com>
Merge pull request #8 from rdebath/patch-palettes Patch palette into GIF file.
diff --git a/default.h b/default.h index 4babf69..a05707e 100644 --- a/default.h +++ b/default.h @@ -1,4 +1,4 @@ -static uint8_t def_plt[0x30] = { +static uint8_t plt_xterm[0x30] = { 0x00, 0x00, 0x00, 0xCD, 0x00, 0x00, 0x00, 0xCD, 0x00, @@ -6,7 +6,7 @@ static uint8_t def_plt[0x30] = { 0x00, 0x00, 0xEE, 0xCD, 0x00, 0xCD, 0x00, 0xCD, 0xCD, - 0xCD, 0xCD, 0xCD, + 0xE5, 0xE5, 0xE5, 0x7F, 0x7F, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, @@ -17,9 +17,86 @@ static uint8_t def_plt[0x30] = { 0xFF, 0xFF, 0xFF }; +static uint8_t plt_vga_ansi[0x30] = { + 0x00, 0x00, 0x00, + 0xAA, 0x00, 0x00, + 0x00, 0xAA, 0x00, + 0xAA, 0x55, 0x00, + 0x00, 0x00, 0xAA, + 0xAA, 0x00, 0xAA, + 0x00, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, + 0x55, 0x55, 0x55, + 0xFF, 0x55, 0x55, + 0x55, 0xFF, 0x55, + 0xFF, 0xFF, 0x55, + 0x55, 0x55, 0xFF, + 0xFF, 0x55, 0xFF, + 0x55, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF +}; + +static uint8_t plt_solarized_like_ansi[0x30] = { + 0x07, 0x36, 0x42, + 0xdc, 0x32, 0x2f, + 0x32, 0x99, 0x00, + 0xb5, 0x89, 0x00, + 0x26, 0x5e, 0xd2, + 0xd3, 0x36, 0x82, + 0x26, 0x96, 0x82, + 0x93, 0xa1, 0xa1, + 0x34, 0x63, 0x6f, + 0xff, 0x5f, 0x5c, + 0x5f, 0xe2, 0x2d, + 0xe2, 0xb6, 0x2d, + 0x26, 0x8b, 0xff, + 0xff, 0x63, 0xaf, + 0x53, 0xc3, 0xaf, + 0xc0, 0xce, 0xce +}; + +static uint8_t plt_solarized[0x30] = { + 0x07, 0x36, 0x42, + 0xdc, 0x32, 0x2f, + 0x85, 0x99, 0x00, + 0xb5, 0x89, 0x00, + 0x26, 0x8b, 0xd2, + 0xd3, 0x36, 0x82, + 0x2a, 0xa1, 0x98, + 0xee, 0xe8, 0xd5, + 0x00, 0x2b, 0x36, + 0xcb, 0x4b, 0x16, + 0x58, 0x6e, 0x75, + 0x65, 0x7b, 0x83, + 0x83, 0x94, 0x96, + 0x6c, 0x71, 0xc4, + 0x93, 0xa1, 0xa1, + 0xfd, 0xf6, 0xe3 +}; + +static uint8_t plt_putty[0x30] = { + 0x00, 0x00, 0x00, + 0xbb, 0x00, 0x00, + 0x00, 0xbb, 0x00, + 0xbb, 0xbb, 0x00, + 0x00, 0x00, 0xbb, + 0xbb, 0x00, 0xbb, + 0x00, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, + 0x55, 0x55, 0x55, + 0xff, 0x55, 0x55, + 0x55, 0xff, 0x55, + 0xff, 0xff, 0x55, + 0x55, 0x55, 0xff, + 0xff, 0x55, 0xff, + 0x55, 0xff, 0xff, + 0xff, 0xff, 0xff +}; + #define DEF_FORE 0x7 #define DEF_BACK 0x0 +static uint8_t * def_plt = plt_xterm; static uint16_t def_mode = M_AUTOWRAP | M_AUTORPT | M_CURSORVIS; static uint8_t def_attr = A_NORMAL; static uint8_t def_pair = (DEF_FORE << 4) | DEF_BACK; diff --git a/gif.c b/gif.c index f43192e..544574c 100644 --- a/gif.c +++ b/gif.c @@ -133,6 +133,12 @@ put_image(GIF *gif, uint16_t w, uint16_t h, uint16_t x, uint16_t y) { int nkeys, key_size, i, j; Node *node, *child, *root; + uint8_t id_packed = 0x00; + + if (gif->plt) { + id_packed &= ~0x7; + id_packed |= 0x83; /* Local clut, 4 bits. */ + } root = malloc(sizeof(*root)); write(gif->fd, ",", 1); @@ -140,7 +146,11 @@ put_image(GIF *gif, uint16_t w, uint16_t h, uint16_t x, uint16_t y) write_num(gif->fd, y); write_num(gif->fd, w); write_num(gif->fd, h); - write(gif->fd, (uint8_t []) {0x00, 0x04}, 2); + write(gif->fd, &id_packed, 1); + if (id_packed & 0x80) + write(gif->fd, gif->plt, 3<<((id_packed & 0x7)+1)); + + write(gif->fd, "\x04", 1); /* Min code size */ root = node = new_trie(&nkeys); key_size = 5; put_key(gif, 0x10, key_size); /* clear code */ @@ -216,6 +226,10 @@ add_frame(GIF *gif, uint16_t d) if (d) set_delay(gif, d); + if (gif->plt_dirty) { + w = gif->w; h = gif->h; x = y = 0; + gif->plt_dirty = 0; + } else if (!get_bbox(gif, &w, &h, &x, &y)) { /* image's not changed; save one pixel just to add delay */ w = h = 1; diff --git a/gif.h b/gif.h index 951a4d8..b79e8d3 100644 --- a/gif.h +++ b/gif.h @@ -4,8 +4,9 @@ typedef struct GIF { uint16_t w, h; int fd; int offset; - uint8_t *cur, *old; + uint8_t *cur, *old, *plt; uint32_t partial; + uint8_t plt_dirty; uint8_t buffer[0xFF]; } GIF; diff --git a/main.c b/main.c index 0ba53de..8105f27 100644 --- a/main.c +++ b/main.c @@ -104,6 +104,14 @@ render(Term *term, Font *font, GIF *gif, uint16_t delay) draw_char(font, gif, code, pair, i, j); } } + + if (term->plt_local) + gif->plt = term->plt; + else + gif->plt = 0; + gif->plt_dirty |= term->plt_dirty; + term->plt_dirty = 0; + add_frame(gif, delay); } @@ -227,6 +235,7 @@ help(char *name) " -h lines Terminal height\n" " -w columns Terminal width\n" " -c on|off Show/hide cursor\n" + " -p palette Define color palette, '@help' for std else file.\n" " -q Quiet mode (don't show progress bar)\n" " -v Verbose mode (show parser logs)\n" , name); @@ -262,7 +271,7 @@ main(int argc, char *argv[]) options.width = size.ws_col; has_winsize = 1; } - while ((opt = getopt(argc, argv, "o:m:d:l:f:h:w:c:qv")) != -1) { + while ((opt = getopt(argc, argv, "o:m:d:l:f:h:w:c:p:qv")) != -1) { switch (opt) { case 'o': options.output = optarg; @@ -299,6 +308,9 @@ main(int argc, char *argv[]) case 'v': set_verbosity(1); break; + case 'p': + set_default_palette(optarg); + break; default: help(argv[0]); return 1; diff --git a/term.c b/term.c index b98a1bc..851588d 100644 --- a/term.c +++ b/term.c @@ -75,6 +75,83 @@ load_misc(Term *term) term->cs_index = term->save_misc.cs_index; } +void +set_default_palette(char * pname) +{ + static struct { + char * name; + uint8_t * plt; + } pal[] = { + { "xterm", plt_xterm }, + { "vga", plt_vga_ansi }, + { "sol_ansi", plt_solarized_like_ansi }, + { "solarized", plt_solarized }, + { "putty", plt_putty }, + { 0, 0} + }; + + if (pname[0] == '@') { + int i; + for(i=0; pal[i].name; i++) { + if (strcasecmp(pname+1, pal[i].name) == 0) { + def_plt = pal[i].plt; + return; + } + } + fprintf(stderr, "Known standard palette names are:\n"); + for(i=0; pal[i].name; i++) + fprintf(stderr, " @%s\n", pal[i].name); + exit(2); + } else { + FILE * fd; + char buf[BUFSIZ]; + Term * term = 0; + uint8_t * plt = malloc(sizeof(term->plt)); + memcpy(plt, def_plt, sizeof(term->plt)); + def_plt = plt; + + if ((fd = fopen(pname, "r")) == 0) { + perror(pname); exit(1); + } + while (fgets(buf, sizeof(buf), fd) != 0) { + char * s = buf, *e; + long cno = 0, colour = 0; + + while (*s == ' ' || *s == '\t') s++; + if (*s == '#') continue; + + if (strncasecmp(s, "color", 5) == 0) { + s += 5; + } else if (strncasecmp(s, "colour", 6) == 0) { + s += 6; + } else continue; + + // Only lines that match /^ *colou?r[0-9]+/i + if (*s < '0' || *s > '9') continue; + + cno = strtol(s, &e, 0); + if (s == e) goto bad_line; + if (cno < 0 || cno > 16) goto bad_line; + + s = e; + while (*s == ' ' || *s == '\t' || *s == '#' || *s == '=') s++; + colour = strtol(s, &e, 16); + if (e-s != 6) goto bad_line; + + plt[cno*3+0] = ((colour>>16) & 0xFF); + plt[cno*3+1] = ((colour>> 8) & 0xFF); + plt[cno*3+2] = ((colour ) & 0xFF); + continue; +bad_line: + fprintf(stderr, "Bad line in colour file: %s", buf); + exit(2); + } + + fclose(fd); + } + return; +} + static void reset(Term *term) { @@ -91,7 +168,11 @@ reset(Term *term) term->cs_index = 0; term->state = S_ANY; term->parlen = 0; + if (memcmp(term->plt, def_plt, sizeof(term->plt) != 0)) { + term->plt_dirty = 1; + } memcpy(term->plt, def_plt, sizeof(term->plt)); + term->plt_local = 0; for (i = 0; i < term->rows; i++) { term->addr[i] = &term->cells[i*term->cols]; for (j = 0; j < term->cols; j++) @@ -113,6 +194,7 @@ new_term(int rows, int cols) term->addr = (Cell **) &term[1]; term->cells = (Cell *) &term->addr[rows]; reset(term); + term->plt_dirty = 0; return term; } @@ -391,6 +473,44 @@ escseq(Term *term, uint8_t byte) } static int +do_linux_osc(Term *term) +{ + int i; + uint8_t buf[4] = {0,0,0,0}; + if (term->partial[0] == 'R') + { + if (memcmp(term->plt, def_plt, sizeof(term->plt) != 0)) + term->plt_dirty = 1; + memcpy(term->plt, def_plt, sizeof(term->plt)); + term->plt_local = 0; + return 1; + } + if (term->partial[0] != 'P' || term->parlen != 8) + return 0; + + for (i=1; i<8; i++) { + /* isxdigit is locale broken */ + int ch = term->partial[i]; + if (ch >= '0' && ch <= '9') + buf[i>>1] = (buf[i>>1] << 4) + (ch - '0'); + else if (ch >= 'a' && ch <= 'f') + buf[i>>1] = (buf[i>>1] << 4) + (ch - 'a' + 10); + else if (ch >= 'A' && ch <= 'F') + buf[i>>1] = (buf[i>>1] << 4) + (ch - 'A' + 10); + else + return 0; + } + for(i=0; i<3; i++) { + if (term->plt[buf[0]*3+i] != buf[i+1]) { + term->plt[buf[0]*3+i] = buf[i+1]; + term->plt_local = term->plt_dirty = 1; + } + } + + return 1; +} + +static int getparams(char *partial, int *params, int n) { char *next; @@ -929,6 +1049,14 @@ parse(Term *term, uint8_t byte) PARCAT(term, byte); else term->state = S_STR; + + if (term->partial[0] == 'P' && term->parlen == 8) { + if (do_linux_osc(term)) + RESET_STATE(term); + } else if (term->partial[0] == 'R' && term->parlen == 1) { + if (do_linux_osc(term)) + RESET_STATE(term); + } } break; case S_UNI: diff --git a/term.h b/term.h index 58fd8a6..1bf5384 100644 --- a/term.h +++ b/term.h @@ -74,8 +74,10 @@ typedef struct Term { int unilen; uint8_t partial[MAX_PARTIAL]; uint8_t plt[0x30]; + uint8_t plt_local, plt_dirty; } Term; void set_verbosity(int level); Term *new_term(int rows, int cols); void parse(Term *term, uint8_t byte); +void set_default_palette(char * optarg);