1c23f9150Swiz /* $OpenBSD$ */ 2c23f9150Swiz 3c23f9150Swiz /* 4c23f9150Swiz * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com> 5c23f9150Swiz * 6c23f9150Swiz * Permission to use, copy, modify, and distribute this software for any 7c23f9150Swiz * purpose with or without fee is hereby granted, provided that the above 8c23f9150Swiz * copyright notice and this permission notice appear in all copies. 9c23f9150Swiz * 10c23f9150Swiz * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11c23f9150Swiz * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12c23f9150Swiz * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13c23f9150Swiz * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14c23f9150Swiz * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15c23f9150Swiz * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16c23f9150Swiz * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17c23f9150Swiz */ 18c23f9150Swiz 19c23f9150Swiz #include <sys/types.h> 20c23f9150Swiz 21c23f9150Swiz #include <stdlib.h> 22c23f9150Swiz #include <string.h> 23c23f9150Swiz 24c23f9150Swiz #include "tmux.h" 25c23f9150Swiz 26c23f9150Swiz #define SIXEL_WIDTH_LIMIT 10000 27c23f9150Swiz #define SIXEL_HEIGHT_LIMIT 10000 28c23f9150Swiz 29c23f9150Swiz struct sixel_line { 30c23f9150Swiz u_int x; 31c23f9150Swiz uint16_t *data; 32c23f9150Swiz }; 33c23f9150Swiz 34c23f9150Swiz struct sixel_image { 35c23f9150Swiz u_int x; 36c23f9150Swiz u_int y; 37c23f9150Swiz u_int xpixel; 38c23f9150Swiz u_int ypixel; 39c23f9150Swiz 40c23f9150Swiz u_int *colours; 41c23f9150Swiz u_int ncolours; 42c23f9150Swiz 43c23f9150Swiz u_int dx; 44c23f9150Swiz u_int dy; 45c23f9150Swiz u_int dc; 46c23f9150Swiz 47c23f9150Swiz struct sixel_line *lines; 48c23f9150Swiz }; 49c23f9150Swiz 50c23f9150Swiz static int 51c23f9150Swiz sixel_parse_expand_lines(struct sixel_image *si, u_int y) 52c23f9150Swiz { 53c23f9150Swiz if (y <= si->y) 54c23f9150Swiz return (0); 55c23f9150Swiz if (y > SIXEL_HEIGHT_LIMIT) 56c23f9150Swiz return (1); 57c23f9150Swiz si->lines = xrecallocarray(si->lines, si->y, y, sizeof *si->lines); 58c23f9150Swiz si->y = y; 59c23f9150Swiz return (0); 60c23f9150Swiz } 61c23f9150Swiz 62c23f9150Swiz static int 63c23f9150Swiz sixel_parse_expand_line(struct sixel_image *si, struct sixel_line *sl, u_int x) 64c23f9150Swiz { 65c23f9150Swiz if (x <= sl->x) 66c23f9150Swiz return (0); 67c23f9150Swiz if (x > SIXEL_WIDTH_LIMIT) 68c23f9150Swiz return (1); 69c23f9150Swiz if (x > si->x) 70c23f9150Swiz si->x = x; 71c23f9150Swiz sl->data = xrecallocarray(sl->data, sl->x, si->x, sizeof *sl->data); 72c23f9150Swiz sl->x = si->x; 73c23f9150Swiz return (0); 74c23f9150Swiz } 75c23f9150Swiz 76c23f9150Swiz static u_int 77c23f9150Swiz sixel_get_pixel(struct sixel_image *si, u_int x, u_int y) 78c23f9150Swiz { 79c23f9150Swiz struct sixel_line *sl; 80c23f9150Swiz 81c23f9150Swiz if (y >= si->y) 82c23f9150Swiz return (0); 83c23f9150Swiz sl = &si->lines[y]; 84c23f9150Swiz if (x >= sl->x) 85c23f9150Swiz return (0); 86c23f9150Swiz return (sl->data[x]); 87c23f9150Swiz } 88c23f9150Swiz 89c23f9150Swiz static int 90c23f9150Swiz sixel_set_pixel(struct sixel_image *si, u_int x, u_int y, u_int c) 91c23f9150Swiz { 92c23f9150Swiz struct sixel_line *sl; 93c23f9150Swiz 94c23f9150Swiz if (sixel_parse_expand_lines(si, y + 1) != 0) 95c23f9150Swiz return (1); 96c23f9150Swiz sl = &si->lines[y]; 97c23f9150Swiz if (sixel_parse_expand_line(si, sl, x + 1) != 0) 98c23f9150Swiz return (1); 99c23f9150Swiz sl->data[x] = c; 100c23f9150Swiz return (0); 101c23f9150Swiz } 102c23f9150Swiz 103c23f9150Swiz static int 104c23f9150Swiz sixel_parse_write(struct sixel_image *si, u_int ch) 105c23f9150Swiz { 106c23f9150Swiz struct sixel_line *sl; 107c23f9150Swiz u_int i; 108c23f9150Swiz 109c23f9150Swiz if (sixel_parse_expand_lines(si, si->dy + 6) != 0) 110c23f9150Swiz return (1); 111c23f9150Swiz sl = &si->lines[si->dy]; 112c23f9150Swiz 113c23f9150Swiz for (i = 0; i < 6; i++) { 114c23f9150Swiz if (sixel_parse_expand_line(si, sl, si->dx + 1) != 0) 115c23f9150Swiz return (1); 116c23f9150Swiz if (ch & (1 << i)) 117c23f9150Swiz sl->data[si->dx] = si->dc; 118c23f9150Swiz sl++; 119c23f9150Swiz } 120c23f9150Swiz return (0); 121c23f9150Swiz } 122c23f9150Swiz 123c23f9150Swiz static const char * 124c23f9150Swiz sixel_parse_attributes(struct sixel_image *si, const char *cp, const char *end) 125c23f9150Swiz { 126c23f9150Swiz const char *last; 127c23f9150Swiz char *endptr; 128c23f9150Swiz u_int x, y; 129c23f9150Swiz 130c23f9150Swiz last = cp; 131c23f9150Swiz while (last != end) { 132c23f9150Swiz if (*last != ';' && (*last < '0' || *last > '9')) 133c23f9150Swiz break; 134c23f9150Swiz last++; 135c23f9150Swiz } 136c23f9150Swiz strtoul(cp, &endptr, 10); 137c23f9150Swiz if (endptr == last || *endptr != ';') 138c23f9150Swiz return (last); 139c23f9150Swiz strtoul(endptr + 1, &endptr, 10); 140c23f9150Swiz if (endptr == last) 141c23f9150Swiz return (last); 142c23f9150Swiz if (*endptr != ';') { 143c23f9150Swiz log_debug("%s: missing ;", __func__); 144c23f9150Swiz return (NULL); 145c23f9150Swiz } 146c23f9150Swiz 147c23f9150Swiz x = strtoul(endptr + 1, &endptr, 10); 148c23f9150Swiz if (endptr == last || *endptr != ';') { 149c23f9150Swiz log_debug("%s: missing ;", __func__); 150c23f9150Swiz return (NULL); 151c23f9150Swiz } 152c23f9150Swiz if (x > SIXEL_WIDTH_LIMIT) { 153c23f9150Swiz log_debug("%s: image is too wide", __func__); 154c23f9150Swiz return (NULL); 155c23f9150Swiz } 156c23f9150Swiz y = strtoul(endptr + 1, &endptr, 10); 157c23f9150Swiz if (endptr != last) { 158c23f9150Swiz log_debug("%s: extra ;", __func__); 159c23f9150Swiz return (NULL); 160c23f9150Swiz } 161c23f9150Swiz if (y > SIXEL_HEIGHT_LIMIT) { 162c23f9150Swiz log_debug("%s: image is too tall", __func__); 163c23f9150Swiz return (NULL); 164c23f9150Swiz } 165c23f9150Swiz 166c23f9150Swiz si->x = x; 167c23f9150Swiz sixel_parse_expand_lines(si, y); 168c23f9150Swiz 169c23f9150Swiz return (last); 170c23f9150Swiz } 171c23f9150Swiz 172c23f9150Swiz static const char * 173c23f9150Swiz sixel_parse_colour(struct sixel_image *si, const char *cp, const char *end) 174c23f9150Swiz { 175c23f9150Swiz const char *last; 176c23f9150Swiz char *endptr; 177c23f9150Swiz u_int c, type, r, g, b; 178c23f9150Swiz 179c23f9150Swiz last = cp; 180c23f9150Swiz while (last != end) { 181c23f9150Swiz if (*last != ';' && (*last < '0' || *last > '9')) 182c23f9150Swiz break; 183c23f9150Swiz last++; 184c23f9150Swiz } 185c23f9150Swiz 186c23f9150Swiz c = strtoul(cp, &endptr, 10); 187c23f9150Swiz if (c > SIXEL_COLOUR_REGISTERS) { 188c23f9150Swiz log_debug("%s: too many colours", __func__); 189c23f9150Swiz return (NULL); 190c23f9150Swiz } 191c23f9150Swiz si->dc = c + 1; 192c23f9150Swiz if (endptr == last || *endptr != ';') 193c23f9150Swiz return (last); 194c23f9150Swiz 195c23f9150Swiz type = strtoul(endptr + 1, &endptr, 10); 196c23f9150Swiz if (endptr == last || *endptr != ';') { 197c23f9150Swiz log_debug("%s: missing ;", __func__); 198c23f9150Swiz return (NULL); 199c23f9150Swiz } 200c23f9150Swiz r = strtoul(endptr + 1, &endptr, 10); 201c23f9150Swiz if (endptr == last || *endptr != ';') { 202c23f9150Swiz log_debug("%s: missing ;", __func__); 203c23f9150Swiz return (NULL); 204c23f9150Swiz } 205c23f9150Swiz g = strtoul(endptr + 1, &endptr, 10); 206c23f9150Swiz if (endptr == last || *endptr != ';') { 207c23f9150Swiz log_debug("%s: missing ;", __func__); 208c23f9150Swiz return (NULL); 209c23f9150Swiz } 210c23f9150Swiz b = strtoul(endptr + 1, &endptr, 10); 211c23f9150Swiz if (endptr != last) { 212c23f9150Swiz log_debug("%s: missing ;", __func__); 213c23f9150Swiz return (NULL); 214c23f9150Swiz } 215c23f9150Swiz 216c23f9150Swiz if (type != 1 && type != 2) { 217c23f9150Swiz log_debug("%s: invalid type %d", __func__, type); 218c23f9150Swiz return (NULL); 219c23f9150Swiz } 220c23f9150Swiz if (c + 1 > si->ncolours) { 221c23f9150Swiz si->colours = xrecallocarray(si->colours, si->ncolours, c + 1, 222c23f9150Swiz sizeof *si->colours); 223c23f9150Swiz si->ncolours = c + 1; 224c23f9150Swiz } 225c23f9150Swiz si->colours[c] = (type << 24) | (r << 16) | (g << 8) | b; 226c23f9150Swiz return (last); 227c23f9150Swiz } 228c23f9150Swiz 229c23f9150Swiz static const char * 230c23f9150Swiz sixel_parse_repeat(struct sixel_image *si, const char *cp, const char *end) 231c23f9150Swiz { 232c23f9150Swiz const char *last; 233c23f9150Swiz char tmp[32], ch; 234c23f9150Swiz u_int n = 0, i; 235c23f9150Swiz const char *errstr = NULL; 236c23f9150Swiz 237c23f9150Swiz last = cp; 238c23f9150Swiz while (last != end) { 239c23f9150Swiz if (*last < '0' || *last > '9') 240c23f9150Swiz break; 241c23f9150Swiz tmp[n++] = *last++; 242c23f9150Swiz if (n == (sizeof tmp) - 1) { 243c23f9150Swiz log_debug("%s: repeat not terminated", __func__); 244c23f9150Swiz return (NULL); 245c23f9150Swiz } 246c23f9150Swiz } 247c23f9150Swiz if (n == 0 || last == end) { 248c23f9150Swiz log_debug("%s: repeat not terminated", __func__); 249c23f9150Swiz return (NULL); 250c23f9150Swiz } 251c23f9150Swiz tmp[n] = '\0'; 252c23f9150Swiz 253c23f9150Swiz n = strtonum(tmp, 1, SIXEL_WIDTH_LIMIT, &errstr); 254c23f9150Swiz if (n == 0 || errstr != NULL) { 255c23f9150Swiz log_debug("%s: repeat too wide", __func__); 256c23f9150Swiz return (NULL); 257c23f9150Swiz } 258c23f9150Swiz 259c23f9150Swiz ch = (*last++) - 0x3f; 260c23f9150Swiz for (i = 0; i < n; i++) { 261c23f9150Swiz if (sixel_parse_write(si, ch) != 0) { 262c23f9150Swiz log_debug("%s: width limit reached", __func__); 263c23f9150Swiz return (NULL); 264c23f9150Swiz } 265c23f9150Swiz si->dx++; 266c23f9150Swiz } 267c23f9150Swiz return (last); 268c23f9150Swiz } 269c23f9150Swiz 270c23f9150Swiz struct sixel_image * 271c23f9150Swiz sixel_parse(const char *buf, size_t len, u_int xpixel, u_int ypixel) 272c23f9150Swiz { 273c23f9150Swiz struct sixel_image *si; 274c23f9150Swiz const char *cp = buf, *end = buf + len; 275c23f9150Swiz char ch; 276c23f9150Swiz 277c23f9150Swiz if (len == 0 || len == 1 || *cp++ != 'q') { 278c23f9150Swiz log_debug("%s: empty image", __func__); 279c23f9150Swiz return (NULL); 280c23f9150Swiz } 281c23f9150Swiz 282c23f9150Swiz si = xcalloc (1, sizeof *si); 283c23f9150Swiz si->xpixel = xpixel; 284c23f9150Swiz si->ypixel = ypixel; 285c23f9150Swiz 286c23f9150Swiz while (cp != end) { 287c23f9150Swiz ch = *cp++; 288c23f9150Swiz switch (ch) { 289c23f9150Swiz case '"': 290c23f9150Swiz cp = sixel_parse_attributes(si, cp, end); 291c23f9150Swiz if (cp == NULL) 292c23f9150Swiz goto bad; 293c23f9150Swiz break; 294c23f9150Swiz case '#': 295c23f9150Swiz cp = sixel_parse_colour(si, cp, end); 296c23f9150Swiz if (cp == NULL) 297c23f9150Swiz goto bad; 298c23f9150Swiz break; 299c23f9150Swiz case '!': 300c23f9150Swiz cp = sixel_parse_repeat(si, cp, end); 301c23f9150Swiz if (cp == NULL) 302c23f9150Swiz goto bad; 303c23f9150Swiz break; 304c23f9150Swiz case '-': 305c23f9150Swiz si->dx = 0; 306c23f9150Swiz si->dy += 6; 307c23f9150Swiz break; 308c23f9150Swiz case '$': 309c23f9150Swiz si->dx = 0; 310c23f9150Swiz break; 311c23f9150Swiz default: 312c23f9150Swiz if (ch < 0x20) 313c23f9150Swiz break; 314c23f9150Swiz if (ch < 0x3f || ch > 0x7e) 315c23f9150Swiz goto bad; 316c23f9150Swiz if (sixel_parse_write(si, ch - 0x3f) != 0) { 317c23f9150Swiz log_debug("%s: width limit reached", __func__); 318c23f9150Swiz goto bad; 319c23f9150Swiz } 320c23f9150Swiz si->dx++; 321c23f9150Swiz break; 322c23f9150Swiz } 323c23f9150Swiz } 324c23f9150Swiz 325c23f9150Swiz if (si->x == 0 || si->y == 0) 326c23f9150Swiz goto bad; 327c23f9150Swiz return (si); 328c23f9150Swiz 329c23f9150Swiz bad: 330c23f9150Swiz free(si); 331c23f9150Swiz return (NULL); 332c23f9150Swiz } 333c23f9150Swiz 334c23f9150Swiz void 335c23f9150Swiz sixel_free(struct sixel_image *si) 336c23f9150Swiz { 337c23f9150Swiz u_int y; 338c23f9150Swiz 339c23f9150Swiz for (y = 0; y < si->y; y++) 340c23f9150Swiz free(si->lines[y].data); 341c23f9150Swiz free(si->lines); 342c23f9150Swiz 343c23f9150Swiz free(si->colours); 344c23f9150Swiz free(si); 345c23f9150Swiz } 346c23f9150Swiz 347c23f9150Swiz void 348c23f9150Swiz sixel_log(struct sixel_image *si) 349c23f9150Swiz { 350c23f9150Swiz struct sixel_line *sl; 351c23f9150Swiz char s[SIXEL_WIDTH_LIMIT + 1]; 352c23f9150Swiz u_int i, x, y, cx, cy; 353c23f9150Swiz 354c23f9150Swiz sixel_size_in_cells(si, &cx, &cy); 355c23f9150Swiz log_debug("%s: image %ux%u (%ux%u)", __func__, si->x, si->y, cx, cy); 356c23f9150Swiz for (i = 0; i < si->ncolours; i++) 357c23f9150Swiz log_debug("%s: colour %u is %07x", __func__, i, si->colours[i]); 358c23f9150Swiz for (y = 0; y < si->y; y++) { 359c23f9150Swiz sl = &si->lines[y]; 360c23f9150Swiz for (x = 0; x < si->x; x++) { 361c23f9150Swiz if (x >= sl->x) 362c23f9150Swiz s[x] = '_'; 363c23f9150Swiz else if (sl->data[x] != 0) 364c23f9150Swiz s[x] = '0' + (sl->data[x] - 1) % 10; 365c23f9150Swiz else 366c23f9150Swiz s[x] = '.'; 367c23f9150Swiz } 368c23f9150Swiz s[x] = '\0'; 369c23f9150Swiz log_debug("%s: %4u: %s", __func__, y, s); 370c23f9150Swiz } 371c23f9150Swiz } 372c23f9150Swiz 373c23f9150Swiz void 374c23f9150Swiz sixel_size_in_cells(struct sixel_image *si, u_int *x, u_int *y) 375c23f9150Swiz { 376c23f9150Swiz if ((si->x % si->xpixel) == 0) 377c23f9150Swiz *x = (si->x / si->xpixel); 378c23f9150Swiz else 379c23f9150Swiz *x = 1 + (si->x / si->xpixel); 380c23f9150Swiz if ((si->y % si->ypixel) == 0) 381c23f9150Swiz *y = (si->y / si->ypixel); 382c23f9150Swiz else 383c23f9150Swiz *y = 1 + (si->y / si->ypixel); 384c23f9150Swiz } 385c23f9150Swiz 386c23f9150Swiz struct sixel_image * 387c23f9150Swiz sixel_scale(struct sixel_image *si, u_int xpixel, u_int ypixel, u_int ox, 388c23f9150Swiz u_int oy, u_int sx, u_int sy, int colours) 389c23f9150Swiz { 390c23f9150Swiz struct sixel_image *new; 391c23f9150Swiz u_int cx, cy, pox, poy, psx, psy, tsx, tsy, px, py; 392c23f9150Swiz u_int x, y, i; 393c23f9150Swiz 394c23f9150Swiz /* 395c23f9150Swiz * We want to get the section of the image at ox,oy in image cells and 396c23f9150Swiz * map it onto the same size in terminal cells, remembering that we 397c23f9150Swiz * can only draw vertical sections of six pixels. 398c23f9150Swiz */ 399c23f9150Swiz 400c23f9150Swiz sixel_size_in_cells(si, &cx, &cy); 401c23f9150Swiz if (ox >= cx) 402c23f9150Swiz return (NULL); 403c23f9150Swiz if (oy >= cy) 404c23f9150Swiz return (NULL); 405c23f9150Swiz if (ox + sx >= cx) 406c23f9150Swiz sx = cx - ox; 407c23f9150Swiz if (oy + sy >= cy) 408c23f9150Swiz sy = cy - oy; 409c23f9150Swiz 410c23f9150Swiz if (xpixel == 0) 411c23f9150Swiz xpixel = si->xpixel; 412c23f9150Swiz if (ypixel == 0) 413c23f9150Swiz ypixel = si->ypixel; 414c23f9150Swiz 415c23f9150Swiz pox = ox * si->xpixel; 416c23f9150Swiz poy = oy * si->ypixel; 417c23f9150Swiz psx = sx * si->xpixel; 418c23f9150Swiz psy = sy * si->ypixel; 419c23f9150Swiz 420c23f9150Swiz tsx = sx * xpixel; 421c23f9150Swiz tsy = ((sy * ypixel) / 6) * 6; 422c23f9150Swiz 423c23f9150Swiz new = xcalloc (1, sizeof *si); 424c23f9150Swiz new->xpixel = xpixel; 425c23f9150Swiz new->ypixel = ypixel; 426c23f9150Swiz 427c23f9150Swiz for (y = 0; y < tsy; y++) { 428c23f9150Swiz py = poy + ((double)y * psy / tsy); 429c23f9150Swiz for (x = 0; x < tsx; x++) { 430c23f9150Swiz px = pox + ((double)x * psx / tsx); 431c23f9150Swiz sixel_set_pixel(new, x, y, sixel_get_pixel(si, px, py)); 432c23f9150Swiz } 433c23f9150Swiz } 434c23f9150Swiz 435c23f9150Swiz if (colours) { 436c23f9150Swiz new->colours = xmalloc(si->ncolours * sizeof *new->colours); 437c23f9150Swiz for (i = 0; i < si->ncolours; i++) 438c23f9150Swiz new->colours[i] = si->colours[i]; 439c23f9150Swiz new->ncolours = si->ncolours; 440c23f9150Swiz } 441c23f9150Swiz return (new); 442c23f9150Swiz } 443c23f9150Swiz 444c23f9150Swiz static void 445c23f9150Swiz sixel_print_add(char **buf, size_t *len, size_t *used, const char *s, 446c23f9150Swiz size_t slen) 447c23f9150Swiz { 448c23f9150Swiz if (*used + slen >= *len + 1) { 449c23f9150Swiz (*len) *= 2; 450c23f9150Swiz *buf = xrealloc(*buf, *len); 451c23f9150Swiz } 452c23f9150Swiz memcpy(*buf + *used, s, slen); 453c23f9150Swiz (*used) += slen; 454c23f9150Swiz } 455c23f9150Swiz 456c23f9150Swiz static void 457c23f9150Swiz sixel_print_repeat(char **buf, size_t *len, size_t *used, u_int count, char ch) 458c23f9150Swiz { 459c23f9150Swiz char tmp[16]; 460c23f9150Swiz size_t tmplen; 461c23f9150Swiz 462c23f9150Swiz if (count == 1) 463c23f9150Swiz sixel_print_add(buf, len, used, &ch, 1); 464c23f9150Swiz else if (count == 2) { 465c23f9150Swiz sixel_print_add(buf, len, used, &ch, 1); 466c23f9150Swiz sixel_print_add(buf, len, used, &ch, 1); 467c23f9150Swiz } else if (count == 3) { 468c23f9150Swiz sixel_print_add(buf, len, used, &ch, 1); 469c23f9150Swiz sixel_print_add(buf, len, used, &ch, 1); 470c23f9150Swiz sixel_print_add(buf, len, used, &ch, 1); 471c23f9150Swiz } else if (count != 0) { 472c23f9150Swiz tmplen = xsnprintf(tmp, sizeof tmp, "!%u%c", count, ch); 473c23f9150Swiz sixel_print_add(buf, len, used, tmp, tmplen); 474c23f9150Swiz } 475c23f9150Swiz } 476c23f9150Swiz 477c23f9150Swiz char * 478c23f9150Swiz sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size) 479c23f9150Swiz { 480f844e94eSwiz char *buf, tmp[64], *contains, data = 0, last = 0; 481c23f9150Swiz size_t len, used = 0, tmplen; 482c23f9150Swiz u_int *colours, ncolours, i, c, x, y, count; 483c23f9150Swiz struct sixel_line *sl; 484c23f9150Swiz 485c23f9150Swiz if (map != NULL) { 486c23f9150Swiz colours = map->colours; 487c23f9150Swiz ncolours = map->ncolours; 488c23f9150Swiz } else { 489c23f9150Swiz colours = si->colours; 490c23f9150Swiz ncolours = si->ncolours; 491c23f9150Swiz } 492*890b6d91Swiz 493*890b6d91Swiz if (ncolours == 0) 494*890b6d91Swiz return (NULL); 495c23f9150Swiz contains = xcalloc(1, ncolours); 496c23f9150Swiz 497c23f9150Swiz len = 8192; 498c23f9150Swiz buf = xmalloc(len); 499c23f9150Swiz 500c23f9150Swiz sixel_print_add(&buf, &len, &used, "\033Pq", 3); 501c23f9150Swiz 502c23f9150Swiz tmplen = xsnprintf(tmp, sizeof tmp, "\"1;1;%u;%u", si->x, si->y); 503c23f9150Swiz sixel_print_add(&buf, &len, &used, tmp, tmplen); 504c23f9150Swiz 505c23f9150Swiz for (i = 0; i < ncolours; i++) { 506c23f9150Swiz c = colours[i]; 507c23f9150Swiz tmplen = xsnprintf(tmp, sizeof tmp, "#%u;%u;%u;%u;%u", 508c23f9150Swiz i, c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff); 509c23f9150Swiz sixel_print_add(&buf, &len, &used, tmp, tmplen); 510c23f9150Swiz } 511c23f9150Swiz 512c23f9150Swiz for (y = 0; y < si->y; y += 6) { 513c23f9150Swiz memset(contains, 0, ncolours); 514c23f9150Swiz for (x = 0; x < si->x; x++) { 515c23f9150Swiz for (i = 0; i < 6; i++) { 516c23f9150Swiz if (y + i >= si->y) 517c23f9150Swiz break; 518c23f9150Swiz sl = &si->lines[y + i]; 519c23f9150Swiz if (x < sl->x && sl->data[x] != 0) 520c23f9150Swiz contains[sl->data[x] - 1] = 1; 521c23f9150Swiz } 522c23f9150Swiz } 523c23f9150Swiz 524c23f9150Swiz for (c = 0; c < ncolours; c++) { 525c23f9150Swiz if (!contains[c]) 526c23f9150Swiz continue; 527c23f9150Swiz tmplen = xsnprintf(tmp, sizeof tmp, "#%u", c); 528c23f9150Swiz sixel_print_add(&buf, &len, &used, tmp, tmplen); 529c23f9150Swiz 530c23f9150Swiz count = 0; 531c23f9150Swiz for (x = 0; x < si->x; x++) { 532c23f9150Swiz data = 0; 533c23f9150Swiz for (i = 0; i < 6; i++) { 534c23f9150Swiz if (y + i >= si->y) 535c23f9150Swiz break; 536c23f9150Swiz sl = &si->lines[y + i]; 537c23f9150Swiz if (x < sl->x && sl->data[x] == c + 1) 538c23f9150Swiz data |= (1 << i); 539c23f9150Swiz } 540c23f9150Swiz data += 0x3f; 541c23f9150Swiz if (data != last) { 542c23f9150Swiz sixel_print_repeat(&buf, &len, &used, 543c23f9150Swiz count, last); 544c23f9150Swiz last = data; 545c23f9150Swiz count = 1; 546c23f9150Swiz } else 547c23f9150Swiz count++; 548c23f9150Swiz } 549c23f9150Swiz sixel_print_repeat(&buf, &len, &used, count, data); 550c23f9150Swiz sixel_print_add(&buf, &len, &used, "$", 1); 551c23f9150Swiz } 552c23f9150Swiz 553c23f9150Swiz if (buf[used - 1] == '$') 554c23f9150Swiz used--; 555c23f9150Swiz if (buf[used - 1] != '-') 556c23f9150Swiz sixel_print_add(&buf, &len, &used, "-", 1); 557c23f9150Swiz } 558c23f9150Swiz if (buf[used - 1] == '$' || buf[used - 1] == '-') 559c23f9150Swiz used--; 560c23f9150Swiz 561c23f9150Swiz sixel_print_add(&buf, &len, &used, "\033\\", 2); 562c23f9150Swiz 563c23f9150Swiz buf[used] = '\0'; 564c23f9150Swiz if (size != NULL) 565c23f9150Swiz *size = used; 566c23f9150Swiz 567c23f9150Swiz free(contains); 568c23f9150Swiz return (buf); 569c23f9150Swiz } 570c23f9150Swiz 571c23f9150Swiz struct screen * 572c23f9150Swiz sixel_to_screen(struct sixel_image *si) 573c23f9150Swiz { 574c23f9150Swiz struct screen *s; 575c23f9150Swiz struct screen_write_ctx ctx; 576c23f9150Swiz struct grid_cell gc; 577c23f9150Swiz u_int x, y, sx, sy; 578c23f9150Swiz 579c23f9150Swiz sixel_size_in_cells(si, &sx, &sy); 580c23f9150Swiz 581c23f9150Swiz s = xmalloc(sizeof *s); 582c23f9150Swiz screen_init(s, sx, sy, 0); 583c23f9150Swiz 584c23f9150Swiz memcpy(&gc, &grid_default_cell, sizeof gc); 585c23f9150Swiz gc.attr |= (GRID_ATTR_CHARSET|GRID_ATTR_DIM); 586c23f9150Swiz utf8_set(&gc.data, '~'); 587c23f9150Swiz 588c23f9150Swiz screen_write_start(&ctx, s); 589c23f9150Swiz if (sx == 1 || sy == 1) { 590c23f9150Swiz for (y = 0; y < sy; y++) { 591c23f9150Swiz for (x = 0; x < sx; x++) 592c23f9150Swiz grid_view_set_cell(s->grid, x, y, &gc); 593c23f9150Swiz } 594c23f9150Swiz } else { 595c23f9150Swiz screen_write_box(&ctx, sx, sy, BOX_LINES_DEFAULT, NULL, NULL); 596c23f9150Swiz for (y = 1; y < sy - 1; y++) { 597c23f9150Swiz for (x = 1; x < sx - 1; x++) 598c23f9150Swiz grid_view_set_cell(s->grid, x, y, &gc); 599c23f9150Swiz } 600c23f9150Swiz } 601c23f9150Swiz screen_write_stop(&ctx); 602c23f9150Swiz return (s); 603c23f9150Swiz } 604