1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00

[sixel] Copied big framgents of code form libsixel.

Also hardcode 6x13 cell size. Scroll works for me.
This commit is contained in:
Witold Filipczyk 2023-05-21 21:17:13 +02:00
parent c0a140f4f3
commit 3fee0b4f6a
5 changed files with 881 additions and 31 deletions

View File

@ -27,6 +27,733 @@ struct sixel_decoder {
sixel_allocator_t *allocator;
};
/* encoder object */
struct sixel_encoder {
unsigned int ref; /* reference counter */
sixel_allocator_t *allocator; /* allocator object */
int reqcolors;
int color_option;
char *mapfile;
int builtin_palette;
int method_for_diffuse;
int method_for_largest;
int method_for_rep;
int quality_mode;
int method_for_resampling;
int loop_mode;
int palette_type;
int f8bit;
int finvert;
int fuse_macro;
int fignore_delay;
int complexion;
int fstatic;
int pixelwidth;
int pixelheight;
int percentwidth;
int percentheight;
int clipx;
int clipy;
int clipwidth;
int clipheight;
int clipfirst;
int macro_number;
int penetrate_multiplexer;
int encode_policy;
int ormode;
int pipe_mode;
int verbose;
int has_gri_arg_limit;
unsigned char *bgcolor;
int outfd;
int finsecure;
int *cancel_flag;
void *dither_cache;
};
/* palette type */
#define SIXEL_COLOR_OPTION_DEFAULT 0 /* use default settings */
#define SIXEL_COLOR_OPTION_MONOCHROME 1 /* use monochrome palette */
#define SIXEL_COLOR_OPTION_BUILTIN 2 /* use builtin palette */
#define SIXEL_COLOR_OPTION_MAPFILE 3 /* use mapfile option */
#define SIXEL_COLOR_OPTION_HIGHCOLOR 4 /* use highcolor option */
static int
sixel_write_callback(char *data, int size, void *priv)
{
struct string *text = priv;
add_bytes_to_string(text, data, size);
return size;
}
static SIXELSTATUS
sixel_encoder_output_without_macro(
sixel_frame_t /* in */ *frame,
sixel_dither_t /* in */ *dither,
sixel_output_t /* in */ *output,
sixel_encoder_t /* in */ *encoder)
{
SIXELSTATUS status = SIXEL_OK;
static unsigned char *p;
int depth;
enum { message_buffer_size = 256 };
char message[message_buffer_size];
int nwrite;
int dulation;
int delay;
int lag = 0;
struct timespec tv;
clock_t start;
unsigned char *pixbuf;
int width;
int height;
int pixelformat;
size_t size;
if (encoder == NULL) {
sixel_helper_set_additional_message(
"sixel_encoder_output_without_macro: encoder object is null.");
status = SIXEL_BAD_ARGUMENT;
goto end;
}
if (encoder->color_option == SIXEL_COLOR_OPTION_DEFAULT) {
sixel_dither_set_optimize_palette(dither, 1);
}
pixelformat = sixel_frame_get_pixelformat(frame);
depth = sixel_helper_compute_depth(pixelformat);
if (depth < 0) {
status = SIXEL_LOGIC_ERROR;
nwrite = sprintf(message,
"sixel_encoder_output_without_macro: "
"sixel_helper_compute_depth(%08x) failed.",
pixelformat);
if (nwrite > 0) {
sixel_helper_set_additional_message(message);
}
goto end;
}
width = sixel_frame_get_width(frame);
height = sixel_frame_get_height(frame);
size = (size_t)(width * height * depth);
p = (unsigned char *)sixel_allocator_malloc(encoder->allocator, size);
if (p == NULL) {
sixel_helper_set_additional_message(
"sixel_encoder_output_without_macro: sixel_allocator_malloc() failed.");
status = SIXEL_BAD_ALLOCATION;
goto end;
}
start = clock();
delay = sixel_frame_get_delay(frame);
if (delay > 0 && !encoder->fignore_delay) {
dulation = (int)((clock() - start) * 1000 * 1000 / CLOCKS_PER_SEC) - (int)lag;
lag = 0;
if (dulation < 10000 * delay) {
tv.tv_sec = 0;
tv.tv_nsec = (long)((10000 * delay - dulation) * 1000);
nanosleep(&tv, NULL);
} else {
lag = (int)(10000 * delay - dulation);
}
}
pixbuf = sixel_frame_get_pixels(frame);
memcpy(p, pixbuf, (size_t)(width * height * depth));
if (encoder->cancel_flag && *encoder->cancel_flag) {
goto end;
}
status = sixel_encode(p, width, height, depth, dither, output);
if (status != SIXEL_OK) {
goto end;
}
end:
sixel_allocator_free(encoder->allocator, p);
return status;
}
static SIXELSTATUS
sixel_encoder_output_with_macro(
sixel_frame_t /* in */ *frame,
sixel_dither_t /* in */ *dither,
sixel_output_t /* in */ *output,
sixel_encoder_t /* in */ *encoder)
{
SIXELSTATUS status = SIXEL_OK;
enum { message_buffer_size = 256 };
char buffer[message_buffer_size];
int nwrite;
int dulation;
int lag = 0;
struct timespec tv;
clock_t start;
unsigned char *pixbuf;
int width;
int height;
int delay;
start = clock();
if (sixel_frame_get_loop_no(frame) == 0) {
if (encoder->macro_number >= 0) {
nwrite = sprintf(buffer, "\033P%d;0;1!z", encoder->macro_number);
} else {
nwrite = sprintf(buffer, "\033P%d;0;1!z", sixel_frame_get_frame_no(frame));
}
if (nwrite < 0) {
status = (SIXEL_LIBC_ERROR | (errno & 0xff));
sixel_helper_set_additional_message(
"sixel_encoder_output_with_macro: sprintf() failed.");
goto end;
}
nwrite = sixel_write_callback(buffer, (int)strlen(buffer), &encoder->outfd);
if (nwrite < 0) {
status = (SIXEL_LIBC_ERROR | (errno & 0xff));
sixel_helper_set_additional_message(
"sixel_encoder_output_with_macro: sixel_write_callback() failed.");
goto end;
}
pixbuf = sixel_frame_get_pixels(frame),
width = sixel_frame_get_width(frame),
height = sixel_frame_get_height(frame),
status = sixel_encode(pixbuf, width, height, /* unused */ 3, dither, output);
if (SIXEL_FAILED(status)) {
goto end;
}
nwrite = sixel_write_callback("\033\\", 2, &encoder->outfd);
if (nwrite < 0) {
status = (SIXEL_LIBC_ERROR | (errno & 0xff));
sixel_helper_set_additional_message(
"sixel_encoder_output_with_macro: sixel_write_callback() failed.");
goto end;
}
}
if (encoder->macro_number < 0) {
nwrite = sprintf(buffer, "\033[%d*z", sixel_frame_get_frame_no(frame));
if (nwrite < 0) {
status = (SIXEL_LIBC_ERROR | (errno & 0xff));
sixel_helper_set_additional_message(
"sixel_encoder_output_with_macro: sprintf() failed.");
}
nwrite = sixel_write_callback(buffer, (int)strlen(buffer), &encoder->outfd);
if (nwrite < 0) {
status = (SIXEL_LIBC_ERROR | (errno & 0xff));
sixel_helper_set_additional_message(
"sixel_encoder_output_with_macro: sixel_write_callback() failed.");
goto end;
}
delay = sixel_frame_get_delay(frame);
if (delay > 0 && !encoder->fignore_delay) {
dulation = (int)((clock() - start) * 1000 * 1000 / CLOCKS_PER_SEC) - (int)lag;
lag = 0;
if (dulation < 10000 * delay) {
tv.tv_sec = 0;
tv.tv_nsec = (long)((10000 * delay - dulation) * 1000);
nanosleep(&tv, NULL);
} else {
lag = (int)(10000 * delay - dulation);
}
}
}
end:
return status;
}
/* returns monochrome dithering context object */
static SIXELSTATUS
sixel_prepare_monochrome_palette(
sixel_dither_t /* out */ **dither,
int /* in */ finvert)
{
SIXELSTATUS status = SIXEL_FALSE;
if (finvert) {
*dither = sixel_dither_get(SIXEL_BUILTIN_MONO_LIGHT);
} else {
*dither = sixel_dither_get(SIXEL_BUILTIN_MONO_DARK);
}
if (*dither == NULL) {
sixel_helper_set_additional_message(
"sixel_prepare_monochrome_palette: sixel_dither_get() failed.");
status = SIXEL_RUNTIME_ERROR;
goto end;
}
status = SIXEL_OK;
end:
return status;
}
/* returns dithering context object with specified builtin palette */
static SIXELSTATUS
sixel_prepare_builtin_palette(
sixel_dither_t /* out */ **dither,
int /* in */ builtin_palette)
{
SIXELSTATUS status = SIXEL_FALSE;
*dither = sixel_dither_get(builtin_palette);
if (*dither == NULL) {
sixel_helper_set_additional_message(
"sixel_prepare_builtin_palette: sixel_dither_get() failed.");
status = SIXEL_RUNTIME_ERROR;
goto end;
}
status = SIXEL_OK;
end:
return status;
}
#if 0
/* create palette from specified map file */
static SIXELSTATUS
sixel_prepare_specified_palette(
sixel_dither_t /* out */ **dither,
sixel_encoder_t /* in */ *encoder)
{
SIXELSTATUS status = SIXEL_FALSE;
sixel_callback_context_for_mapfile_t callback_context;
callback_context.reqcolors = encoder->reqcolors;
callback_context.dither = NULL;
callback_context.allocator = encoder->allocator;
status = sixel_helper_load_image_file(encoder->mapfile,
1, /* fstatic */
1, /* fuse_palette */
SIXEL_PALETTE_MAX, /* reqcolors */
encoder->bgcolor,
SIXEL_LOOP_DISABLE,
load_image_callback_for_palette,
encoder->finsecure,
encoder->cancel_flag,
&callback_context,
encoder->allocator);
if (status != SIXEL_OK) {
return status;
}
*dither = callback_context.dither;
return status;
}
#endif
/* create dither object from a frame */
static SIXELSTATUS
sixel_encoder_prepare_palette(
sixel_encoder_t *encoder, /* encoder object */
sixel_frame_t *frame, /* input frame object */
sixel_dither_t **dither) /* dither object to be created from the frame */
{
SIXELSTATUS status = SIXEL_FALSE;
int histogram_colors;
switch (encoder->color_option) {
case SIXEL_COLOR_OPTION_HIGHCOLOR:
if (encoder->dither_cache) {
*dither = encoder->dither_cache;
status = SIXEL_OK;
} else {
status = sixel_dither_new(dither, (-1), encoder->allocator);
}
goto end;
case SIXEL_COLOR_OPTION_MONOCHROME:
if (encoder->dither_cache) {
*dither = encoder->dither_cache;
status = SIXEL_OK;
} else {
status = sixel_prepare_monochrome_palette(dither, encoder->finvert);
}
goto end;
case SIXEL_COLOR_OPTION_MAPFILE:
#if 0
if (encoder->dither_cache) {
*dither = encoder->dither_cache;
status = SIXEL_OK;
} else {
status = sixel_prepare_specified_palette(dither, encoder);
}
#endif
goto end;
case SIXEL_COLOR_OPTION_BUILTIN:
if (encoder->dither_cache) {
*dither = encoder->dither_cache;
status = SIXEL_OK;
} else {
status = sixel_prepare_builtin_palette(dither, encoder->builtin_palette);
}
goto end;
case SIXEL_COLOR_OPTION_DEFAULT:
default:
break;
}
if (sixel_frame_get_pixelformat(frame) & SIXEL_FORMATTYPE_PALETTE) {
if (!sixel_frame_get_palette(frame)) {
status = SIXEL_LOGIC_ERROR;
goto end;
}
status = sixel_dither_new(dither, sixel_frame_get_ncolors(frame),
encoder->allocator);
if (SIXEL_FAILED(status)) {
goto end;
}
sixel_dither_set_palette(*dither, sixel_frame_get_palette(frame));
sixel_dither_set_pixelformat(*dither, sixel_frame_get_pixelformat(frame));
if (sixel_frame_get_transparent(frame) != (-1)) {
sixel_dither_set_transparent(*dither, sixel_frame_get_transparent(frame));
}
if (*dither && encoder->dither_cache) {
sixel_dither_unref(encoder->dither_cache);
}
goto end;
}
if (sixel_frame_get_pixelformat(frame) & SIXEL_FORMATTYPE_GRAYSCALE) {
switch (sixel_frame_get_pixelformat(frame)) {
case SIXEL_PIXELFORMAT_G1:
*dither = sixel_dither_get(SIXEL_BUILTIN_G1);
break;
case SIXEL_PIXELFORMAT_G2:
*dither = sixel_dither_get(SIXEL_BUILTIN_G2);
break;
case SIXEL_PIXELFORMAT_G4:
*dither = sixel_dither_get(SIXEL_BUILTIN_G4);
break;
case SIXEL_PIXELFORMAT_G8:
*dither = sixel_dither_get(SIXEL_BUILTIN_G8);
break;
default:
*dither = NULL;
status = SIXEL_LOGIC_ERROR;
goto end;
}
if (*dither && encoder->dither_cache) {
sixel_dither_unref(encoder->dither_cache);
}
sixel_dither_set_pixelformat(*dither, sixel_frame_get_pixelformat(frame));
status = SIXEL_OK;
goto end;
}
if (encoder->dither_cache) {
sixel_dither_unref(encoder->dither_cache);
}
status = sixel_dither_new(dither, encoder->reqcolors, encoder->allocator);
if (SIXEL_FAILED(status)) {
goto end;
}
status = sixel_dither_initialize(*dither,
sixel_frame_get_pixels(frame),
sixel_frame_get_width(frame),
sixel_frame_get_height(frame),
sixel_frame_get_pixelformat(frame),
encoder->method_for_largest,
encoder->method_for_rep,
encoder->quality_mode);
if (SIXEL_FAILED(status)) {
goto end;
}
histogram_colors = sixel_dither_get_num_of_histogram_colors(*dither);
if (histogram_colors <= encoder->reqcolors) {
encoder->method_for_diffuse = SIXEL_DIFFUSE_NONE;
}
sixel_dither_set_pixelformat(*dither, sixel_frame_get_pixelformat(frame));
status = SIXEL_OK;
end:
return status;
}
/* from libsixel-1.10.3 */
/* clip a frame with settings of specified encoder object */
static SIXELSTATUS
sixel_encoder_do_clip(
sixel_encoder_t /* in */ *encoder, /* encoder object */
sixel_frame_t /* in */ *frame) /* frame object to be resized */
{
SIXELSTATUS status = SIXEL_FALSE;
int src_width;
int src_height;
int clip_x;
int clip_y;
int clip_w;
int clip_h;
/* get frame width and height */
src_width = sixel_frame_get_width(frame);
src_height = sixel_frame_get_height(frame);
/* settings around clipping */
clip_x = encoder->clipx;
clip_y = encoder->clipy;
clip_w = encoder->clipwidth;
clip_h = encoder->clipheight;
/* adjust clipping width with comparing it to frame width */
if (clip_w + clip_x > src_width) {
if (clip_x > src_width) {
clip_w = 0;
} else {
clip_w = src_width - clip_x;
}
}
/* adjust clipping height with comparing it to frame height */
if (clip_h + clip_y > src_height) {
if (clip_y > src_height) {
clip_h = 0;
} else {
clip_h = src_height - clip_y;
}
}
/* do clipping */
if (clip_w > 0 && clip_h > 0) {
status = sixel_frame_clip(frame, clip_x, clip_y, clip_w, clip_h);
if (SIXEL_FAILED(status)) {
goto end;
}
}
/* success */
status = SIXEL_OK;
end:
return status;
}
/* from libsixel-1.10.3 */
/* resize a frame with settings of specified encoder object */
static SIXELSTATUS
sixel_encoder_do_resize(
sixel_encoder_t /* in */ *encoder, /* encoder object */
sixel_frame_t /* in */ *frame) /* frame object to be resized */
{
SIXELSTATUS status = SIXEL_FALSE;
int src_width;
int src_height;
int dst_width;
int dst_height;
/* get frame width and height */
src_width = sixel_frame_get_width(frame);
src_height = sixel_frame_get_height(frame);
/* settings around scaling */
dst_width = encoder->pixelwidth; /* may be -1 (default) */
dst_height = encoder->pixelheight; /* may be -1 (default) */
/* if the encoder has percentwidth or percentheight property,
convert them to pixelwidth / pixelheight */
if (encoder->percentwidth > 0) {
dst_width = src_width * encoder->percentwidth / 100;
}
if (encoder->percentheight > 0) {
dst_height = src_height * encoder->percentheight / 100;
}
/* if only either width or height is set, set also the other
to retain frame aspect ratio */
if (encoder->pixelwidth > 0 && dst_height <= 0) {
dst_height = src_height * encoder->pixelwidth / src_width;
}
if (encoder->pixelheight > 0 && dst_width <= 0) {
dst_width = src_width * encoder->pixelheight / src_height;
}
/* do resize */
if (dst_width > 0 && dst_height > 0) {
status = sixel_frame_resize(frame, dst_width, dst_height,
encoder->method_for_resampling);
if (SIXEL_FAILED(status)) {
goto end;
}
}
/* success */
status = SIXEL_OK;
end:
return status;
}
/* from libsixel-1.10.3 */
static SIXELSTATUS
sixel_encoder_encode_frame(
sixel_encoder_t *encoder,
sixel_frame_t *frame,
sixel_output_t *output)
{
SIXELSTATUS status = SIXEL_FALSE;
sixel_dither_t *dither = NULL;
//int height;
//int is_animation = 0;
//int nwrite;
/* evaluate -w, -h, and -c option: crop/scale input source */
if (encoder->clipfirst) {
/* clipping */
status = sixel_encoder_do_clip(encoder, frame);
if (SIXEL_FAILED(status)) {
goto end;
}
/* scaling */
status = sixel_encoder_do_resize(encoder, frame);
if (SIXEL_FAILED(status)) {
goto end;
}
} else {
/* scaling */
status = sixel_encoder_do_resize(encoder, frame);
if (SIXEL_FAILED(status)) {
goto end;
}
/* clipping */
status = sixel_encoder_do_clip(encoder, frame);
if (SIXEL_FAILED(status)) {
goto end;
}
}
/* prepare dither context */
status = sixel_encoder_prepare_palette(encoder, frame, &dither);
if (status != SIXEL_OK) {
goto end;
}
if (encoder->dither_cache != NULL) {
encoder->dither_cache = dither;
sixel_dither_ref(dither);
}
#if 0
/* evaluate -v option: print palette */
if (encoder->verbose) {
if ((sixel_frame_get_pixelformat(frame) & SIXEL_FORMATTYPE_PALETTE)) {
sixel_debug_print_palette(dither);
}
}
#endif
/* evaluate -d option: set method for diffusion */
sixel_dither_set_diffusion_type(dither, encoder->method_for_diffuse);
/* evaluate -C option: set complexion score */
if (encoder->complexion > 1) {
sixel_dither_set_complexion_score(dither, encoder->complexion);
}
if (output) {
sixel_output_ref(output);
} else {
#if 0
/* create output context */
if (encoder->fuse_macro || encoder->macro_number >= 0) {
/* -u or -n option */
status = sixel_output_new(&output,
sixel_hex_write_callback,
&encoder->outfd,
encoder->allocator);
} else {
status = sixel_output_new(&output,
sixel_write_callback,
&encoder->outfd,
encoder->allocator);
}
if (SIXEL_FAILED(status)) {
goto end;
}
#endif
}
sixel_output_set_8bit_availability(output, encoder->f8bit);
sixel_output_set_gri_arg_limit(output, encoder->has_gri_arg_limit);
sixel_output_set_palette_type(output, encoder->palette_type);
sixel_output_set_penetrate_multiplexer(
output, encoder->penetrate_multiplexer);
sixel_output_set_encode_policy(output, encoder->encode_policy);
sixel_output_set_ormode(output, encoder->ormode);
#if 0
if (sixel_frame_get_multiframe(frame) && !encoder->fstatic) {
if (sixel_frame_get_loop_no(frame) != 0 || sixel_frame_get_frame_no(frame) != 0) {
is_animation = 1;
}
height = sixel_frame_get_height(frame);
(void) sixel_tty_scroll(sixel_write_callback, encoder->outfd, height, is_animation);
}
#endif
if (encoder->cancel_flag && *encoder->cancel_flag) {
status = SIXEL_INTERRUPTED;
goto end;
}
/* output sixel: junction of multi-frame processing strategy */
if (encoder->fuse_macro) { /* -u option */
/* use macro */
status = sixel_encoder_output_with_macro(frame, dither, output, encoder);
} else if (encoder->macro_number >= 0) { /* -n option */
/* use macro */
status = sixel_encoder_output_with_macro(frame, dither, output, encoder);
} else {
/* do not use macro */
status = sixel_encoder_output_without_macro(frame, dither, output, encoder);
}
#if 0
if (encoder->cancel_flag && *encoder->cancel_flag) {
nwrite = sixel_write_callback("\x18\033\\", 3, &encoder->outfd);
if (nwrite < 0) {
status = (SIXEL_LIBC_ERROR | (errno & 0xff));
sixel_helper_set_additional_message(
"load_image_callback: sixel_write_callback() failed.");
goto end;
}
status = SIXEL_INTERRUPTED;
}
#endif
if (SIXEL_FAILED(status)) {
goto end;
}
end:
if (output) {
sixel_output_unref(output);
}
if (dither) {
sixel_dither_unref(dither);
}
return status;
}
void
try_to_draw_images(struct terminal *term)
{
@ -39,7 +766,7 @@ try_to_draw_images(struct terminal *term)
return;
}
add_cursor_move_to_string(&text, im->y + 1, im->x + 1);
add_string_to_string(&text, &im->sixel);
add_string_to_string(&text, &im->pixels);
if (text.length) {
if (term->master) want_draw();
@ -54,32 +781,36 @@ void
delete_image(struct image *im)
{
del_from_list(im);
done_string(&im->sixel);
done_string(&im->pixels);
mem_free(im);
}
int
add_image_to_document(struct document *doc, struct string *pixels, int lineno)
{
struct image *im = mem_calloc(1, sizeof(*im));
if (!im) {
return 0;
}
sixel_decoder_t *decoder = NULL;
SIXELSTATUS status = sixel_decoder_new(&decoder, NULL);
if (status != SIXEL_OK) {
return 0;
}
unsigned char *indexed_pixels = NULL;
unsigned char *palette = NULL;
sixel_decoder_t *decoder = NULL;
sixel_frame_t *frame = NULL;
int ncolors;
int width;
int height;
int ile = 0;
struct image *im = mem_calloc(1, sizeof(*im));
SIXELSTATUS status;
if (!im) {
return 0;
}
if (!init_string(&im->pixels)) {
mem_free(im);
return 0;
}
status = sixel_decoder_new(&decoder, NULL);
if (SIXEL_FAILED(status)) {
goto end;
}
status = sixel_decode_raw(
(unsigned char *)pixels->source,
pixels->length,
@ -91,6 +822,24 @@ add_image_to_document(struct document *doc, struct string *pixels, int lineno)
decoder->allocator
);
if (SIXEL_FAILED(status)) {
goto end;
}
status = sixel_frame_new(&frame, NULL);
if (SIXEL_FAILED(status)) {
goto end;
}
status = sixel_frame_init(
frame,
indexed_pixels,
width,
height,
SIXEL_PIXELFORMAT_PAL8,
palette,
ncolors
);
if (SIXEL_FAILED(status)) {
goto end;
}
@ -98,13 +847,107 @@ add_image_to_document(struct document *doc, struct string *pixels, int lineno)
im->x = 0;
im->width = width;
im->height = height;
*(&im->sixel) = *pixels;
ile = (height + 15) / 16;
add_string_to_string(&im->pixels, pixels);
ile = (height + 12) / 13;
add_to_list(doc->images, im);
end:
sixel_allocator_free(decoder->allocator, indexed_pixels);
sixel_allocator_free(decoder->allocator, palette);
sixel_frame_unref(frame);
sixel_decoder_unref(decoder);
return ile;
}
struct image *
copy_frame(struct image *src, int box_width, int box_height, int cell_width, int cell_height, int dy)
{
sixel_decoder_t *decoder = NULL;
sixel_encoder_t *encoder = NULL;
sixel_frame_t *frame = NULL;
unsigned char *indexed_pixels = NULL;
unsigned char *palette = NULL;
int ncolors;
int width;
int height;
int y;
struct image *dest = mem_calloc(1, sizeof(*dest));
SIXELSTATUS status;
if (!dest) {
return NULL;
}
if (!init_string(&dest->pixels)) {
mem_free(dest);
return NULL;
}
status = sixel_decoder_new(&decoder, NULL);
if (SIXEL_FAILED(status)) {
goto end;
}
status = sixel_decode_raw(
(unsigned char *)src->pixels.source,
src->pixels.length,
&indexed_pixels,
&width,
&height,
&palette,
&ncolors,
decoder->allocator
);
if (SIXEL_FAILED(status)) {
goto end;
}
status = sixel_frame_new(&frame, NULL);
if (SIXEL_FAILED(status)) {
goto end;
}
status = sixel_frame_init(
frame,
indexed_pixels,
width,
height,
SIXEL_PIXELFORMAT_PAL8,
palette,
ncolors
);
if (SIXEL_FAILED(status)) {
goto end;
}
status = sixel_encoder_new(&encoder, NULL);
if (SIXEL_FAILED(status)) {
goto end;
}
encoder->clipx = 0;
y = src->y - dy;
encoder->clipy = y >= 0 ? 0 : (-y * cell_height);
encoder->clipwidth = box_width * cell_width;
encoder->clipheight = box_height * cell_height;
sixel_output_t *output = NULL;
status = sixel_output_new(&output, sixel_write_callback, &dest->pixels, NULL);
if (SIXEL_FAILED(status)) {
goto end;
}
status = sixel_encoder_encode_frame(encoder, frame, output);
if (SIXEL_FAILED(status)) {
goto end;
}
dest->x = src->x;
dest->y = y < 0 ? 1 : y;
dest->width = src->width;
dest->height = src->height;
end:
sixel_frame_unref(frame);
sixel_decoder_unref(decoder);
sixel_encoder_unref(encoder);
return dest;
}

View File

@ -1,6 +1,7 @@
#ifndef EL__TERMINAL_SIXEL_H
#define EL__TERMINAL_SIXEL_H
#include <sixel.h>
#include "util/lists.h"
#include "util/string.h"
@ -12,9 +13,10 @@ extern "C" {
struct document;
struct terminal;
struct image {
LIST_HEAD(struct image);
struct string sixel;
struct string pixels;
int x;
int y;
int width;
@ -28,6 +30,8 @@ void try_to_draw_images(struct terminal *term);
/* return height of image in terminal rows */
int add_image_to_document(struct document *doc, struct string *pixels, int lineno);
struct image *copy_frame(struct image *src, int box_width, int box_height, int cell_width, int cell_height, int dy);
#endif

View File

@ -120,6 +120,8 @@ init_term(int fdin, int fdout)
#ifdef CONFIG_LIBSIXEL
init_list(term->images);
term->cell_height = 13;
term->cell_width = 6;
#endif
term->fdin = fdin;
term->fdout = fdout;

View File

@ -175,6 +175,8 @@ struct terminal {
#ifdef CONFIG_LIBSIXEL
LIST_OF(struct image) images;
int cell_width;
int cell_height;
#endif
};

View File

@ -469,19 +469,18 @@ draw_doc(struct session *ses, struct document_view *doc_view, int active)
struct image *im;
foreach (im, doc_view->document->images) {
if (im) {
struct image *im_copy = mem_calloc(1, sizeof(*im_copy));
if (im->y >= vs->y + box->height) {
continue;
}
if (im_copy) {
if (init_string(&im_copy->sixel)) {
add_string_to_string(&im_copy->sixel, &im->sixel);
im_copy->x = im->x;
im_copy->y = im->y;
im_copy->width = im->width;
im_copy->height = im->height;
add_to_list(term->images, im_copy);
}
}
if (im->y + ((im->height + term->cell_height - 1) / term->cell_height) < vs->y) {
continue;
}
struct image *im_copy = copy_frame(im, box->width, box->height, term->cell_width, term->cell_height, vs->y);
if (im_copy) {
add_to_list(term->images, im_copy);
}
}
}