0
0
mirror of https://github.com/rkd77/elinks.git synced 2025-06-30 22:19:29 -04:00

[image] Added more portable code for encoding sixel image

This commit is contained in:
Witold Filipczyk 2025-06-11 18:00:35 +02:00
parent 70189a892a
commit 9de22e9085
8 changed files with 146 additions and 125 deletions

View File

@ -40,6 +40,7 @@
#include "globhist/globhist.h"
#include "mime/mime.h"
#include "protocol/uri.h"
#include "terminal/image.h"
#ifdef CONFIG_KITTY
#include "terminal/kitty.h"
#endif

View File

@ -11,6 +11,7 @@ OBJS = \
draw.o \
event.o \
hardio.o \
image.o \
kbd.o \
screen.o \
tab.o \

123
src/terminal/image.c Normal file
View File

@ -0,0 +1,123 @@
/* Terminal kitty and sixel routines. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef CONFIG_GZIP
#include <zlib.h>
#endif
#ifdef CONFIG_LIBSIXEL
#include <sixel.h>
#endif
#include "elinks.h"
#include "terminal/image.h"
#include "util/base64.h"
#include "util/memory.h"
#include "util/string.h"
#if defined(CONFIG_KITTY) || defined(CONFIG_SIXEL)
#define STB_IMAGE_IMPLEMENTATION
#include "terminal/stb_image.h"
#endif
#ifdef CONFIG_KITTY
unsigned char *
el_kitty_get_image(char *data, int length, int *outlen, int *width, int *height, int *compressed)
{
ELOG
int comp;
unsigned char *pixels = stbi_load_from_memory((unsigned char *)data, length, width, height, &comp, KITTY_BYTES_PER_PIXEL);
unsigned char *b64;
if (!pixels) {
return NULL;
}
int size = *width * *height * KITTY_BYTES_PER_PIXEL;
*compressed = 0;
#ifdef CONFIG_GZIP
unsigned char *complace = (unsigned char *)mem_alloc(size);
if (complace) {
unsigned long compsize = size;
int res = compress(complace, &compsize, pixels, size);
if (res == Z_OK) {
*compressed = 1;
b64 = base64_encode_bin(complace, compsize, outlen);
stbi_image_free(pixels);
mem_free(complace);
return b64;
}
mem_free(complace);
}
#endif
b64 = base64_encode_bin(pixels, size, outlen);
stbi_image_free(pixels);
return b64;
}
#endif
#ifdef CONFIG_LIBSIXEL
static int
sixel_write_callback(char *data, int size, void *priv)
{
ELOG
struct string *text = priv;
add_bytes_to_string(text, data, size);
return size;
}
unsigned char *
el_sixel_get_image(char *data, int length, int *outlen)
{
ELOG
int comp;
int width;
int height;
unsigned char *outdata = NULL;
unsigned char *pixels = stbi_load_from_memory((unsigned char *)data, length, &width, &height, &comp, 3);
if (!pixels) {
return NULL;
}
sixel_output_t *output = NULL;
sixel_dither_t *dither = NULL;
struct string ret;
if (!init_string(&ret)) {
goto end;
}
SIXELSTATUS status = sixel_output_new(&output, sixel_write_callback, &ret, NULL);
if (SIXEL_FAILED(status)) {
goto end;
}
dither = sixel_dither_get(SIXEL_BUILTIN_XTERM256);
sixel_dither_set_pixelformat(dither, SIXEL_PIXELFORMAT_RGB888);
status = sixel_encode(pixels, width, height, 3, dither, output);
outdata = (unsigned char *)memacpy(ret.source, ret.length);
if (outdata) {
*outlen = ret.length;
}
done_string(&ret);
end:
stbi_image_free(pixels);
return outdata;
}
#endif

20
src/terminal/image.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef EL__TERMINAL_IMAGE_H
#define EL__TERMINAL_IMAGE_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_KITTY
unsigned char *el_kitty_get_image(char *data, int len, int *outlen, int *width, int *height, int *compressed);
#endif
#ifdef CONFIG_LIBSIXEL
unsigned char *el_sixel_get_image(char *data, int len, int *outlen);
#endif
#ifdef __cplusplus
}
#endif
#endif /* EL__TERMINAL_IMAGE_H */

View File

