login

<     >

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);