README.md (5721B)
1 ## WebAssembly demonstration 2 3 This folder contains an example how to decode JPEG XL files on a web page using 4 WASM engine. 5 6 ### One line demo 7 8 The simplest way to get support of JXL images on the client side is simply to 9 link one extra script (`<script src="service_worker.js">`) to the page. 10 This script installs a `ServiceWorker` that: 11 12 - checks if the browser supports the JXL image format already 13 - if it is not, then advertise `image/jxl` as media format in image requests 14 - then, if the server responds with `image/jxl` content it gets decoded and 15 re-encoded to PNG on the fly 16 17 Generally the message / data flow looks the following way: 18 19 - `Fetch API` receives a resource request from client page (e.g. when the HTML 20 engine discovers an `img` tag) and asks the `ServiceWorker` how to proceed 21 - the `ServiceWorker` alters the request and uses the `Fetch API` 22 to obtain data 23 - when data arrives, the `ServiceWorker` forwards it to the "client" 24 (the page) that initiated the resource request 25 - the client forwards the data to a worker (see `client_worker.js`) to avoid 26 processing in the "main loop" thread 27 - a worker does the actual decoding; to make it faster several additional 28 workers are spawned (to enable multi-threading in WASM module); 29 the decoded image is wrapped in non-compressed PNG format and sent back 30 to client 31 - the client relays image data to `ServiceWorker` 32 - the `ServiceWorker` passes data to `Fetch API` as a response to initial 33 resource request 34 35 Despite the additional "hop" (client) in the flow, data is not copied every 36 time but rather "transferred" between the participants. 37 38 Demo page: `one_line_demo.html`. Extended demo, that also shows how long it 39 took do decode images: `one_line_demo_with_console.html`. 40 41 Page that shows "manual" decoding (and has benchmarking capabilities): 42 `manual_decode_demo.html`. 43 44 ### Hosting 45 46 To enable multi-threading some files should be served in a secure context (i.e. 47 transferred over HTTPS) and executed in a "site-isolation" mode (controlled by 48 COOP and COEP response headers). 49 50 Unfortunately [GitHub Pages](https://pages.github.com/) does not allow setting 51 response headers. 52 53 [Netlify](https://www.netlify.com/) provides free, easy to setup and deploy 54 platform for serving such demonstration sites. However, any other 55 service provider / software that allows changing response headers could be 56 employed as well. 57 58 `netlify.toml` and `netlify/precompressed.ts` specify the serving rules. 59 Namely, some requests get "upgraded" responses: 60 61 - if a request specifies that `brotli` compression is supported, 62 then precompressed entries are sent 63 - if a request specifies that `image/jxl` format is allowed, 64 then entries transcoded to JXL format are sent 65 66 ### How to build the demo 67 68 `build_site.py` script takes care of JavaScript minification, template 69 substitution and resource compression. Its arguments are: 70 71 - source path: site template directory (that contains this README file) 72 - binary path: build directory, that contains compiled WASM module 73 - output path 74 75 To complete the site few more files are to be added to output directory: 76 77 - `image00.jpg`, `image01.png` demo images; will be shown if `ServiceWorker` 78 is not yet operable (fallback); to see those one could initiate 79 "hard page reload" (press Shift-(Ctrl|Cmd)-R) 80 - `image00.jpg.jxl`, `image01.png.jxl` demo images in JXL format 81 - `imageNN.jxl` images for "manual" decoding demo; NN is a number starting 82 form `00` 83 - `favicon.ico` is an optional site icon 84 - `index.html` is an optional site "home" page 85 86 In the source code (`service_worker.js`) there are two compile-time constants 87 that modify the behaviour of Service Worker: 88 89 - `FORCE_COP` flag allows rewriting responses to add COOP / COEP headers; 90 this is useful when it is difficult / impossible to setup response headers 91 otherwise (e.g. GitHub Pages) 92 - `FORCE_DECODING` flag activate JXL decoding when image response type has 93 `Content-Encoding` header set to `application/octet-stream`; this happens 94 when server does not know the JXL MIME-type 95 96 One dependency that `build_site.py` requires is [uglifyjs](https://github.com/mishoo/UglifyJS), which can be installed with 97 ``` 98 npm install uglify-js -g 99 ``` 100 If you followed the [wasm build instructions](../../docs/building_wasm.md), 101 assuming you are in the root level of the cloned libjxl repo a typical call to 102 build the site would be 103 ```bash 104 python3 ./tools/wasm_demo/build_site.py ./tools/wasm_demo/ ./build-wasm32/tools/wasm_demo/ /path/to/demo-site 105 ``` 106 Then you need to put your image files in the correct same place and are should be good to go. 107 108 109 To summarize, using the wasm decoder together with a service workder amounts to adding 110 ```html 111 <script src="service_worker.js"></script> 112 ``` 113 to your html and then putting the `service_worker.js` and `jxl_decoder.wasm` binary in directory where they can be read. 114 115 116 It is not guaranteed, but somewhat fresh demo is hosted on 117 `https://jxl-demo.netlify.app/`, e.g.: 118 119 - [one line demo](https://jxl-demo.netlify.app/one_line_demo_with_console.html) 120 - [one line demo with console](https://jxl-demo.netlify.app/one_line_demo.html) 121 - [manual decode demo](https://jxl-demo.netlify.app/manual_decode_demo.html?img=1&colorSpace=rec2100-pq&runBenchmark=30&wantSdr=false&displayNits=1500); 122 URL contains query parameters that control rendering and benchmarking options; 123 please note, that HDR canvas is often not enabled by default, it could be 124 enabled in some browsers via `about://flags/#enable-experimental-web-platform-features` 125 - [`service_worker.js`](https://jxl-demo.netlify.app/service_worker.js) 126 - [`jxl_decoder.wasm`](https://jxl-demo.netlify.app/jxl_decoder.wasm)