Gitweb links:

...log 
http://git.netsurf-browser.org/netsurf.git/shortlog/9d5ebb857caa8561972f0c2395e2176ce2b03146
...commit 
http://git.netsurf-browser.org/netsurf.git/commit/9d5ebb857caa8561972f0c2395e2176ce2b03146
...tree 
http://git.netsurf-browser.org/netsurf.git/tree/9d5ebb857caa8561972f0c2395e2176ce2b03146

The branch, vince/libjxl has been created
        at  9d5ebb857caa8561972f0c2395e2176ce2b03146 (commit)

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/netsurf.git/commit/?id=9d5ebb857caa8561972f0c2395e2176ce2b03146
commit 9d5ebb857caa8561972f0c2395e2176ce2b03146
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    Implement simple jpeg xl image handler

diff --git a/Makefile b/Makefile
index 828f83b..05cb03e 100644
--- a/Makefile
+++ b/Makefile
@@ -171,6 +171,7 @@ endif
 $(eval $(call pkg_config_find_and_add_enabled,OPENSSL,openssl,OpenSSL))
 
 $(eval $(call pkg_config_find_and_add_enabled,UTF8PROC,libutf8proc,utf8))
+$(eval $(call pkg_config_find_and_add_enabled,JPEGXL,libjxl,JPEGXL))
 $(eval $(call pkg_config_find_and_add_enabled,WEBP,libwebp,WEBP))
 $(eval $(call pkg_config_find_and_add_enabled,PNG,libpng,PNG))
 $(eval $(call pkg_config_find_and_add_enabled,BMP,libnsbmp,BMP))
diff --git a/content/handlers/image/Makefile b/content/handlers/image/Makefile
index afc90f4..ac052b3 100644
--- a/content/handlers/image/Makefile
+++ b/content/handlers/image/Makefile
@@ -7,6 +7,7 @@ S_IMAGE_$(NETSURF_USE_BMP) += bmp.c
 S_IMAGE_$(NETSURF_USE_GIF) += gif.c
 S_IMAGE_$(NETSURF_USE_BMP) += ico.c
 S_IMAGE_$(NETSURF_USE_JPEG) += jpeg.c
+S_IMAGE_$(NETSURF_USE_JPEGXL) += jpegxl.c
 S_IMAGE_$(NETSURF_USE_ROSPRITE) += nssprite.c
 S_IMAGE_$(NETSURF_USE_PNG) += png.c
 S_IMAGE_$(NETSURF_USE_NSSVG) += svg.c
diff --git a/content/handlers/image/image.c b/content/handlers/image/image.c
index 3107ee4..2bd5f5f 100644
--- a/content/handlers/image/image.c
+++ b/content/handlers/image/image.c
@@ -32,6 +32,7 @@
 #include "image/gif.h"
 #include "image/ico.h"
 #include "image/jpeg.h"
+#include "image/jpegxl.h"
 #include "image/nssprite.h"
 #include "image/png.h"
 #include "image/rsvg.h"
@@ -72,6 +73,12 @@ nserror image_init(void)
                return error;
 #endif
 
+#ifdef WITH_JPEGXL
+       error = nsjpegxl_init();
+       if (error != NSERROR_OK)
+               return error;
+#endif
+
 #ifdef WITH_PNG
        error = nspng_init();
        if (error != NSERROR_OK)
