mirror of
https://github.com/tmux/tmux.git
synced 2024-11-17 18:08:51 +00:00
dfbc6b1888
Squashed commit of the following: commit 6ebc3feb4671d9b25b3db99d3c16b2323b8e3d02 Author: topcat001 <anindya49@hotmail.com> Date: Sun Aug 20 16:09:51 2023 -0700 Remove redundant {}. commit 6f013fce39602c259a5be2d690d548c73e51cccc Author: topcat001 <anindya49@hotmail.com> Date: Sun Aug 20 16:02:15 2023 -0700 Revert "Do not defer redraw if it is just the status line (will need to do more here I" This reverts commit0a15bbf3f1
. commit e6322b4196d73c975ba2e73633e6de9c46779059 Author: topcat001 <anindya49@hotmail.com> Date: Sun Aug 20 15:46:59 2023 -0700 Fix placeholder label and clean up. commit 5896ac52a1f72056a75480b3e1ada328f239df9b Merge: ad982330e3a8b843
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Fri Aug 18 17:00:03 2023 +0100 Merge branch 'master' into sixel commit ad98233066b72547aee7fa0c87838847ee7f1ece Author: topcat001 <anindya49@hotmail.com> Date: Tue Aug 15 13:57:08 2023 -0700 Better text placeholder. commit 312d83252c27fc4d09d09d121bf7573336e3cdca Merge: 14b8b5243d93b0c5
Author: topcat001 <anindya49@hotmail.com> Date: Tue Aug 15 13:39:22 2023 -0700 Merge remote-tracking branch 'origin/master' into sixel commit 14b8b524523a7d5a4e42f7dfa346905c604c91e2 Merge: 4baf7642fda39377
Author: topcat001 <anindya49@hotmail.com> Date: Sat Jul 22 17:29:10 2023 -0700 Merge branch 'master' into sixel commit 4baf76422fadb216bf27b47645b52da3379e7dea Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Wed Jun 21 07:43:53 2023 +0100 Both files can go on one line. commit4c92acf6ff
Author: topcat001 <anindya49@hotmail.com> Date: Sat Jun 17 17:53:01 2023 -0700 Merge topcat001/tmux/sixel. commit6794facc82
Merge: 7b85f5adf41c536f
Author: topcat001 <anindya49@hotmail.com> Date: Sat Jun 17 17:21:02 2023 -0700 Merge remote-tracking branch 'origin/master' into sixel commit 7b85f5adf9a5094db580ca98e4d2231d8d5b5a4f Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Jun 8 12:55:03 2023 +0100 Do not require passthrough for SIXEL. commit a6ee55e0925cac35d011c188db2da0421fc09be1 Merge: 6da391f4fe385b18
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Jun 8 12:19:55 2023 +0100 Merge branch 'master' into sixel commit 6da391f460414ed3dde23e5ab6ca3fe8e988ce51 Merge: 0d71e5850eb5d254
Author: topcat001 <anindya49@hotmail.com> Date: Sat May 20 17:05:55 2023 -0700 Merge branch 'master' into sixel commit 0d71e5853ffe797f90b815ac3af25ac0ad92ab07 Merge:64368a1a
fbe6fe7f
Author: topcat001 <anindya49@hotmail.com> Date: Sat Apr 29 17:32:07 2023 -0700 Merge branch 'master' into sixel commit64368a1a63
Merge:c630a56a
22eb0334
Author: topcat001 <anindya49@hotmail.com> Date: Thu Mar 30 14:21:09 2023 -0700 Merge branch 'master' into sixel commitc630a56a62
Merge:34c96c4c
aaa043a2
Author: topcat001 <anindya49@hotmail.com> Date: Thu Nov 10 18:53:01 2022 -0800 Merge branch 'master' into sixel commit34c96c4c4a
Merge:2a1e16a2
50f4e0fa
Author: topcat001 <anindya49@hotmail.com> Date: Sat Nov 5 18:05:36 2022 -0700 Merge branch 'master' into sixel commit2a1e16a24d
Merge:a82f14c7
d001a94d
Author: topcat001 <anindya49@hotmail.com> Date: Thu Oct 27 16:01:35 2022 -0700 Merge branch 'master' into sixel commita82f14c7b2
Merge:742c0634
f7b30ed3
Author: topcat001 <anindya49@hotmail.com> Date: Sun Aug 28 13:43:07 2022 -0700 Merge branch 'master' into sixel commit742c063473
Merge:906c92a5
87b248f3
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Fri Apr 1 10:14:15 2022 +0100 Merge branch 'master' into sixel commit906c92a5f4
Merge:6680a024
138ffc7c
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Wed Dec 8 10:37:33 2021 +0000 Merge branch 'master' into sixel commit6680a024be
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Oct 7 13:59:08 2021 +0100 Fix build. commitebd2c58593
Merge:90dc0519
fed7b29c
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Oct 7 13:19:48 2021 +0100 Merge branch 'master' into sixel commit90dc05191c
Merge:a282439f
4694afbe
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Feb 20 20:37:32 2020 +0000 Merge branch 'master' into sixel commita282439fcb
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Jan 30 09:12:53 2020 +0000 Add missing declarations. commit3a741aacd1
Merge:40ad0107
339832b9
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Jan 30 09:11:01 2020 +0000 Merge branch 'sixel-passthrough' into sixel commit339832b92c
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Jan 30 09:04:51 2020 +0000 Bad merge. commit92ed9fc0b2
Merge:5bb07548
32be954b
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Jan 30 09:03:38 2020 +0000 Merge branch 'master' into sixel-passthrough commit40ad01073d
Merge:dd3c72f1
61b075a2
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Sun Jan 12 20:03:41 2020 +0000 Merge branch 'master' into sixel commit5bb075487f
Merge:7c033a74
54efe337
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Wed Dec 18 20:24:42 2019 +0000 Merge branch 'master' into sixel-passthrough commitdd3c72f132
Merge:1a0e5fe9
54efe337
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Wed Dec 18 20:24:26 2019 +0000 Merge branch 'master' into sixel commit1a0e5fe933
Merge:cf071ffe
15d7e564
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Tue Dec 10 16:34:11 2019 +0000 Merge branch 'master' into sixel commitcf071ffecd
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Mon Dec 9 15:41:56 2019 +0000 Remove images when reflow happens. commit2006b7a563
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Dec 5 09:27:15 2019 +0000 More invalidation of images. commitb642eac450
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Dec 5 09:11:24 2019 +0000 Redraw and scroll images and part of invalidating them. commit7566e37a46
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Dec 5 08:51:24 2019 +0000 Call sixel_scale with the right number of arguments. commit62c0280b23
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Dec 5 08:48:58 2019 +0000 Correctly remove when not visible. commit86c5098a88
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Dec 5 08:32:25 2019 +0000 Add helpers to scroll image up and a flag to copy the colours. commit49f2f0a8f1
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Dec 5 00:02:55 2019 +0000 Store images, currently at most 10. commit3aebcc6709
Merge:146ee3f6
92ecd611
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Wed Dec 4 19:27:16 2019 +0000 Merge branch 'master' into sixel commit7c033a74e2
Merge:0a15bbf3
92ecd611
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Wed Dec 4 12:41:09 2019 +0000 Merge branch 'master' into sixel-passthrough commit146ee3f6f8
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Sat Nov 30 09:47:53 2019 +0000 Don't write image as text yet. commit0a15bbf3f1
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Sat Nov 30 09:15:35 2019 +0000 Do not defer redraw if it is just the status line (will need to do more here I think). commita5b1e20941
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Nov 28 14:20:22 2019 +0000 Add a flag to disable blocking while sending a SIXEL image (turned off when the buffer hits 0 size). commit968382aa6a
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Nov 28 12:35:18 2019 +0000 Pass through SIXEL DCS sequences (treat similarly to the passthrough escape sequence) if it appears the terminal outside supports them. commitb1904c9b8d
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Sat Nov 30 09:17:18 2019 +0000 Store SIXELs as a box for the moment. commit5d8dbcdf3d
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Sat Nov 30 09:15:35 2019 +0000 Do not defer redraw if it is just the status line (will need to do more here I think). commit0c999a402e
Merge:28961dd5
866b053f
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Fri Nov 29 18:54:09 2019 +0000 Merge branch 'master' into sixel commit28961dd5a3
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Nov 28 14:24:57 2019 +0000 Add an image. commitd2e3f3c1cc
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Nov 28 14:20:22 2019 +0000 Add a flag to disable blocking while sending a SIXEL image (turned off when the buffer hits 0 size). commite01df67ca1
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Nov 28 13:21:40 2019 +0000 Crop and scale images as needed when drawing them. commite24acc0b5c
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Nov 28 12:38:02 2019 +0000 Simple SIXEL parse and modify API. commitb34111b3da
Author: Nicholas Marriott <nicholas.marriott@gmail.com> Date: Thu Nov 28 12:35:18 2019 +0000 Pass through SIXEL DCS sequences (treat similarly to the passthrough escape sequence) if it appears the terminal outside supports them.
566 lines
12 KiB
C
566 lines
12 KiB
C
/* $OpenBSD$ */
|
|
|
|
/*
|
|
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "tmux.h"
|
|
|
|
#define SIXEL_COLOUR_REGISTERS 1024
|
|
#define SIXEL_WIDTH_LIMIT 2016
|
|
#define SIXEL_HEIGHT_LIMIT 2016
|
|
|
|
struct sixel_line {
|
|
u_int x;
|
|
uint16_t *data;
|
|
};
|
|
|
|
struct sixel_image {
|
|
u_int x;
|
|
u_int y;
|
|
u_int xpixel;
|
|
u_int ypixel;
|
|
|
|
u_int *colours;
|
|
u_int ncolours;
|
|
|
|
u_int dx;
|
|
u_int dy;
|
|
u_int dc;
|
|
|
|
struct sixel_line *lines;
|
|
};
|
|
|
|
static int
|
|
sixel_parse_expand_lines(struct sixel_image *si, u_int y)
|
|
{
|
|
if (y <= si->y)
|
|
return (0);
|
|
if (y > SIXEL_HEIGHT_LIMIT)
|
|
return (1);
|
|
si->lines = xrecallocarray(si->lines, si->y, y, sizeof *si->lines);
|
|
si->y = y;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
sixel_parse_expand_line(struct sixel_image *si, struct sixel_line *sl, u_int x)
|
|
{
|
|
if (x <= sl->x)
|
|
return (0);
|
|
if (x > SIXEL_WIDTH_LIMIT)
|
|
return (1);
|
|
if (x > si->x)
|
|
si->x = x;
|
|
sl->data = xrecallocarray(sl->data, sl->x, si->x, sizeof *sl->data);
|
|
sl->x = si->x;
|
|
return (0);
|
|
}
|
|
|
|
static u_int
|
|
sixel_get_pixel(struct sixel_image *si, u_int x, u_int y)
|
|
{
|
|
struct sixel_line *sl;
|
|
|
|
if (y >= si->y)
|
|
return (0);
|
|
sl = &si->lines[y];
|
|
if (x >= sl->x)
|
|
return (0);
|
|
return (sl->data[x]);
|
|
}
|
|
|
|
static int
|
|
sixel_set_pixel(struct sixel_image *si, u_int x, u_int y, u_int c)
|
|
{
|
|
struct sixel_line *sl;
|
|
|
|
if (sixel_parse_expand_lines(si, y + 1) != 0)
|
|
return (1);
|
|
sl = &si->lines[y];
|
|
if (sixel_parse_expand_line(si, sl, x + 1) != 0)
|
|
return (1);
|
|
sl->data[x] = c;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
sixel_parse_write(struct sixel_image *si, u_int ch)
|
|
{
|
|
struct sixel_line *sl;
|
|
u_int i;
|
|
|
|
if (sixel_parse_expand_lines(si, si->dy + 6) != 0)
|
|
return (1);
|
|
sl = &si->lines[si->dy];
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
if (sixel_parse_expand_line(si, sl, si->dx + 1) != 0)
|
|
return (1);
|
|
if (ch & (1 << i))
|
|
sl->data[si->dx] = si->dc;
|
|
sl++;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
static const char *
|
|
sixel_parse_attributes(struct sixel_image *si, const char *cp, const char *end)
|
|
{
|
|
const char *last;
|
|
char *endptr;
|
|
u_int x, y;
|
|
|
|
last = cp;
|
|
while (last != end) {
|
|
if (*last != ';' && (*last < '0' || *last > '9'))
|
|
break;
|
|
last++;
|
|
}
|
|
strtoul(cp, &endptr, 10);
|
|
if (endptr == last || *endptr != ';')
|
|
return (last);
|
|
strtoul(endptr + 1, &endptr, 10);
|
|
if (endptr == last || *endptr != ';')
|
|
return (NULL);
|
|
|
|
x = strtoul(endptr + 1, &endptr, 10);
|
|
if (endptr == last || *endptr != ';')
|
|
return (NULL);
|
|
if (x > SIXEL_WIDTH_LIMIT)
|
|
return (NULL);
|
|
y = strtoul(endptr + 1, &endptr, 10);
|
|
if (endptr != last)
|
|
return (NULL);
|
|
if (y > SIXEL_HEIGHT_LIMIT)
|
|
return (NULL);
|
|
|
|
si->x = x;
|
|
sixel_parse_expand_lines(si, y);
|
|
|
|
return (last);
|
|
}
|
|
|
|
static const char *
|
|
sixel_parse_colour(struct sixel_image *si, const char *cp, const char *end)
|
|
{
|
|
const char *last;
|
|
char *endptr;
|
|
u_int c, type, r, g, b;
|
|
|
|
last = cp;
|
|
while (last != end) {
|
|
if (*last != ';' && (*last < '0' || *last > '9'))
|
|
break;
|
|
last++;
|
|
}
|
|
|
|
c = strtoul(cp, &endptr, 10);
|
|
if (c > SIXEL_COLOUR_REGISTERS)
|
|
return (NULL);
|
|
si->dc = c + 1;
|
|
if (endptr == last || *endptr != ';')
|
|
return (last);
|
|
|
|
type = strtoul(endptr + 1, &endptr, 10);
|
|
if (endptr == last || *endptr != ';')
|
|
return (NULL);
|
|
r = strtoul(endptr + 1, &endptr, 10);
|
|
if (endptr == last || *endptr != ';')
|
|
return (NULL);
|
|
g = strtoul(endptr + 1, &endptr, 10);
|
|
if (endptr == last || *endptr != ';')
|
|
return (NULL);
|
|
b = strtoul(endptr + 1, &endptr, 10);
|
|
if (endptr != last)
|
|
return (NULL);
|
|
|
|
if (type != 1 && type != 2)
|
|
return (NULL);
|
|
if (c + 1 > si->ncolours) {
|
|
si->colours = xrecallocarray(si->colours, si->ncolours, c + 1,
|
|
sizeof *si->colours);
|
|
si->ncolours = c + 1;
|
|
}
|
|
si->colours[c] = (type << 24) | (r << 16) | (g << 8) | b;
|
|
return (last);
|
|
}
|
|
|
|
static const char *
|
|
sixel_parse_repeat(struct sixel_image *si, const char *cp, const char *end)
|
|
{
|
|
const char *last;
|
|
char tmp[32], ch;
|
|
u_int n = 0, i;
|
|
const char *errstr = NULL;
|
|
|
|
last = cp;
|
|
while (last != end) {
|
|
if (*last < '0' || *last > '9')
|
|
break;
|
|
tmp[n++] = *last++;
|
|
if (n == (sizeof tmp) - 1)
|
|
return (NULL);
|
|
}
|
|
if (n == 0 || last == end)
|
|
return (NULL);
|
|
tmp[n] = '\0';
|
|
|
|
n = strtonum(tmp, 1, SIXEL_WIDTH_LIMIT, &errstr);
|
|
if (n == 0 || errstr != NULL)
|
|
return (NULL);
|
|
|
|
ch = (*last++) - 0x3f;
|
|
for (i = 0; i < n; i++) {
|
|
if (sixel_parse_write(si, ch) != 0)
|
|
return (NULL);
|
|
si->dx++;
|
|
}
|
|
return (last);
|
|
}
|
|
|
|
struct sixel_image *
|
|
sixel_parse(const char *buf, size_t len, u_int xpixel, u_int ypixel)
|
|
{
|
|
struct sixel_image *si;
|
|
const char *cp = buf, *end = buf + len;
|
|
char ch;
|
|
|
|
if (len == 0 || len == 1 || *cp++ != 'q')
|
|
return (NULL);
|
|
|
|
si = xcalloc (1, sizeof *si);
|
|
si->xpixel = xpixel;
|
|
si->ypixel = ypixel;
|
|
|
|
while (cp != end) {
|
|
ch = *cp++;
|
|
switch (ch) {
|
|
case '"':
|
|
cp = sixel_parse_attributes(si, cp, end);
|
|
if (cp == NULL)
|
|
goto bad;
|
|
break;
|
|
case '#':
|
|
cp = sixel_parse_colour(si, cp, end);
|
|
if (cp == NULL)
|
|
goto bad;
|
|
break;
|
|
case '!':
|
|
cp = sixel_parse_repeat(si, cp, end);
|
|
if (cp == NULL)
|
|
goto bad;
|
|
break;
|
|
case '-':
|
|
si->dx = 0;
|
|
si->dy += 6;
|
|
break;
|
|
case '$':
|
|
si->dx = 0;
|
|
break;
|
|
default:
|
|
if (ch < 0x20)
|
|
break;
|
|
if (ch < 0x3f || ch > 0x7e)
|
|
goto bad;
|
|
if (sixel_parse_write(si, ch - 0x3f) != 0)
|
|
goto bad;
|
|
si->dx++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (si->x == 0 || si->y == 0)
|
|
goto bad;
|
|
return (si);
|
|
|
|
bad:
|
|
free(si);
|
|
return (NULL);
|
|
}
|
|
|
|
void
|
|
sixel_free(struct sixel_image *si)
|
|
{
|
|
u_int y;
|
|
|
|
for (y = 0; y < si->y; y++)
|
|
free(si->lines[y].data);
|
|
free(si->lines);
|
|
|
|
free(si->colours);
|
|
free(si);
|
|
}
|
|
|
|
void
|
|
sixel_log(struct sixel_image *si)
|
|
{
|
|
struct sixel_line *sl;
|
|
char s[SIXEL_WIDTH_LIMIT + 1];
|
|
u_int i, x, y, cx, cy;
|
|
|
|
sixel_size_in_cells(si, &cx, &cy);
|
|
log_debug("%s: image %ux%u (%ux%u)", __func__, si->x, si->y, cx, cy);
|
|
for (i = 0; i < si->ncolours; i++)
|
|
log_debug("%s: colour %u is %07x", __func__, i, si->colours[i]);
|
|
for (y = 0; y < si->y; y++) {
|
|
sl = &si->lines[y];
|
|
for (x = 0; x < si->x; x++) {
|
|
if (x >= sl->x)
|
|
s[x] = '_';
|
|
else if (sl->data[x] != 0)
|
|
s[x] = '0' + (sl->data[x] - 1) % 10;
|
|
else
|
|
s[x] = '.';
|
|
}
|
|
s[x] = '\0';
|
|
log_debug("%s: %4u: %s", __func__, y, s);
|
|
}
|
|
}
|
|
|
|
void
|
|
sixel_size_in_cells(struct sixel_image *si, u_int *x, u_int *y)
|
|
{
|
|
if ((si->x % si->xpixel) == 0)
|
|
*x = (si->x / si->xpixel);
|
|
else
|
|
*x = 1 + (si->x / si->xpixel);
|
|
if ((si->y % si->ypixel) == 0)
|
|
*y = (si->y / si->ypixel);
|
|
else
|
|
*y = 1 + (si->y / si->ypixel);
|
|
}
|
|
|
|
struct sixel_image *
|
|
sixel_scale(struct sixel_image *si, u_int xpixel, u_int ypixel, u_int ox,
|
|
u_int oy, u_int sx, u_int sy, int colours)
|
|
{
|
|
struct sixel_image *new;
|
|
u_int cx, cy, pox, poy, psx, psy, tsx, tsy, px, py;
|
|
u_int x, y, i;
|
|
|
|
/*
|
|
* We want to get the section of the image at ox,oy in image cells and
|
|
* map it onto the same size in terminal cells, remembering that we
|
|
* can only draw vertical sections of six pixels.
|
|
*/
|
|
|
|
sixel_size_in_cells(si, &cx, &cy);
|
|
if (ox >= cx)
|
|
return (NULL);
|
|
if (oy >= cy)
|
|
return (NULL);
|
|
if (ox + sx >= cx)
|
|
sx = cx - ox;
|
|
if (oy + sy >= cy)
|
|
sy = cy - oy;
|
|
|
|
if (xpixel == 0)
|
|
xpixel = si->xpixel;
|
|
if (ypixel == 0)
|
|
ypixel = si->ypixel;
|
|
|
|
pox = ox * si->xpixel;
|
|
poy = oy * si->ypixel;
|
|
psx = sx * si->xpixel;
|
|
psy = sy * si->ypixel;
|
|
|
|
tsx = sx * xpixel;
|
|
tsy = ((sy * ypixel) / 6) * 6;
|
|
|
|
new = xcalloc (1, sizeof *si);
|
|
new->xpixel = xpixel;
|
|
new->ypixel = ypixel;
|
|
|
|
for (y = 0; y < tsy; y++) {
|
|
py = poy + ((double)y * psy / tsy);
|
|
for (x = 0; x < tsx; x++) {
|
|
px = pox + ((double)x * psx / tsx);
|
|
sixel_set_pixel(new, x, y, sixel_get_pixel(si, px, py));
|
|
}
|
|
}
|
|
|
|
if (colours) {
|
|
new->colours = xmalloc(si->ncolours * sizeof *new->colours);
|
|
for (i = 0; i < si->ncolours; i++)
|
|
new->colours[i] = si->colours[i];
|
|
new->ncolours = si->ncolours;
|
|
}
|
|
return (new);
|
|
}
|
|
|
|
static void
|
|
sixel_print_add(char **buf, size_t *len, size_t *used, const char *s,
|
|
size_t slen)
|
|
{
|
|
if (*used + slen >= *len + 1) {
|
|
(*len) *= 2;
|
|
*buf = xrealloc(*buf, *len);
|
|
}
|
|
memcpy(*buf + *used, s, slen);
|
|
(*used) += slen;
|
|
}
|
|
|
|
static void
|
|
sixel_print_repeat(char **buf, size_t *len, size_t *used, u_int count, char ch)
|
|
{
|
|
char tmp[16];
|
|
size_t tmplen;
|
|
|
|
if (count == 1)
|
|
sixel_print_add(buf, len, used, &ch, 1);
|
|
else if (count == 2) {
|
|
sixel_print_add(buf, len, used, &ch, 1);
|
|
sixel_print_add(buf, len, used, &ch, 1);
|
|
} else if (count == 3) {
|
|
sixel_print_add(buf, len, used, &ch, 1);
|
|
sixel_print_add(buf, len, used, &ch, 1);
|
|
sixel_print_add(buf, len, used, &ch, 1);
|
|
} else if (count != 0) {
|
|
tmplen = xsnprintf(tmp, sizeof tmp, "!%u%c", count, ch);
|
|
sixel_print_add(buf, len, used, tmp, tmplen);
|
|
}
|
|
}
|
|
|
|
char *
|
|
sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
|
{
|
|
char *buf, tmp[64], *contains, data, last = 0;
|
|
size_t len, used = 0, tmplen;
|
|
u_int *colours, ncolours, i, c, x, y, count;
|
|
struct sixel_line *sl;
|
|
|
|
if (map != NULL) {
|
|
colours = map->colours;
|
|
ncolours = map->ncolours;
|
|
} else {
|
|
colours = si->colours;
|
|
ncolours = si->ncolours;
|
|
}
|
|
contains = xcalloc(1, ncolours);
|
|
|
|
len = 8192;
|
|
buf = xmalloc(len);
|
|
|
|
sixel_print_add(&buf, &len, &used, "\033Pq", 3);
|
|
|
|
tmplen = xsnprintf(tmp, sizeof tmp, "\"1;1;%u;%u", si->x, si->y);
|
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
|
|
|
for (i = 0; i < ncolours; i++) {
|
|
c = colours[i];
|
|
tmplen = xsnprintf(tmp, sizeof tmp, "#%u;%u;%u;%u;%u",
|
|
i, c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
|
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
|
}
|
|
|
|
for (y = 0; y < si->y; y += 6) {
|
|
memset(contains, 0, ncolours);
|
|
for (x = 0; x < si->x; x++) {
|
|
for (i = 0; i < 6; i++) {
|
|
if (y + i >= si->y)
|
|
break;
|
|
sl = &si->lines[y + i];
|
|
if (x < sl->x && sl->data[x] != 0)
|
|
contains[sl->data[x] - 1] = 1;
|
|
}
|
|
}
|
|
|
|
for (c = 0; c < ncolours; c++) {
|
|
if (!contains[c])
|
|
continue;
|
|
tmplen = xsnprintf(tmp, sizeof tmp, "#%u", c);
|
|
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
|
|
|
count = 0;
|
|
for (x = 0; x < si->x; x++) {
|
|
data = 0;
|
|
for (i = 0; i < 6; i++) {
|
|
if (y + i >= si->y)
|
|
break;
|
|
sl = &si->lines[y + i];
|
|
if (x < sl->x && sl->data[x] == c + 1)
|
|
data |= (1 << i);
|
|
}
|
|
data += 0x3f;
|
|
if (data != last) {
|
|
sixel_print_repeat(&buf, &len, &used,
|
|
count, last);
|
|
last = data;
|
|
count = 1;
|
|
} else
|
|
count++;
|
|
}
|
|
sixel_print_repeat(&buf, &len, &used, count, data);
|
|
sixel_print_add(&buf, &len, &used, "$", 1);
|
|
}
|
|
|
|
if (buf[used - 1] == '$')
|
|
used--;
|
|
if (buf[used - 1] != '-')
|
|
sixel_print_add(&buf, &len, &used, "-", 1);
|
|
}
|
|
if (buf[used - 1] == '$' || buf[used - 1] == '-')
|
|
used--;
|
|
|
|
sixel_print_add(&buf, &len, &used, "\033\\", 2);
|
|
|
|
buf[used] = '\0';
|
|
if (size != NULL)
|
|
*size = used;
|
|
|
|
free(contains);
|
|
return (buf);
|
|
}
|
|
|
|
struct screen *
|
|
sixel_to_screen(struct sixel_image *si)
|
|
{
|
|
struct screen *s;
|
|
struct screen_write_ctx ctx;
|
|
struct grid_cell gc;
|
|
u_int x, y, sx, sy;
|
|
|
|
sixel_size_in_cells(si, &sx, &sy);
|
|
|
|
s = xmalloc(sizeof *s);
|
|
screen_init(s, sx, sy, 0);
|
|
|
|
memcpy(&gc, &grid_default_cell, sizeof gc);
|
|
gc.attr |= (GRID_ATTR_CHARSET|GRID_ATTR_DIM);
|
|
utf8_set(&gc.data, '~');
|
|
|
|
screen_write_start(&ctx, s);
|
|
if (sx == 1 || sy == 1) {
|
|
for (y = 0; y < sy; y++) {
|
|
for (x = 0; x < sx; x++)
|
|
grid_view_set_cell(s->grid, x, y, &gc);
|
|
}
|
|
} else {
|
|
screen_write_box(&ctx, sx, sy, BOX_LINES_DEFAULT, NULL, NULL);
|
|
for (y = 1; y < sy - 1; y++) {
|
|
for (x = 1; x < sx - 1; x++)
|
|
grid_view_set_cell(s->grid, x, y, &gc);
|
|
}
|
|
}
|
|
screen_write_stop(&ctx);
|
|
return (s);
|
|
}
|