@ -10,10 +10,6 @@
#include <fcntl.h>
#include <sys/stat.h>
#ifdef CONFIG_GZIP
#include <zlib.h>
#endif
#include "elinks.h"
#include "document/document.h"
@ -26,46 +22,6 @@
#include "util/base64.h"
#include "util/memory.h"
#define STB_IMAGE_IMPLEMENTATION
#include "terminal/stb_image.h"
unsigned char *
el_kitty_get_image(char *data, int length, int *outlen, int *width, int *height, int *compressed)
{
ELOG
int comp;
unsigned char *pixels = stbi_load_from_memory((unsigned char *)data, length, width, height, &comp, KITTY_BYTES_PER_PIXEL);
unsigned char *b64;
if (!pixels) {
return NULL;
}
int size = *width * *height * KITTY_BYTES_PER_PIXEL;
*compressed = 0;
#ifdef CONFIG_GZIP
unsigned char *complace = (unsigned char *)mem_alloc(size);
if (complace) {
unsigned long compsize = size;
int res = compress(complace, &compsize, pixels, size);
if (res == Z_OK) {
*compressed = 1;
b64 = base64_encode_bin(complace, compsize, outlen);
stbi_image_free(pixels);
mem_free(complace);
return b64;
}
mem_free(complace);
}
#endif
b64 = base64_encode_bin(pixels, size, outlen);
stbi_image_free(pixels);
return b64;
}
int
add_kitty_image_to_document(struct document *doc, char *data, int datalen, int lineno, struct k_image **imagine, int width, int height)
{

View File

@ -10,4 +10,4 @@ endif
if conf_data.get('CONFIG_TERMINFO')
srcs += files('terminfo.c')
endif
srcs += files('color.c', 'draw.c', 'event.c', 'hardio.c', 'kbd.c', 'screen.c', 'tab.c', 'terminal.c', 'window.c')
srcs += files('color.c', 'draw.c', 'event.c', 'hardio.c', 'image.c', 'kbd.c', 'screen.c', 'tab.c', 'terminal.c', 'window.c')

View File

@ -27,11 +27,6 @@
#include "config.h"
#endif
#ifdef HAVE_MEMFD_CREATE
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/mman.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -1055,76 +1050,3 @@ end:
return dest;
}
unsigned char *
el_sixel_get_image(char *data, int length, int *outlen)
{
ELOG
SIXELSTATUS status = SIXEL_FALSE;
sixel_encoder_t *encoder = NULL;
unsigned char *ret = NULL;
*outlen = 0;
#ifdef HAVE_MEMFD_CREATE
#ifdef CONFIG_MEMCOUNT
init_allocator();
status = sixel_encoder_new(&encoder, el_sixel_allocator);
#else
status = sixel_encoder_new(&encoder, NULL);
#endif
if (SIXEL_FAILED(status)) {
goto error;
}
int fdout = -1;
encoder->outfd = memfd_create("out.sixel", 0);
fdout = dup(encoder->outfd);
encoder->fstatic = 1;
int fdin = memfd_create("input.sixel", 0);
FILE *f = fdopen(fdin, "wb");
if (!f) {
goto error;
}
fwrite(data, 1, length, f);
rewind(f);
struct string name;
if (!init_string(&name)) {
goto error;
}
add_format_to_string(&name, "/proc/self/fd/%d", fdin);
status = sixel_encoder_encode(encoder, name.source);
done_string(&name);
if (SIXEL_FAILED(status)) {
goto error;
}
struct stat sb;
fstat(fdout, &sb);
if (sb.st_size > 0) {
ret = (unsigned char *)mem_alloc(sb.st_size);
if (ret) {
FILE *f2 = fdopen(fdout, "rb");
if (f2) {
rewind(f2);
*outlen = (int)fread(ret, 1, (size_t)sb.st_size, f2);
fclose(f2);
}
}
}
close(fdout);
error:
if (f) {
fclose(f);
}
sixel_encoder_unref(encoder);
#endif
return ret;
}

View File

@ -34,8 +34,6 @@ int add_image_to_document(struct document *doc, struct string *pixels, int linen
struct image *copy_frame(struct image *src, struct el_box *box, int cell_width, int cell_height, int dx, int dy);
unsigned char *el_sixel_get_image(char *data, int len, int *outlen);
#endif
#ifdef __cplusplus