diff --git a/content/handlers/image/jpegxl.c b/content/handlers/image/jpegxl.c
new file mode 100644
index 0000000..4bba02d
--- /dev/null
+++ b/content/handlers/image/jpegxl.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2023 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * implementation of content handling for image/jpegxl
+ *
+ * This implementation uses the JXL library.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <string.h>
+
+#include <jxl/decode.h>
+
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "netsurf/bitmap.h"
+#include "content/llcache.h"
+#include "content/content.h"
+#include "content/content_protected.h"
+#include "content/content_factory.h"
+#include "desktop/gui_internal.h"
+#include "desktop/bitmap.h"
+
+#include "image/image_cache.h"
+
+#include "image/jpegxl.h"
+
+
+/**
+ * output image format
+ */
+static const JxlPixelFormat jxl_output_format = {4, JXL_TYPE_UINT8, 
JXL_LITTLE_ENDIAN, 0};
+
+/**
+ * Content create entry point.
+ */
+static nserror
+nsjpegxl_create(const content_handler *handler,
+               lwc_string *imime_type, const struct http_parameter *params,
+               llcache_handle *llcache, const char *fallback_charset,
+               bool quirks, struct content **c)
+{
+       struct content *jpeg;
+       nserror error;
+
+       jpeg = calloc(1, sizeof(struct content));
+       if (jpeg == NULL)
+               return NSERROR_NOMEM;
+
+       error = content__init(jpeg, handler, imime_type, params,
+                             llcache, fallback_charset, quirks);
+       if (error != NSERROR_OK) {
+               free(jpeg);
+               return error;
+       }
+
+       *c = jpeg;
+
+       return NSERROR_OK;
+}
+
+static void image_out_callback(void *opaque, size_t x, size_t y, size_t 
num_pixels, const void *pixels)
+{
+       struct bitmap * bitmap = opaque;
+       uint8_t * output;
+
+       output = guit->bitmap->get_buffer(bitmap);
+       if (output != NULL) {
+               /* bitmap buffer available */
+               memcpy(output + (x*jxl_output_format.num_channels) + (y * 
guit->bitmap->get_rowstride(bitmap)),
+                      pixels,
+                      num_pixels*jxl_output_format.num_channels);
+       }
+}
+
+/**
+ * create a bitmap from jpeg xl content.
+ */
+static struct bitmap *
+jpegxl_cache_convert(struct content *c)
+{
+       struct bitmap * bitmap = NULL;
+       JxlDecoder *jxldec;
+       JxlDecoderStatus decstatus;
+       JxlBasicInfo binfo;
+       const uint8_t *src_data;
+       size_t src_size;
+
+       jxldec = JxlDecoderCreate(NULL);
+       if (jxldec == NULL) {
+               NSLOG(netsurf, ERROR, "Unable to allocate decoder");
+               return NULL;
+       }
+       decstatus= JxlDecoderSubscribeEvents(jxldec, JXL_DEC_FULL_IMAGE);
+       if (decstatus != JXL_DEC_SUCCESS) {
+               NSLOG(netsurf, ERROR, "Unable to subscribe");
+               return NULL;
+       }
+       src_data = content__get_source_data(c, &src_size);
+
+       decstatus = JxlDecoderSetInput(jxldec, src_data, src_size);
+       if (decstatus != JXL_DEC_SUCCESS) {
+               NSLOG(netsurf, ERROR, "unable to set input");
+               return NULL;
+       }
+
+       decstatus = JxlDecoderProcessInput(jxldec);
+       if (decstatus != JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
+               NSLOG(netsurf, ERROR,
+                     "expected status JXL_DEC_NEED_IMAGE_OUT_BUFFER(%d) got 
%d",
+                     JXL_DEC_NEED_IMAGE_OUT_BUFFER,
+                     decstatus);
+               JxlDecoderDestroy(jxldec);
+               return NULL;
+       }
+
+       decstatus = JxlDecoderGetBasicInfo(jxldec, &binfo);
+       if (decstatus != JXL_DEC_SUCCESS) {
+               NSLOG(netsurf, ERROR, "unable to get basic info 
status:%d",decstatus);
+               JxlDecoderDestroy(jxldec);
+               return NULL;
+       }
+
+       /* create bitmap with appropriate opacity */
+       if (binfo.alpha_bits > 0) {
+               bitmap = guit->bitmap->create(c->width, c->height, 
BITMAP_OPAQUE);
+       } else {
+               bitmap = guit->bitmap->create(c->width, c->height, BITMAP_NONE);
+       }
+       if (bitmap == NULL) {
+               /* empty bitmap could not be created */
+               JxlDecoderDestroy(jxldec);
+               return NULL;
+       }
+
+       /* ensure buffer was allocated */
+       if (guit->bitmap->get_buffer(bitmap) == NULL) {
+               /* bitmap with no buffer available */
+               guit->bitmap->destroy(bitmap);
+               JxlDecoderDestroy(jxldec);
+               return NULL;
+       }
+
+       decstatus = JxlDecoderSetImageOutCallback(jxldec, &jxl_output_format, 
image_out_callback, bitmap);
+       if (decstatus != JXL_DEC_SUCCESS) {
+               NSLOG(netsurf, ERROR, "unable to set output buffer callback 
status:%d",decstatus);
+               guit->bitmap->destroy(bitmap);
+               JxlDecoderDestroy(jxldec);
+               return NULL;
+       }
+
+       decstatus = JxlDecoderProcessInput(jxldec);
+       if (decstatus != JXL_DEC_FULL_IMAGE) {
+               NSLOG(netsurf, ERROR, "did not get decode event");
+               guit->bitmap->destroy(bitmap);
+               JxlDecoderDestroy(jxldec);
+               return NULL;
+       }
+       
+       JxlDecoderDestroy(jxldec);
+
+       guit->bitmap->modified(bitmap);
+               
+       return bitmap;
+}
+
+/**
+ * report failiure
+ */
+static bool jxl_report_fail(struct content *c, JxlDecoderStatus decstatus, 
const char *msg)
+{
+       union content_msg_data msg_data;
+       NSLOG(netsurf, ERROR, "%s decoder status:%d", msg, decstatus);
+       msg_data.errordata.errorcode = NSERROR_UNKNOWN;
+       msg_data.errordata.errormsg = msg;
+       content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
+       return false;
+}
+
+/**
+ * Convert a CONTENT_JPEGXL for display.
+ */
+static bool nsjpegxl_convert(struct content *c)
+{
+       JxlDecoder *jxldec;
+       JxlSignature decsig;
+       JxlDecoderStatus decstatus = JXL_DEC_ERROR;
+       JxlBasicInfo binfo;
+       union content_msg_data msg_data;
+       const uint8_t *data;
+       size_t size;
+       char *title;
+       size_t image_size;
+
+       /* check image header is valid and get width/height */
+       data = content__get_source_data(c, &size);
+
+       decsig = JxlSignatureCheck(data,size);
+       if ((decsig != JXL_SIG_CODESTREAM) && (decsig != JXL_SIG_CONTAINER)) {
+               NSLOG(netsurf, ERROR, "signature failed");
+               msg_data.errordata.errorcode = NSERROR_UNKNOWN;
+               msg_data.errordata.errormsg = "Signature failed";
+               content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
+               return false;
+       }
+
+       jxldec = JxlDecoderCreate(NULL);
+       if (jxldec == NULL) {
+               return jxl_report_fail(c, decstatus, "Unable to allocate 
decoder");
+       }
+       decstatus= JxlDecoderSubscribeEvents(jxldec, JXL_DEC_BASIC_INFO);
+       if (decstatus != JXL_DEC_SUCCESS) {
+               return jxl_report_fail(c, decstatus, "Unable to subscribe");
+       }
+       decstatus = JxlDecoderSetInput(jxldec, data,size);
+       if (decstatus != JXL_DEC_SUCCESS) {
+               return jxl_report_fail(c, decstatus, "unable to set input");
+       }
+       decstatus = JxlDecoderProcessInput(jxldec);
+       if (decstatus != JXL_DEC_BASIC_INFO) {
+               return jxl_report_fail(c, decstatus, "did not get basic info 
event");
+       }
+       decstatus = JxlDecoderGetBasicInfo(jxldec, &binfo);
+       if (decstatus != JXL_DEC_SUCCESS) {
+               return jxl_report_fail(c, decstatus, "unable to get basic 
info");
+       }
+       decstatus = JxlDecoderImageOutBufferSize(jxldec, &jxl_output_format, 
&image_size);
+       if (decstatus != JXL_DEC_SUCCESS) {
+               return jxl_report_fail(c, decstatus, "unable get image size");
+       }
+       
+       JxlDecoderDestroy(jxldec);
+
+       NSLOG(netsurf, INFO, "got basic info size:%ld x:%d y:%d", image_size, 
binfo.xsize, binfo.ysize);
+
+       c->width = binfo.xsize;
+       c->height = binfo.ysize;
+       c->size = image_size;
+
+       image_cache_add(c, NULL, jpegxl_cache_convert);
+
+       /* set title text */
+       title = messages_get_buff("JPEGXLTitle",
+                       nsurl_access_leaf(llcache_handle_get_url(c->llcache)),
+                       c->width, c->height);
+       if (title != NULL) {
+               content__set_title(c, title);
+               free(title);
+       }
+
+       content_set_ready(c);
+       content_set_done(c);    
+       content_set_status(c, ""); /* Done: update status bar */
+
+       return true;
+}
+
+
+/**
+ * Clone content.
+ */
+static nserror nsjpegxl_clone(const struct content *old, struct content **newc)
+{
+       struct content *jpegxl_c;
+       nserror error;
+
+       jpegxl_c = calloc(1, sizeof(struct content));
+       if (jpegxl_c == NULL)
+               return NSERROR_NOMEM;
+
+       error = content__clone(old, jpegxl_c);
+       if (error != NSERROR_OK) {
+               content_destroy(jpegxl_c);
+               return error;
+       }
+
+       /* re-convert if the content is ready */
+       if ((old->status == CONTENT_STATUS_READY) ||
+           (old->status == CONTENT_STATUS_DONE)) {
+               if (nsjpegxl_convert(jpegxl_c) == false) {
+                       content_destroy(jpegxl_c);
+                       return NSERROR_CLONE_FAILED;
+               }
+       }
+
+       *newc = jpegxl_c;
+
+       return NSERROR_OK;
+}
+
+static const content_handler nsjpegxl_content_handler = {
+       .create = nsjpegxl_create,
+       .data_complete = nsjpegxl_convert,
+       .destroy = image_cache_destroy,
+       .redraw = image_cache_redraw,
+       .clone = nsjpegxl_clone,
+       .get_internal = image_cache_get_internal,
+       .type = image_cache_content_type,
+       .is_opaque = image_cache_is_opaque,
+       .no_share = false,
+};
+
+static const char *nsjpegxl_types[] = {
+       "image/jxl",
+};
+
+CONTENT_FACTORY_REGISTER_TYPES(nsjpegxl, nsjpegxl_types, 
nsjpegxl_content_handler);
diff --git a/content/handlers/image/jpegxl.h b/content/handlers/image/jpegxl.h
new file mode 100644
index 0000000..e37d934
--- /dev/null
+++ b/content/handlers/image/jpegxl.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 Vincent Sanders <[email protected]>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Content for image/jpegxl (interface).
+ */
+
+#ifndef _NETSURF_IMAGE_JPEGXL_H_
+#define _NETSURF_IMAGE_JPEGXL_H_
+
+nserror nsjpegxl_init(void);
+
+#endif
diff --git a/content/mimesniff.c b/content/mimesniff.c
index 9a11834..adc000d 100644
--- a/content/mimesniff.c
+++ b/content/mimesniff.c
@@ -260,6 +260,13 @@ static nserror mimesniff__match_unknown_exact(const 
uint8_t *data, size_t len,
                SIG(&corestring_lwc_application_x_gzip, "\x1f\x8b\x08", true),
                SIG(&corestring_lwc_application_postscript, "%!PS-Adobe-",true),
                SIG(&corestring_lwc_application_pdf, "%PDF-", false),
+               SIG(&corestring_lwc_image_jxl, "\xFF\x0A", true), /* 
containerless jpeg xl*/
+               {
+                       (const uint8_t *)"\x00\x00\x00\x0CJXL \x0D\x0A\x87\x0A",
+                       12,
+                       true,
+                       &corestring_lwc_image_jxl
+               }, /* containered jpeg xl*/
                { NULL, 0, false, NULL }
        };
 #undef SIG
@@ -376,6 +383,12 @@ static nserror mimesniff__compute_image(lwc_string 
*official_type,
                SIG(&corestring_lwc_image_jpeg, "\xff\xd8\xff"),
                SIG(&corestring_lwc_image_bmp, "BM"),
                SIG(&corestring_lwc_image_vnd_microsoft_icon, 
"\x00\x00\x01\x00"),
+               SIG(&corestring_lwc_image_jxl, "\xFF\x0A"), /* containerless 
jpeg xl*/
+               {
+                       (const uint8_t *)"\x00\x00\x00\x0CJXL \x0D\x0A\x87\x0A",
+                       12,
+                       &corestring_lwc_image_jxl
+               }, /* containered jpeg xl*/
                { NULL, 0, NULL }
        };
 #undef SIG
diff --git a/frontends/gtk/fetch.c b/frontends/gtk/fetch.c
index 58bd0b8..d77073a 100644
--- a/frontends/gtk/fetch.c
+++ b/frontends/gtk/fetch.c
@@ -75,6 +75,7 @@ void gtk_fetch_filetype_init(const char *mimefile)
        hash_add(mime_hash, "html", "text/html");
        hash_add(mime_hash, "jpg", "image/jpeg");
        hash_add(mime_hash, "jpeg", "image/jpeg");
+       hash_add(mime_hash, "jxl", "image/jxl");
        hash_add(mime_hash, "gif", "image/gif");
        hash_add(mime_hash, "png", "image/png");
        hash_add(mime_hash, "jng", "image/jng");
diff --git a/utils/corestringlist.h b/utils/corestringlist.h
index b253b3b..5cdbb3a 100644
--- a/utils/corestringlist.h
+++ b/utils/corestringlist.h
@@ -167,6 +167,7 @@ CORESTRING_LWC_VALUE(application_octet_stream, 
"application/octet-stream");
 CORESTRING_LWC_VALUE(image_gif, "image/gif");
 CORESTRING_LWC_VALUE(image_png, "image/png");
 CORESTRING_LWC_VALUE(image_jpeg, "image/jpeg");
+CORESTRING_LWC_VALUE(image_jxl, "image/jxl");
 CORESTRING_LWC_VALUE(image_bmp, "image/bmp");
 CORESTRING_LWC_VALUE(image_vnd_microsoft_icon, "image/vnd.microsoft.icon");
 CORESTRING_LWC_VALUE(image_webp, "image/webp");


-----------------------------------------------------------------------


-- 
NetSurf Browser
_______________________________________________
netsurf-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to