1
0
mirror of https://github.com/rkd77/elinks.git synced 2025-04-18 00:47:36 -04:00

[sixel] messy code to load sixel images

memfd_create is not portable, but I don't want
to modify libsixel code.
This commit is contained in:
Witold Filipczyk 2025-01-27 22:10:36 +01:00
parent 9809c60d1d
commit b718f8955e
8 changed files with 154 additions and 9 deletions

View File

@ -415,6 +415,7 @@ done_document(struct document *document)
while (!list_empty(document->images)) {
delete_image((struct image *)document->images.next);
}
free_uri_list(&document->image_uris);
#endif
#ifdef CONFIG_CSS

View File

@ -313,6 +313,7 @@ struct document {
enum clipboard_status clipboard_status;
#ifdef CONFIG_LIBSIXEL
LIST_OF(struct image) images;
struct uri_list image_uris;
#endif
};

View File

@ -26,6 +26,7 @@
#include "bfu/listmenu.h"
#include "bfu/menu.h"
#include "bookmarks/bookmarks.h"
#include "cache/cache.h"
#include "config/options.h"
#include "config/kbdbind.h"
#include "document/html/frames.h"
@ -235,25 +236,60 @@ html_img_sixel(struct html_context *html_context, char *a,
if (!html_context->options->sixel || !html_context->document) {
return;
}
unsigned char *data = NULL;
int datalen = 0;
char *elsix = get_attr_val(a, "elsix", html_context->doc_cp);
if (!elsix) {
return;
char *url = get_attr_val(a, "src", html_context->doc_cp);
if (!url) {
return;
}
char *url2 = join_urls(html_context->base_href, url);
if (url2) {
struct uri *uri = get_uri(url2, URI_BASE);
if (uri) {
struct cache_entry *cached = get_redirected_cache_entry(uri);
if (cached) {
struct fragment *fragment = get_cache_fragment(cached);
if (fragment) {
data = el_sixel_get_image(fragment->data, fragment->length);
}
}
if (!data) {
html_context->special_f(html_context, SP_IMAGE, uri);
}
done_uri(uri);
}
mem_free(url2);
}
mem_free(url);
if (data) {
datalen = strlen(data);
} else {
return;
}
}
struct string pixels;
if (!init_string(&pixels)) {
mem_free(elsix);
mem_free_if(elsix);
return;
}
int datalen;
unsigned char *data = base64_decode_bin((const unsigned char *)elsix, strlen(elsix), &datalen);
if (!datalen) {
data = base64_decode_bin((const unsigned char *)elsix, strlen(elsix), &datalen);
mem_free(elsix);
mem_free(elsix);
if (!data) {
done_string(&pixels);
return;
if (!data) {
done_string(&pixels);
return;
}
}
add_bytes_to_string(&pixels, (const char *)data, datalen);
mem_free(data);

View File

@ -2230,6 +2230,19 @@ html_special(struct html_context *html_context, html_special_type_T c, ...)
}
break;
}
case SP_IMAGE:
#ifdef CONFIG_LIBSIXEL
{
if (document) {
struct uri *uri = va_arg(l, struct uri *);
add_to_uri_list(&document->image_uris, uri);
}
}
#endif
break;
default:
break;

View File

@ -34,7 +34,8 @@ enum html_special_type {
SP_STYLESHEET,
SP_COLOR_LINK_LINES,
SP_SCRIPT,
SP_IFRAME
SP_IFRAME,
SP_IMAGE
};
typedef unsigned int html_special_type_T;

View File

@ -518,6 +518,24 @@ load_css_imports(struct session *ses, struct document_view *doc_view)
#define load_css_imports(ses, doc_view)
#endif
#ifdef CONFIG_LIBSIXEL
static void
load_images(struct session *ses, struct document_view *doc_view)
{
struct document *document = doc_view->document;
struct uri *uri;
int index;
if (!document) return;
foreach_uri (uri, index, &document->image_uris) {
request_additional_file(ses, "", uri, PRI_CSS);
}
}
#else
#define load_images(ses, doc_view)
#endif
#ifdef CONFIG_ECMASCRIPT
static inline void
load_ecmascript_imports(struct session *ses, struct document_view *doc_view)
@ -557,6 +575,7 @@ load_frames(struct session *ses, struct document_view *doc_view)
foreach (doc_view, ses->scrn_frames) {
load_css_imports(ses, doc_view);
load_ecmascript_imports(ses, doc_view);
load_images(ses, ses->doc_view);
}
}
@ -589,6 +608,7 @@ load_common(struct session *ses)
load_css_imports(ses, ses->doc_view);
load_ecmascript_imports(ses, ses->doc_view);
load_iframes(ses, ses->doc_view);
load_images(ses, ses->doc_view);
process_file_requests(ses);
}
@ -759,6 +779,7 @@ doc_loading_callback(struct download *download, struct session *ses)
load_frames(ses, ses->doc_view);
load_css_imports(ses, ses->doc_view);
load_ecmascript_imports(ses, ses->doc_view);
load_images(ses, ses->doc_view);
process_file_requests(ses);
start_document_refreshes(ses);

View File

@ -27,10 +27,18 @@
#include "config.h"
#endif
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sys/mman.h>
int memfd_create(const char *name, unsigned int flags);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sixel.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "elinks.h"
@ -1033,3 +1041,66 @@ end:
return dest;
}
unsigned char *
el_sixel_get_image(char *data, int length)
{
SIXELSTATUS status = SIXEL_FALSE;
sixel_encoder_t *encoder = NULL;
unsigned char *ret = NULL;
status = sixel_encoder_new(&encoder, NULL);
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);
fread(ret, 1, (size_t)sb.st_size, f2);
fclose(f2);
}
}
}
close(fdout);
error:
fclose(f);
end:
sixel_encoder_unref(encoder);
return ret;
}

View File

@ -34,6 +34,7 @@ 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);
#endif