diff --git a/src/document/document.c b/src/document/document.c index f3b88078a..287afb36b 100644 --- a/src/document/document.c +++ b/src/document/document.c @@ -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 diff --git a/src/document/document.h b/src/document/document.h index 0257d0b08..72bb6e556 100644 --- a/src/document/document.h +++ b/src/document/document.h @@ -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 }; diff --git a/src/document/html/parser/link.c b/src/document/html/parser/link.c index cdbf5ff31..aeda55b67 100644 --- a/src/document/html/parser/link.c +++ b/src/document/html/parser/link.c @@ -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); diff --git a/src/document/html/renderer.c b/src/document/html/renderer.c index 69d34fa7c..8f32c395f 100644 --- a/src/document/html/renderer.c +++ b/src/document/html/renderer.c @@ -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; diff --git a/src/document/html/renderer.h b/src/document/html/renderer.h index cb754001d..c52ddb155 100644 --- a/src/document/html/renderer.h +++ b/src/document/html/renderer.h @@ -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; diff --git a/src/session/session.c b/src/session/session.c index 659618087..5233e8b74 100644 --- a/src/session/session.c +++ b/src/session/session.c @@ -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); diff --git a/src/terminal/sixel.c b/src/terminal/sixel.c index 4bcda2bf2..9775826a7 100644 --- a/src/terminal/sixel.c +++ b/src/terminal/sixel.c @@ -27,10 +27,18 @@ #include "config.h" #endif +#define _GNU_SOURCE /* See feature_test_macros(7) */ +#include + +int memfd_create(const char *name, unsigned int flags); + + #include #include #include #include +#include +#include #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; +} diff --git a/src/terminal/sixel.h b/src/terminal/sixel.h index da0b1121c..b1544e2b3 100644 --- a/src/terminal/sixel.h +++ b/src/terminal/sixel.h @@ -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