This folder contains an example how to decode JPEG XL files on a web page using WASM engine.
The simplest way to get support of JXL images on the client side is simply to
link one extra script (<script src="service_worker.js">) to the page.
This script installs a ServiceWorker that:
- checks if the browser supports the JXL image format already
- if it is not, then advertise
image/jxlas media format in image requests - then, if the server responds with
image/jxlcontent it gets decoded and re-encoded to PNG on the fly
Generally the message / data flow looks the following way:
Fetch APIreceives a resource request from client page (e.g. when the HTML engine discovers animgtag) and asks theServiceWorkerhow to proceed- the
ServiceWorkeralters the request and uses theFetch APIto obtain data - when data arrives, the
ServiceWorkerforwards it to the "client" (the page) that initiated the resource request - the client forwards the data to a worker (see
client_worker.js) to avoid processing in the "main loop" thread - a worker does the actual decoding; to make it faster several additional workers are spawned (to enable multi-threading in WASM module); the decoded image is wrapped in non-compressed PNG format and sent back to client
- the client relays image data to
ServiceWorker - the
ServiceWorkerpasses data toFetch APIas a response to initial resource request
Despite the additional "hop" (client) in the flow, data is not copied every time but rather "transferred" between the participants.
Demo page: one_line_demo.html. Extended demo, that also shows how long it
took do decode images: one_line_demo_with_console.html.
Page that shows "manual" decoding (and has benchmarking capabilities):
manual_decode_demo.html.
To enable multi-threading some files should be served in a secure context (i.e. transferred over HTTPS) and executed in a "site-isolation" mode (controlled by COOP and COEP response headers).
Unfortunately GitHub Pages does not allow setting response headers.
Netlify provides free, easy to setup and deploy platform for serving such demonstration sites. However, any other service provider / software that allows changing response headers could be employed as well.
netlify.toml and netlify/precompressed.ts specify the serving rules.
Namely, some requests get "upgraded" responses:
- if a request specifies that
brotlicompression is supported, then precompressed entries are sent - if a request specifies that
image/jxlformat is allowed, then entries transcoded to JXL format are sent
build_site.py script takes care of JavaScript minification, template
substitution and resource compression. Its arguments are:
- source path: site template directory (that contains this README file)
- binary path: build directory, that contains compiled WASM module
- output path
To complete the site few more files are to be added to output directory:
image00.jpg,image01.pngdemo images; will be shown ifServiceWorkeris not yet operable (fallback); to see those one could initiate "hard page reload" (press Shift-(Ctrl|Cmd)-R)image00.jpg.jxl,image01.png.jxldemo images in JXL formatimageNN.jxlimages for "manual" decoding demo; NN is a number starting form00favicon.icois an optional site iconindex.htmlis an optional site "home" page
In the source code (service_worker.js) there are two compile-time constants
that modify the behaviour of Service Worker:
FORCE_COPflag allows rewriting responses to add COOP / COEP headers; this is useful when it is difficult / impossible to setup response headers otherwise (e.g. GitHub Pages)FORCE_DECODINGflag activate JXL decoding when image response type hasContent-Encodingheader set toapplication/octet-stream; this happens when server does not know the JXL MIME-type
One dependency that build_site.py requires is uglifyjs, which can be installed with
npm install uglify-js -g
If you followed the wasm build instructions, assuming you are in the root level of the cloned libjxl repo a typical call to build the site would be
python3 ./tools/wasm_demo/build_site.py ./tools/wasm_demo/ ./build-wasm32/tools/wasm_demo/ /path/to/demo-siteThen you need to put your image files in the correct same place and are should be good to go.
To summarize, using the wasm decoder together with a service workder amounts to adding
<script src="service_worker.js"></script>to your html and then putting the service_worker.js and jxl_decoder.wasm binary in directory where they can be read.
It is not guaranteed, but somewhat fresh demo is hosted on
https://jxl-demo.netlify.app/, e.g.:
- one line demo
- one line demo with console
- manual decode demo;
URL contains query parameters that control rendering and benchmarking options;
please note, that HDR canvas is often not enabled by default, it could be
enabled in some browsers via
about://flags/#enable-experimental-web-platform-features service_worker.jsjxl_decoder.wasm