Skip to content

Instantly share code, notes, and snippets.

@saitoha
Last active May 2, 2019 10:17
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save saitoha/be56f3b58c5212abe3f76a13578a548d to your computer and use it in GitHub Desktop.
Save saitoha/be56f3b58c5212abe3f76a13578a548d to your computer and use it in GitHub Desktop.
Add SIXEL graphics support for rxvt-unicode.
diff --git a/src/Makefile.in b/src/Makefile.in
index 18acb39e..ef2e7a40 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -40,7 +40,7 @@ COMMON = \
screen.o scrollbar.o scrollbar-next.o scrollbar-rxvt.o \
scrollbar-xterm.o scrollbar-plain.o xdefaults.o encoding.o \
rxvttoolkit.o rxvtutil.o keyboard.o rxvtimg.o \
- ev_cpp.o fdpass_wrapper.o ptytty_wrapper.o @PERL_O@
+ ev_cpp.o fdpass_wrapper.o ptytty_wrapper.o sixel.o @PERL_O@
COMMON_DAEMON = rxvtdaemon.o
@@ -289,3 +289,5 @@ rxvtperl.o: ../libptytty/src/estl.h emman.h rxvtfont.h rxvttoolkit.h
rxvtperl.o: callback.h rxvtimg.h scrollbar.h ../libptytty/src/libptytty.h
rxvtperl.o: rxvtperl.h hookinc.h rsinc.h optinc.h keyboard.h perlxsi.c
rxvtperl.o: iom_perl.h
+sixel.o: sixel.h
+sixel_hls.o: sixel_hls.h
diff --git a/src/command.C b/src/command.C
index ed376ed1..e9a9072c 100644
--- a/src/command.C
+++ b/src/command.C
@@ -51,6 +51,7 @@
#include "rxvtperl.h"
#include "version.h"
#include "command.h"
+#include "sixel.h"
#ifdef KEYSYM_RESOURCE
# include "keyboard.h"
@@ -2865,6 +2866,8 @@ rxvt_term::process_csi_seq ()
case '?':
if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't')
process_terminal_mode (ch, priv, nargs, arg);
+ else if (ch == 'S')
+ process_graphics_attributes (nargs, arg);
break;
case '!':
@@ -3262,15 +3265,215 @@ rxvt_term::get_to_st (unicode_t &ends_how)
void
rxvt_term::process_dcs_seq ()
{
- /*
- * Not handled yet
- */
-
- unicode_t eh;
- char *s = get_to_st (eh);
- if (s)
- free (s);
+ unicode_t ch;
+ unsigned char c;
+ const int max_params = 16;
+ int params[max_params] = { 0 };
+ int nparams = 0;
+ int cmd = 0;
+ enum {
+ DCS_START,
+ DCS_PARAM,
+ DCS_INTERMEDIATE,
+ DCS_PASSTHROUGH,
+ DCS_IGNORE,
+ DCS_ESC
+ };
+ int st = DCS_START;
+ int x, y;
+ sixel_state_t sixel_st = { PS_GROUND };
+ imagelist_t *new_image;
+ line_t l;
+
+ while (1) {
+ if ((ch = next_char ()) == NOCHAR) {
+ pty_fill ();
+ continue;
+ }
+ c = ch & 0xff;
+ switch (st) {
+ case DCS_START:
+ case DCS_PARAM:
+ switch (c) {
+ case '\030': /* CAN */
+ goto end;
+ case '\032': /* SUB */
+ st = DCS_IGNORE;
+ break;
+ case '\033':
+ st = DCS_ESC;
+ break;
+ case ' ' ... '/':
+ cmd = cmd << 8 | c;
+ st = cmd > (0xff << 16) ? DCS_IGNORE : DCS_INTERMEDIATE;
+ break;
+ case '0' ... '9':
+ params[nparams] = params[nparams] * 10 + c - '0';
+ st = params[nparams] > 256 ? DCS_IGNORE : DCS_PARAM;
+ break;
+ case ';':
+ if (++nparams == max_params)
+ st = DCS_IGNORE;
+ else
+ params[nparams] = 0;
+ break;
+ case ':':
+ st = DCS_IGNORE;
+ break;
+ case '<' ... '?':
+ cmd = cmd << 8 | c;
+ st = cmd > (0xff << 16) ? DCS_IGNORE : DCS_PARAM;
+ break;
+ case '@' ... '~':
+ cmd = cmd << 8 | c;
+ st = cmd > (0xff << 16) ? DCS_IGNORE : DCS_PASSTHROUGH;
+ break;
+ default:
+ st = DCS_IGNORE;
+ break;
+ }
+ break;
+ case DCS_INTERMEDIATE:
+ switch (c) {
+ case '\030': /* CAN */
+ goto end;
+ case '\032': /* SUB */
+ st = DCS_IGNORE;
+ break;
+ case '\033':
+ st = DCS_ESC;
+ break;
+ case ' ' ... '/':
+ cmd = cmd << 8 | c;
+ st = cmd > (0xff << 16) ? DCS_IGNORE : DCS_INTERMEDIATE;
+ break;
+ case '@' ... '~':
+ cmd = cmd << 8 | c;
+ st = cmd > (0xff << 16) ? DCS_IGNORE : DCS_PASSTHROUGH;
+ break;
+ default:
+ st = DCS_IGNORE;
+ break;
+ }
+ break;
+ case DCS_PASSTHROUGH:
+ switch (c) {
+ case '\030': /* CAN */
+ goto end;
+ case '\032': /* SUB */
+ st = DCS_IGNORE;
+ break;
+ case '\033':
+ st = DCS_ESC;
+ break;
+ default:
+ switch (cmd) {
+ case 'q': /* DECSIXEL */
+ switch (sixel_st.state) {
+ case PS_GROUND:
+ {
+ rgba fg = pix_colors[Color_fg];
+ rgba bg = pix_colors[Color_bg];
+ sixel_parser_init(&sixel_st,
+ fg.b >> 8 << 16 | fg.g >> 8 << 8 | fg.r >> 8,
+ bg.b >> 8 << 16 | bg.g >> 8 << 8 | bg.r >> 8,
+ 1, fwidth, fheight);
+ }
+ break;
+ default:
+ sixel_parser_parse(&sixel_st, &c, 1);
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ break;
+ case DCS_IGNORE:
+ switch (c) {
+ case '\030': /* CAN */
+ goto end;
+ case '\032': /* SUB */
+ st = DCS_IGNORE;
+ break;
+ case '\033':
+ st = DCS_ESC;
+ break;
+ default:
+ st = DCS_IGNORE;
+ break;
+ }
+ break;
+ case DCS_ESC:
+ switch (c) {
+ case '\\':
+ switch (cmd) {
+ case 'q': /* DECSIXEL */
+ new_image = (imagelist_t *)rxvt_calloc (1, sizeof(imagelist_t));
+ new_image->pixels = (unsigned char *)rxvt_malloc (sixel_st.image.width * sixel_st.image.height * 4);
+ (void) sixel_parser_finalize (&sixel_st, new_image->pixels);
+ sixel_parser_deinit(&sixel_st);
+ new_image->col = screen.cur.col;
+ new_image->row = screen.cur.row + virtual_lines;
+ new_image->pxwidth = sixel_st.image.width;
+ new_image->pxheight = sixel_st.image.height;
+ if (this->images) {
+ imagelist_t *im;
+ for (im = this->images; im->next; im = im->next)
+ ;
+ new_image->prev = im;
+ im->next = new_image;
+ } else {
+ this->images = new_image;
+ }
+ for (y = 0; y < Pixel2Row (new_image->pxheight + fheight - 1); ++y)
+ {
+ if ((priv_modes & PrivMode_SixelDisplay))
+ l = ROW(screen.cur.row + y);
+ else
+ l = ROW(screen.cur.row);
+ for (x = 0; x < min (ncol - screen.cur.col, Pixel2Col (new_image->pxwidth + fwidth - 1)); ++x)
+ {
+ l.t[screen.cur.col + x] = CHAR_IMAGE;
+ l.r[screen.cur.col + x] = RS_None;
+ }
+ if (!(priv_modes & PrivMode_SixelDisplay))
+ {
+ if (y == Pixel2Row (new_image->pxheight + fheight - 1) - 1) // on last row
+ {
+ if ((priv_modes & PrivMode_SixelScrsRight))
+ {
+ screen.cur.col += x;
+ }
+ else
+ {
+ scr_index (UP);
+ if ((priv_modes & PrivMode_SixelScrsLeft))
+ scr_gotorc (0, 0, R_RELATIVE);
+ }
+ }
+ else
+ {
+ scr_index (UP);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ goto end;
+ default:
+ goto end;
+ }
+ default:
+ break;
+ }
+ }
+end:
return;
}
@@ -3695,6 +3898,7 @@ rxvt_term::process_terminal_mode (int mode, int priv ecb_unused, unsigned int na
#ifndef NO_BACKSPACE_KEY
{ 67, PrivMode_BackSpace }, // DECBKM
#endif
+ { 80, PrivMode_SixelDisplay }, // DECSDM sixel display mode
{ 1000, PrivMode_MouseX11 },
{ 1002, PrivMode_MouseBtnEvent },
{ 1003, PrivMode_MouseAnyEvent },
@@ -3715,6 +3919,10 @@ rxvt_term::process_terminal_mode (int mode, int priv ecb_unused, unsigned int na
{ 1049, PrivMode_Screen }, /* xterm extension, clear screen on ti rather than te */
// 1051, 1052, 1060, 1061 keyboard emulation NYI
{ 2004, PrivMode_BracketPaste },
+ // 7730 sixel-scrolls-left mode, originally proposed by mintty
+ { 7730, PrivMode_SixelScrsLeft },
+ // 8452 sixel-scrolls-right mode, originally proposed by RLogin
+ { 8452, PrivMode_SixelScrsRight },
};
if (nargs == 0)
@@ -4031,6 +4239,62 @@ rxvt_term::process_sgr_mode (unsigned int nargs, const int *arg)
}
}
+void
+rxvt_term::process_graphics_attributes (unsigned int nargs, const int *arg)
+{
+ if (nargs != 3)
+ return;
+ switch (arg[0])
+ {
+ case 1: /* number of sixel color palette */
+ switch (arg[1])
+ {
+ case 1: /* read */
+ tt_printf ("\033[?%d;%d;%dS", arg[0], 0, DECSIXEL_PALETTE_MAX);
+ break;
+ case 2: /* reset to default */
+ tt_printf ("\033[?%d;%d;%dS", arg[0], 0, DECSIXEL_PALETTE_MAX);
+ break;
+ case 3: /* set */
+ if (arg[2] == DECSIXEL_PALETTE_MAX)
+ tt_printf ("\033[?%d;%d;%dS", arg[0], 0, DECSIXEL_PALETTE_MAX);
+ else
+ tt_printf ("\033[?%d;%d;%dS", arg[0], 3, 0);
+ break;
+ case 4: /* read the maximum value */
+ tt_printf ("\033[?%d;%d;%dS", arg[0], 0, DECSIXEL_PALETTE_MAX);
+ break;
+ default:
+ tt_printf ("\033[?%d;%d;%dS", arg[0], 2, 0);
+ break;
+ }
+ break;
+ case 2: /* geometory of sixel graphics */
+ switch (arg[1])
+ {
+ case 1: /* read */
+ tt_printf ("\033[?%d;%d;%d;%dS", arg[0], 0, ncol * fwidth, nrow * fheight);
+ break;
+ case 2: /* reset to default */
+ tt_printf ("\033[?%d;%d;%d;%dS", arg[0], 3, 0, 0);
+ break;
+ case 3: /* set */
+ tt_printf ("\033[?%d;%d;%d;%dS", arg[0], 3, 0, 0);
+ break;
+ case 4: /* read the maximum value */
+ tt_printf ("\033[?%d;%d;%d;%dS", arg[0], 3, 0, 0);
+ break;
+ default:
+ tt_printf ("\033[?%d;%d;%d;%dS", arg[0], 2, 0, 0);
+ break;
+ }
+ break;
+ default:
+ tt_printf ("\033[?%d;%d;%dS", arg[0], 1, 0);
+ break;
+ }
+}
+
void
rxvt_term::set_cursor_style (int style)
{
diff --git a/src/command.h b/src/command.h
index cf356c4d..319eaba0 100644
--- a/src/command.h
+++ b/src/command.h
@@ -58,7 +58,7 @@
* two strings should be the same so that identical read (2) calls may be
* used.
*/
-#define VT100_ANS "\033[?1;2c" /* vt100 answerback */
+#define VT100_ANS "\033[?1;2;4c" /* vt100 answerback(1;2) + sixel graphics(4) */
#ifndef ESCZ_ANSWER
# define ESCZ_ANSWER VT100_ANS /* obsolete ANSI ESC[c */
#endif
diff --git a/src/rxvt.h b/src/rxvt.h
index 5e5ee2df..267ba923 100644
--- a/src/rxvt.h
+++ b/src/rxvt.h
@@ -389,6 +389,7 @@ enum {
C0_CAN, C0_EM , C0_SUB, C0_ESC, C0_IS4, C0_IS3, C0_IS2, C0_IS1,
};
#define CHAR_ST 0x9c /* 0234 */
+#define CHAR_IMAGE 0x01 /* special character for image area */
/*
* XTerm Operating System Commands: ESC ] Ps;Pt (ST|BEL)
@@ -576,6 +577,15 @@ enum {
#define PrivMode_ExtMouseRight (1UL<<24) // xterm pseudo-utf-8, but works in non-utf-8-locales
#define PrivMode_BlinkingCursor (1UL<<25)
#define PrivMode_FocusEvent (1UL<<26)
+#define PrivMode_SixelDisplay (1UL<<27) // sixel display mode
+/* DECSET 7730: sixel scrolling end position
+ * on: sixel scrolling moves cursor to beginning of the line
+ * off(default): sixel scrolling moves cursor to left of graphics */
+#define PrivMode_SixelScrsLeft (1UL<<28)
+/* DECSET 8452: sixel scrolling end position right
+ * on: sixel scrolling leaves cursor to right of graphic
+ * off(default): position after sixel depends on sixel_scrolls_left */
+#define PrivMode_SixelScrsRight (1UL<<29)
#define PrivMode_mouse_report (PrivMode_MouseX10|PrivMode_MouseX11|PrivMode_MouseBtnEvent|PrivMode_MouseAnyEvent)
@@ -901,6 +911,7 @@ struct TermWin_t
int term_start; /* term lines start here */
int view_start; /* scrollback view starts here */
int top_row; /* topmost row index of scrollback */
+ int virtual_lines;
Window parent; /* parent identifier */
Window vt; /* vt100 window */
GC gc; /* GC for drawing */
@@ -984,6 +995,18 @@ enum {
Opt_count
};
+struct imagelist_t
+{
+ imagelist_t *prev, *next;
+ unsigned char *pixels;
+ Drawable drawable;
+ void *storage;
+ int col;
+ int row;
+ int pxwidth;
+ int pxheight;
+};
+
/* ------------------------------------------------------------------------- */
struct rxvt_vars : TermWin_t
@@ -1005,6 +1028,7 @@ struct rxvt_vars : TermWin_t
#ifdef OFF_FOCUS_FADING
rxvt_color pix_colors_unfocused[TOTAL_COLORS];
#endif
+ imagelist_t *images;
};
struct rxvt_term : zero_initialized, rxvt_vars, rxvt_screen
@@ -1297,6 +1321,7 @@ struct rxvt_term : zero_initialized, rxvt_vars, rxvt_screen
int privcases (int mode, unsigned long bit);
void process_terminal_mode (int mode, int priv, unsigned int nargs, const int *arg);
void process_sgr_mode (unsigned int nargs, const int *arg);
+ void process_graphics_attributes (unsigned int nargs, const int *arg);
void set_cursor_style (int style);
// init.C
void init (stringvec *argv, stringvec *envv);
diff --git a/src/screen.C b/src/screen.C
index f3c6d576..160fc28d 100644
--- a/src/screen.C
+++ b/src/screen.C
@@ -30,6 +30,174 @@
#include "rxvtperl.h" /* NECESSARY */
#include <inttypes.h>
+#include <stdio.h>
+
+// tempfile_t manipulation
+
+typedef struct {
+ FILE *fp;
+ unsigned int ref_counter;
+} tempfile_t;
+
+typedef struct {
+ tempfile_t *tempfile;
+ size_t position;
+} temp_storage_t;
+
+static tempfile_t *tempfile_current = NULL;
+static size_t tempfile_num = 0;
+static size_t const TEMPFILE_MAX_SIZE = 1024 * 1024 * 16; /* 16MB */
+static size_t const TEMPFILE_MAX_NUM = 16;
+
+static tempfile_t *
+tempfile_new (void)
+{
+ tempfile_t *tempfile;
+ FILE *fp;
+
+ fp = tmpfile();
+ if (!fp)
+ return NULL;
+
+ tempfile = (tempfile_t *)rxvt_malloc (sizeof(tempfile_t));
+ if (!tempfile)
+ return NULL;
+
+ tempfile->fp = fp;
+ tempfile->ref_counter = 1;
+
+ tempfile_num++;
+
+ return tempfile;
+}
+
+static void
+tempfile_destroy(tempfile_t *tempfile)
+{
+ if (tempfile == tempfile_current)
+ tempfile_current = NULL;
+ fclose((FILE *)tempfile->fp);
+ free (tempfile);
+ tempfile_num--;
+}
+
+static void
+tempfile_ref(tempfile_t *tempfile)
+{
+ tempfile->ref_counter++;
+}
+
+static void
+tempfile_deref(tempfile_t *tempfile)
+{
+ if (--tempfile->ref_counter == 0)
+ tempfile_destroy(tempfile);
+}
+
+static size_t
+tempfile_size(tempfile_t *tempfile)
+{
+ struct stat info;
+
+ fstat(fileno(tempfile->fp), &info);
+
+ return info.st_size;
+}
+
+static tempfile_t *
+tempfile_get(void)
+{
+ size_t size;
+
+ if (!tempfile_current)
+ {
+ tempfile_current = tempfile_new();
+ return tempfile_current;
+ }
+
+ /* get file size */
+ size = tempfile_size(tempfile_current);
+
+ /* if the file size reaches TEMPFILE_MAX_SIZE, return new temporary file */
+ if (size > TEMPFILE_MAX_SIZE)
+ {
+ tempfile_current = tempfile_new();
+ return tempfile_current;
+ }
+
+ /* increment reference counter */
+ tempfile_ref (tempfile_current);
+
+ return tempfile_current;
+}
+
+static bool
+tempfile_write(tempfile_t *tempfile, void *p, size_t pos, size_t size)
+{
+ size_t nbytes;
+
+ fseek ((FILE *)tempfile->fp, pos, SEEK_SET);
+ nbytes = fwrite(p, 1, size, tempfile->fp);
+ if (nbytes != size)
+ return false;
+
+ return true;
+}
+
+static bool
+tempfile_read(tempfile_t *tempfile, void *p, size_t pos, size_t size)
+{
+ size_t nbytes;
+
+ fflush((FILE *)tempfile->fp);
+ fseek((FILE *)tempfile->fp, pos, SEEK_SET);
+ nbytes = fread (p, 1, size, (FILE *)tempfile->fp);
+ if (nbytes != size)
+ return false;
+
+ return true;
+}
+
+// temp_storage_t implementation
+
+static temp_storage_t *
+storage_create(void)
+{
+ temp_storage_t *storage;
+ tempfile_t *tempfile;
+
+ tempfile = tempfile_get ();
+ if (!tempfile)
+ return NULL;
+
+ storage = (temp_storage_t *)rxvt_malloc (sizeof(temp_storage_t));
+ if (!storage)
+ return NULL;
+
+ storage->tempfile = tempfile;
+ storage->position = tempfile_size(storage->tempfile);
+
+ return storage;
+}
+
+static void
+storage_destroy (temp_storage_t *storage)
+{
+ tempfile_deref (storage->tempfile);
+ free (storage);
+}
+
+static bool
+storage_write(temp_storage_t *storage, void *p, size_t size)
+{
+ return tempfile_write (storage->tempfile, p, storage->position, size);
+}
+
+static bool
+storage_read(temp_storage_t *storage, void *p, size_t size)
+{
+ return tempfile_read (storage->tempfile, p, storage->position, size);
+}
static inline void
fill_text (text_t *start, text_t value, int len)
@@ -673,6 +841,7 @@ rxvt_term::scr_scroll_text (int row1, int row2, int count) NOTHROW
// scroll everything up 'count' lines
term_start = (term_start + count) % total_rows;
+ virtual_lines += count;
// now copy lines below the scroll region bottom to the
// bottom of the screen again, so they look as if they
@@ -2446,6 +2615,168 @@ rxvt_term::scr_refresh () NOTHROW
} /* for (col....) */
} /* for (row....) */
+ /*
+ * F: draw sixel images
+ */
+ if (images)
+ {
+ imagelist_t *im;
+ GC clipgc;
+ int trow, brow; // top, bottom
+ int nlimit = 256; // num of allocated rects
+ XRectangle *rects = NULL, *itrect = NULL, *p = NULL;
+ int n, x, y;
+ XImage xi;
+
+ // for each images
+ for (im = images; im; im = im->next)
+ {
+ trow = im->row - virtual_lines;
+ brow = trow + (im->pxheight + fheight - 1) / fheight;
+
+ // if the image is out of scrollback, delete it.
+ if (brow <= top_row)
+ {
+ if (im->prev)
+ im->prev->next = im->next;
+ else
+ images = im->next;
+ if (im->next)
+ im->next->prev = im->prev;
+ if (im->drawable)
+ XFreePixmap (dpy, im->drawable);
+ if (im->storage)
+ storage_destroy ((temp_storage_t *)im->storage);
+ free (im->pixels);
+ free (im);
+ continue;
+ }
+
+ // if the image is out of view, serialize into the storage object(im->storage).
+ if (trow >= view_start + nrow || brow <= view_start)
+ {
+ if (! im->storage)
+ {
+ if (im->drawable)
+ {
+ XFreePixmap (dpy, im->drawable);
+ im->drawable = NULL;
+ }
+ if (! im->storage)
+ im->storage = storage_create();
+ if (! storage_write ((temp_storage_t *)im->storage, im->pixels, im->pxwidth * im->pxheight * 4))
+ break;
+ free (im->pixels);
+ im->pixels = NULL;
+ }
+ continue;
+ }
+
+ // ensure the pixmap(im->drawable) is available
+ if (! im->drawable)
+ {
+ // ensure the in-memory pixel buffer(im->pixels) is available
+ if (! im->pixels)
+ {
+ im->pixels = (unsigned char *)rxvt_malloc (im->pxwidth * im->pxheight * 4);
+ if (! storage_read ((temp_storage_t *)im->storage, im->pixels, im->pxwidth * im->pxheight * 4))
+ break;
+ storage_destroy ((temp_storage_t *)im->storage);
+ im->storage = NULL;
+ assert (im->pixels);
+ }
+
+ // create the pixmap object(im->drawable).
+ XInitImage (&xi);
+ xi.format = ZPixmap;
+ xi.data = (char *)im->pixels;
+ xi.width = im->pxwidth;
+ xi.height = im->pxheight;
+ xi.xoffset = 0;
+ xi.byte_order = LSBFirst;
+ xi.bitmap_bit_order = MSBFirst;
+ xi.bits_per_pixel = 32;
+ xi.bytes_per_line = im->pxwidth * 4;
+ xi.bitmap_unit = 32;
+ xi.bitmap_pad = 32;
+ xi.depth = 24;
+ im->drawable = XCreatePixmap(dpy, vt, im->pxwidth, im->pxheight, DefaultDepth (dpy, 0));
+ XPutImage (dpy, im->drawable, gc, &xi, 0, 0, 0, 0, im->pxwidth, im->pxheight);
+ }
+
+ // XXX: this is shoddy work!!
+ // construct clipping rectangle array
+ itrect = rects = NULL;
+ for (y = trow - view_start; y < brow - view_start; y++) // for rows
+ {
+ if (y >= 0 && y < nrow)
+ {
+ // compare recent two clip rectangles, combine them if they has same (left, width).
+ if (itrect - rects > 0 && itrect->x == (itrect - 1)->x && itrect->width == (itrect - 1)->width)
+ {
+ // test whether itrect adjacent to itrect - 1
+ if ((itrect - 1)->y + (itrect - 1)->height == itrect->y)
+ {
+ itrect--;
+ itrect->height += fheight;
+ }
+ }
+
+ for (x = im->col; x < im->col + Pixel2Col (im->pxwidth + fwidth - 1) && x < ncol; x++) // for cols
+ {
+ // lazy initialization for rectangle array
+ if (!rects)
+ itrect = rects = (XRectangle *)rxvt_malloc (sizeof (XRectangle) * nlimit);
+ if (rects == NULL)
+ break;
+
+ // resize rectangle array
+ if (itrect - rects == nlimit)
+ {
+ p = (XRectangle *)rxvt_realloc (rects, sizeof (XRectangle) * (nlimit *= 2));
+ if (p == NULL)
+ break;
+ rects = p;
+ }
+
+ if (ROW(view_start + y).t[x] == CHAR_IMAGE)
+ {
+ // check if current cell is combinable with last clip rectangle
+ if (itrect - rects > 0 && (itrect - 1)->x + (itrect - 1)->width == Col2Pixel (x) && (itrect - 1)->y == Row2Pixel (y))
+ {
+ (itrect - 1)->width += fwidth;
+ }
+ else
+ {
+ // add new clip rectangle
+ itrect->x = Col2Pixel (x);
+ itrect->y = Row2Pixel (y);
+ itrect->width = fwidth;
+ itrect->height = fheight;
+ itrect++;
+ }
+ }
+ }
+ }
+ }
+
+ if (itrect - rects > 0) // if it should be drawn
+ {
+ clipgc = XCreateGC (dpy, vt, 0, 0);
+ // set clipping region
+ XSetClipRectangles (dpy, clipgc, 0, 0, rects, itrect - rects, YXSorted);
+ XCopyArea (dpy, im->drawable, vt,
+ clipgc, 0, 0,
+ im->pxwidth, im->pxheight,
+ (unsigned int)Width2Pixel (im->col),
+ (unsigned int)Height2Pixel (im->row - virtual_lines - view_start));
+ XFreeGC (dpy, clipgc);
+ }
+
+ free (rects);
+ }
+ }
+
/*
* G: cleanup cursor and display outline cursor if necessary
*/
diff --git a/src/sixel.C b/src/sixel.C
new file mode 100644
index 00000000..3e21c54a
--- /dev/null
+++ b/src/sixel.C
@@ -0,0 +1,681 @@
+// sixel.c (part of mintty)
+// originally written by kmiya@cluti (https://github.com/saitoha/sixel/blob/master/fromsixel.c)
+// Licensed under the terms of the GNU General Public License v3 or later.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h> /* isdigit */
+#include <string.h> /* memcpy */
+
+#include "sixel.h"
+
+#define SIXEL_XRGB(r,g,b) (((r) * 255 + 50) / 100) << 0 | \
+ (((g) * 255 + 50) / 100) << 8 | \
+ (((b) * 255 + 50) / 100) << 16
+
+static colour const sixel_default_color_table[] = {
+ SIXEL_XRGB(0, 0, 0), /* 0 Black */
+ SIXEL_XRGB(20, 20, 80), /* 1 Blue */
+ SIXEL_XRGB(80, 13, 13), /* 2 Red */
+ SIXEL_XRGB(20, 80, 20), /* 3 Green */
+ SIXEL_XRGB(80, 20, 80), /* 4 Magenta */
+ SIXEL_XRGB(20, 80, 80), /* 5 Cyan */
+ SIXEL_XRGB(80, 80, 20), /* 6 Yellow */
+ SIXEL_XRGB(53, 53, 53), /* 7 Gray 50% */
+ SIXEL_XRGB(26, 26, 26), /* 8 Gray 25% */
+ SIXEL_XRGB(33, 33, 60), /* 9 Blue* */
+ SIXEL_XRGB(60, 26, 26), /* 10 Red* */
+ SIXEL_XRGB(33, 60, 33), /* 11 Green* */
+ SIXEL_XRGB(60, 33, 60), /* 12 Magenta* */
+ SIXEL_XRGB(33, 60, 60), /* 13 Cyan* */
+ SIXEL_XRGB(60, 60, 33), /* 14 Yellow* */
+ SIXEL_XRGB(80, 80, 80), /* 15 Gray 75% */
+};
+
+/*
+ * Primary color hues:
+ * blue: 0 degrees
+ * red: 120 degrees
+ * green: 240 degrees
+ */
+int
+hls_to_rgb(int hue, int lum, int sat)
+{
+ double min, max;
+ int r, g, b;
+
+ if (sat == 0) {
+ r = g = b = lum;
+ }
+
+ /* https://wikimedia.org/api/rest_v1/media/math/render/svg/17e876f7e3260ea7fed73f69e19c71eb715dd09d */
+ max = lum + sat * (1.0 - (lum > 50 ? (((lum << 2) / 100.0) - 1.0): - (2 * (lum / 100.0) - 1.0))) / 2.0;
+
+ /* https://wikimedia.org/api/rest_v1/media/math/render/svg/f6721b57985ad83db3d5b800dc38c9980eedde1d */
+ min = lum - sat * (1.0 - (lum > 50 ? (((lum << 2) / 100.0) - 1.0): - (2 * (lum / 100.0) - 1.0))) / 2.0;
+
+ /* sixel hue color ring is roteted -120 degree from nowdays general one. */
+ hue = (hue + 240) % 360;
+
+ /* https://wikimedia.org/api/rest_v1/media/math/render/svg/937e8abdab308a22ff99de24d645ec9e70f1e384 */
+ switch (hue / 60) {
+ case 0: /* 0 <= hue < 60 */
+ r = max;
+ g = (min + (max - min) * (hue / 60.0));
+ b = min;
+ break;
+ case 1: /* 60 <= hue < 120 */
+ r = min + (max - min) * ((120 - hue) / 60.0);
+ g = max;
+ b = min;
+ break;
+ case 2: /* 120 <= hue < 180 */
+ r = min;
+ g = max;
+ b = (min + (max - min) * ((hue - 120) / 60.0));
+ break;
+ case 3: /* 180 <= hue < 240 */
+ r = min;
+ g = (min + (max - min) * ((240 - hue) / 60.0));
+ b = max;
+ break;
+ case 4: /* 240 <= hue < 300 */
+ r = (min + (max - min) * ((hue - 240) / 60.0));
+ g = min;
+ b = max;
+ break;
+ case 5: /* 300 <= hue < 360 */
+ r = max;
+ g = min;
+ b = (min + (max - min) * ((360 - hue) / 60.0));
+ break;
+ default:
+ break;
+ }
+
+ return SIXEL_XRGB(r, g, b);
+}
+
+static int
+set_default_color(sixel_image_t *image)
+{
+ int i;
+ int n;
+ int r;
+ int g;
+ int b;
+
+ /* palette initialization */
+ for (n = 1; n < 17; n++) {
+ image->palette[n] = sixel_default_color_table[n - 1];
+ }
+
+ /* colors 17-232 are a 6x6x6 color cube */
+ for (r = 0; r < 6; r++) {
+ for (g = 0; g < 6; g++) {
+ for (b = 0; b < 6; b++) {
+ image->palette[n++] = SIXEL_XRGB(r * 51, g * 51, b * 51);
+ }
+ }
+ }
+
+ /* colors 233-256 are a grayscale ramp, intentionally leaving out */
+ for (i = 0; i < 24; i++) {
+ image->palette[n++] = SIXEL_XRGB(i * 11, i * 11, i * 11);
+ }
+
+ for (; n < DECSIXEL_PALETTE_MAX; n++) {
+ image->palette[n] = SIXEL_XRGB(255, 255, 255);
+ }
+
+ return (0);
+}
+
+static int
+sixel_image_init(
+ sixel_image_t *image,
+ int width,
+ int height,
+ int fgcolor,
+ int bgcolor,
+ int use_private_register)
+{
+ int status = (-1);
+ size_t size;
+
+ size = (size_t)(width * height) * sizeof(sixel_color_no_t);
+ image->width = width;
+ image->height = height;
+ image->data = (sixel_color_no_t *)malloc(size);
+ image->ncolors = 2;
+ image->use_private_register = use_private_register;
+
+ if (image->data == NULL) {
+ status = (-1);
+ goto end;
+ }
+ memset(image->data, 0, size);
+
+ image->palette[0] = bgcolor;
+
+ if (image->use_private_register)
+ image->palette[1] = fgcolor;
+
+ image->palette_modified = 0;
+
+ status = (0);
+
+end:
+ return status;
+}
+
+
+static int
+image_buffer_resize(
+ sixel_image_t *image,
+ int width,
+ int height)
+{
+ int status = (-1);
+ size_t size;
+ sixel_color_no_t *alt_buffer;
+ int n;
+ int min_height;
+
+ size = (size_t)(width * height) * sizeof(sixel_color_no_t);
+ alt_buffer = (sixel_color_no_t *)malloc(size);
+ if (alt_buffer == NULL) {
+ /* free source image */
+ free(image->data);
+ image->data = NULL;
+ status = (-1);
+ goto end;
+ }
+
+ min_height = height > image->height ? image->height: height;
+ if (width > image->width) { /* if width is extended */
+ for (n = 0; n < min_height; ++n) {
+ /* copy from source image */
+ memcpy(alt_buffer + width * n,
+ image->data + image->width * n,
+ (size_t)image->width * sizeof(sixel_color_no_t));
+ /* fill extended area with background color */
+ memset(alt_buffer + width * n + image->width,
+ 0,
+ (size_t)(width - image->width) * sizeof(sixel_color_no_t));
+ }
+ } else {
+ for (n = 0; n < min_height; ++n) {
+ /* copy from source image */
+ memcpy(alt_buffer + width * n,
+ image->data + image->width * n,
+ (size_t)width * sizeof(sixel_color_no_t));
+ }
+ }
+
+ if (height > image->height) { /* if height is extended */
+ /* fill extended area with background color */
+ memset(alt_buffer + width * image->height,
+ 0,
+ (size_t)(width * (height - image->height)) * sizeof(sixel_color_no_t));
+ }
+
+ /* free source image */
+ free(image->data);
+
+ image->data = alt_buffer;
+ image->width = width;
+ image->height = height;
+
+ status = (0);
+
+end:
+ return status;
+}
+
+static void
+sixel_image_deinit(sixel_image_t *image)
+{
+ free(image->data);
+ image->data = NULL;
+}
+
+int
+sixel_parser_init(sixel_state_t *st,
+ colour fgcolor, colour bgcolor,
+ unsigned char use_private_register,
+ int cell_width, int cell_height)
+{
+ int status = (-1);
+
+ st->state = PS_DECSIXEL;
+ st->pos_x = 0;
+ st->pos_y = 0;
+ st->max_x = 0;
+ st->max_y = 0;
+ st->attributed_pan = 2;
+ st->attributed_pad = 1;
+ st->attributed_ph = 0;
+ st->attributed_pv = 0;
+ st->repeat_count = 1;
+ st->color_index = 16;
+ st->grid_width = cell_width;
+ st->grid_height = cell_height;
+ st->nparams = 0;
+ st->param = 0;
+
+ /* buffer initialization */
+ status = sixel_image_init(&st->image, 1, 1, fgcolor, bgcolor, use_private_register);
+
+ return status;
+}
+
+int
+sixel_parser_set_default_color(sixel_state_t *st)
+{
+ return set_default_color(&st->image);
+}
+
+int
+sixel_parser_finalize(sixel_state_t *st, unsigned char *pixels)
+{
+ int status = (-1);
+ int sx;
+ int sy;
+ sixel_image_t *image = &st->image;
+ int x, y;
+ sixel_color_no_t *src;
+ unsigned char *dst;
+ int color;
+
+ if (++st->max_x < st->attributed_ph)
+ st->max_x = st->attributed_ph;
+
+ if (++st->max_y < st->attributed_pv)
+ st->max_y = st->attributed_pv;
+
+ sx = (st->max_x + st->grid_width - 1) / st->grid_width * st->grid_width;
+ sy = (st->max_y + st->grid_height - 1) / st->grid_height * st->grid_height;
+
+ if (image->width > sx || image->height > sy) {
+ status = image_buffer_resize(image, sx, sy);
+ if (status < 0)
+ goto end;
+ }
+
+ if (image->use_private_register && image->ncolors > 2 && !image->palette_modified) {
+ status = set_default_color(image);
+ if (status < 0)
+ goto end;
+ }
+
+ src = st->image.data;
+ dst = pixels;
+ for (y = 0; y < st->image.height; ++y) {
+ for (x = 0; x < st->image.width; ++x) {
+ color = st->image.palette[*src++];
+ *dst++ = color >> 16 & 0xff; /* b */
+ *dst++ = color >> 8 & 0xff; /* g */
+ *dst++ = color >> 0 & 0xff; /* r */
+ dst++; /* a */
+ }
+ /* fill right padding with bgcolor */
+ for (; x < st->image.width; ++x) {
+ color = st->image.palette[0]; /* bgcolor */
+ *dst++ = color >> 16 & 0xff; /* b */
+ *dst++ = color >> 8 & 0xff; /* g */
+ *dst++ = color >> 0 & 0xff; /* r */
+ dst++; /* a */
+ }
+ }
+ /* fill bottom padding with bgcolor */
+ for (; y < st->image.height; ++y) {
+ for (x = 0; x < st->image.width; ++x) {
+ color = st->image.palette[0]; /* bgcolor */
+ *dst++ = color >> 16 & 0xff; /* b */
+ *dst++ = color >> 8 & 0xff; /* g */
+ *dst++ = color >> 0 & 0xff; /* r */
+ dst++; /* a */
+ }
+ }
+
+ status = (0);
+
+end:
+ return status;
+}
+
+/* convert sixel data into indexed pixel bytes and palette data */
+int
+sixel_parser_parse(sixel_state_t *st, unsigned char *p, size_t len)
+{
+ int status = (-1);
+ int n;
+ int i;
+ int x;
+ int y;
+ int bits;
+ int sixel_vertical_mask;
+ int sx;
+ int sy;
+ int c;
+ int pos;
+ unsigned char *p0 = p;
+ sixel_image_t *image = &st->image;
+
+ if (! image->data)
+ goto end;
+
+ while (p < p0 + len) {
+ switch (st->state) {
+ case PS_ESC:
+ goto end;
+
+ case PS_DECSIXEL:
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ p++;
+ break;
+ case '"':
+ st->param = 0;
+ st->nparams = 0;
+ st->state = PS_DECGRA;
+ p++;
+ break;
+ case '!':
+ st->param = 0;
+ st->nparams = 0;
+ st->state = PS_DECGRI;
+ p++;
+ break;
+ case '#':
+ st->param = 0;
+ st->nparams = 0;
+ st->state = PS_DECGCI;
+ p++;
+ break;
+ case '$':
+ /* DECGCR Graphics Carriage Return */
+ st->pos_x = 0;
+ p++;
+ break;
+ case '-':
+ /* DECGNL Graphics Next Line */
+ st->pos_x = 0;
+ if (st->pos_y < DECSIXEL_HEIGHT_MAX - 5 - 6)
+ st->pos_y += 6;
+ else
+ st->pos_y = DECSIXEL_HEIGHT_MAX + 1;
+ p++;
+ break;
+ default:
+ if (*p >= '?' && *p <= '~') { /* sixel characters */
+ if ((image->width < (st->pos_x + st->repeat_count) || image->height < (st->pos_y + 6))
+ && image->width < DECSIXEL_WIDTH_MAX && image->height < DECSIXEL_HEIGHT_MAX) {
+ sx = image->width * 2;
+ sy = image->height * 2;
+ while (sx < (st->pos_x + st->repeat_count) || sy < (st->pos_y + 6)) {
+ sx *= 2;
+ sy *= 2;
+ }
+
+ if (sx > DECSIXEL_WIDTH_MAX)
+ sx = DECSIXEL_WIDTH_MAX;
+ if (sy > DECSIXEL_HEIGHT_MAX)
+ sy = DECSIXEL_HEIGHT_MAX;
+
+ status = image_buffer_resize(image, sx, sy);
+ if (status < 0)
+ goto end;
+ }
+
+ if (st->color_index > image->ncolors)
+ image->ncolors = st->color_index;
+
+ if (st->pos_x + st->repeat_count > image->width)
+ st->repeat_count = image->width - st->pos_x;
+
+ if (st->repeat_count > 0 && st->pos_y - 5 < image->height) {
+ bits = *p - '?';
+ if (bits != 0) {
+ sixel_vertical_mask = 0x01;
+ if (st->repeat_count <= 1) {
+ for (i = 0; i < 6; i++) {
+ if ((bits & sixel_vertical_mask) != 0) {
+ pos = image->width * (st->pos_y + i) + st->pos_x;
+ image->data[pos] = st->color_index;
+ if (st->max_x < st->pos_x)
+ st->max_x = st->pos_x;
+ if (st->max_y < (st->pos_y + i))
+ st->max_y = st->pos_y + i;
+ }
+ sixel_vertical_mask <<= 1;
+ }
+ } else {
+ /* st->repeat_count > 1 */
+ for (i = 0; i < 6; i++) {
+ if ((bits & sixel_vertical_mask) != 0) {
+ c = sixel_vertical_mask << 1;
+ for (n = 1; (i + n) < 6; n++) {
+ if ((bits & c) == 0)
+ break;
+ c <<= 1;
+ }
+ for (y = st->pos_y + i; y < st->pos_y + i + n; ++y) {
+ for (x = st->pos_x; x < st->pos_x + st->repeat_count; ++x)
+ image->data[image->width * y + x] = st->color_index;
+ }
+ if (st->max_x < (st->pos_x + st->repeat_count - 1))
+ st->max_x = st->pos_x + st->repeat_count - 1;
+ if (st->max_y < (st->pos_y + i + n - 1))
+ st->max_y = st->pos_y + i + n - 1;
+ i += (n - 1);
+ sixel_vertical_mask <<= (n - 1);
+ }
+ sixel_vertical_mask <<= 1;
+ }
+ }
+ }
+ }
+ if (st->repeat_count > 0)
+ st->pos_x += st->repeat_count;
+ st->repeat_count = 1;
+ }
+ p++;
+ break;
+ }
+ break;
+
+ case PS_DECGRA:
+ /* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ p++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ st->param = st->param * 10 + *p - '0';
+ if (st->param > DECSIXEL_PARAMVALUE_MAX)
+ st->param = DECSIXEL_PARAMVALUE_MAX;
+ p++;
+ break;
+ case ';':
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ st->param = 0;
+ p++;
+ break;
+ default:
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ if (st->nparams > 0)
+ st->attributed_pad = st->params[0];
+ if (st->nparams > 1)
+ st->attributed_pan = st->params[1];
+ if (st->nparams > 2 && st->params[2] > 0)
+ st->attributed_ph = st->params[2];
+ if (st->nparams > 3 && st->params[3] > 0)
+ st->attributed_pv = st->params[3];
+
+ if (st->attributed_pan <= 0)
+ st->attributed_pan = 1;
+ if (st->attributed_pad <= 0)
+ st->attributed_pad = 1;
+
+ if (image->width < st->attributed_ph ||
+ image->height < st->attributed_pv) {
+ sx = st->attributed_ph;
+ if (image->width > st->attributed_ph)
+ sx = image->width;
+
+ sy = st->attributed_pv;
+ if (image->height > st->attributed_pv)
+ sy = image->height;
+
+ sx = (sx + st->grid_width - 1) / st->grid_width * st->grid_width;
+ sy = (sy + st->grid_height - 1) / st->grid_height * st->grid_height;
+
+ if (sx > DECSIXEL_WIDTH_MAX)
+ sx = DECSIXEL_WIDTH_MAX;
+ if (sy > DECSIXEL_HEIGHT_MAX)
+ sy = DECSIXEL_HEIGHT_MAX;
+
+ status = image_buffer_resize(image, sx, sy);
+ if (status < 0)
+ goto end;
+ }
+ st->state = PS_DECSIXEL;
+ st->param = 0;
+ st->nparams = 0;
+ }
+ break;
+
+ case PS_DECGRI:
+ /* DECGRI Graphics Repeat Introducer ! Pn Ch */
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ p++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ st->param = st->param * 10 + *p - '0';
+ if (st->param > DECSIXEL_PARAMVALUE_MAX)
+ st->param = DECSIXEL_PARAMVALUE_MAX;
+ p++;
+ break;
+ default:
+ st->repeat_count = st->param;
+ if (st->repeat_count == 0)
+ st->repeat_count = 1;
+ st->state = PS_DECSIXEL;
+ st->param = 0;
+ st->nparams = 0;
+ break;
+ }
+ break;
+
+ case PS_DECGCI:
+ /* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */
+ switch (*p) {
+ case '\x1b':
+ st->state = PS_ESC;
+ p++;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ st->param = st->param * 10 + *p - '0';
+ if (st->param > DECSIXEL_PARAMVALUE_MAX)
+ st->param = DECSIXEL_PARAMVALUE_MAX;
+ p++;
+ break;
+ case ';':
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ st->param = 0;
+ p++;
+ break;
+ default:
+ st->state = PS_DECSIXEL;
+ if (st->nparams < DECSIXEL_PARAMS_MAX)
+ st->params[st->nparams++] = st->param;
+ st->param = 0;
+
+ if (st->nparams > 0) {
+ st->color_index = 1 + st->params[0]; /* offset 1(background color) added */
+ if (st->color_index < 0)
+ st->color_index = 0;
+ else if (st->color_index >= DECSIXEL_PALETTE_MAX)
+ st->color_index = DECSIXEL_PALETTE_MAX - 1;
+ }
+
+ if (st->nparams > 4) {
+ st->image.palette_modified = 1;
+ if (st->params[1] == 1) {
+ /* HLS */
+ if (st->params[2] > 360)
+ st->params[2] = 360;
+ if (st->params[3] > 100)
+ st->params[3] = 100;
+ if (st->params[4] > 100)
+ st->params[4] = 100;
+ image->palette[st->color_index]
+ = hls_to_rgb(st->params[2], st->params[3], st->params[4]);
+ } else if (st->params[1] == 2) {
+ /* RGB */
+ if (st->params[2] > 100)
+ st->params[2] = 100;
+ if (st->params[3] > 100)
+ st->params[3] = 100;
+ if (st->params[4] > 100)
+ st->params[4] = 100;
+ image->palette[st->color_index]
+ = SIXEL_XRGB(st->params[2], st->params[3], st->params[4]);
+ }
+ }
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ status = (0);
+
+end:
+ return status;
+}
+
+void
+sixel_parser_deinit(sixel_state_t *st)
+{
+ if (st)
+ sixel_image_deinit(&st->image);
+}
diff --git a/src/sixel.h b/src/sixel.h
new file mode 100644
index 00000000..1877b2bb
--- /dev/null
+++ b/src/sixel.h
@@ -0,0 +1,61 @@
+#ifndef SIXEL_H
+#define SIXEL_H
+
+#include "config.h"
+
+#define DECSIXEL_PARAMS_MAX 16
+#define DECSIXEL_PALETTE_MAX 65535
+#define DECSIXEL_PARAMVALUE_MAX 65535
+#define DECSIXEL_WIDTH_MAX 4096
+#define DECSIXEL_HEIGHT_MAX 4096
+
+typedef unsigned short sixel_color_no_t;
+typedef unsigned int colour;
+
+typedef struct sixel_image_buffer {
+ sixel_color_no_t *data;
+ int width;
+ int height;
+ colour palette[DECSIXEL_PALETTE_MAX];
+ sixel_color_no_t ncolors;
+ int palette_modified;
+ int use_private_register;
+} sixel_image_t;
+
+typedef enum parse_state {
+ PS_GROUND = 0,
+ PS_ESC = 1, /* ESC */
+ PS_DECSIXEL = 2, /* DECSIXEL body part ", $, -, ? ... ~ */
+ PS_DECGRA = 3, /* DECGRA Set Raster Attributes " Pan; Pad; Ph; Pv */
+ PS_DECGRI = 4, /* DECGRI Graphics Repeat Introducer ! Pn Ch */
+ PS_DECGCI = 5, /* DECGCI Graphics Color Introducer # Pc; Pu; Px; Py; Pz */
+} parse_state_t;
+
+typedef struct parser_context {
+ parse_state_t state;
+ int pos_x;
+ int pos_y;
+ int max_x;
+ int max_y;
+ int attributed_pan;
+ int attributed_pad;
+ int attributed_ph;
+ int attributed_pv;
+ int repeat_count;
+ int color_index;
+ int bgindex;
+ int grid_width;
+ int grid_height;
+ int param;
+ int nparams;
+ int params[DECSIXEL_PARAMS_MAX];
+ sixel_image_t image;
+} sixel_state_t;
+
+int sixel_parser_init(sixel_state_t *st, colour fgcolor, colour bgcolor, unsigned char use_private_register, int cell_width, int cell_height);
+int sixel_parser_parse(sixel_state_t *st, unsigned char *p, size_t len);
+int sixel_parser_set_default_color(sixel_state_t *st);
+int sixel_parser_finalize(sixel_state_t *st, unsigned char *pixels);
+void sixel_parser_deinit(sixel_state_t *st);
+
+#endif
@srlehn
Copy link

srlehn commented Apr 20, 2019

Hi,
src/Screen.C is missing an #include <sys/stat.h> for the stat type.

@redguitarist2141
Copy link

In urxvt with 32-bit color depth displays foreground-color rectangles instead of images

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment