Adding JPEG XL & QOI Support to my Website OS
Dustin Brett
Posted on December 30, 2022
I'm always having fun adding things to my desktop environment in the browser (daedalOS), which also powers my personal website dustinbrett.com where everything I show here can be tried out.
Recently I'd added TIFF support to my project via UTIF.js and now I decided I wanted to add JPEG XL & QOI.
JPEG XL Support (Sample Images)
For adding JPEG XL support I went with jxl.js which I modified for my use case. After looking through the main file, which is also called jxl.js, I decided I only needed 2 relevant code blocks. The one to decode the image and the one to turn the ImageData
into something I could display in my existing codebase (which I already partially had implemented for another use case).
To decode the image it creates a worker with jxl_dec.js, also I updated the path (hardcoded inside jxl_dec.js
) for jxl_dec.wasm to point to where I've stored it within my Next.js public
directory.
Then all that is needed is to run decodeJxl
with image data in Buffer
/Uint8Array
form. Once it returns ImageData
I use imgDataToBuffer
to convert it back into a Buffer
which I use for making thumbnails and displaying the picture in the Photos
app.
type JxlDecodeResponse = { data: { imgData: ImageData } };
export const decodeJxl = async (image: Buffer): Promise<ImageData> =>
new Promise((resolve) => {
const worker = new Worker("System/JXL.js/jxl_dec.js");
worker.postMessage({ image, jxlSrc: "image.jxl" });
worker.addEventListener("message", (message: JxlDecodeResponse) =>
resolve(message?.data?.imgData)
);
});
export const imgDataToBuffer = (imageData: ImageData): Buffer => {
const canvas = document.createElement("canvas");
canvas.width = imageData.width;
canvas.height = imageData.height;
canvas.getContext("2d")?.putImageData(imageData, 0, 0);
return Buffer.from(
canvas?.toDataURL("image/png").replace("data:image/png;base64,", ""),
"base64"
);
};
QOI Support (Sample Images)
When it came to adding QOI support, I used an open source "Gist" example that I basically didn't touch except to turn the qoi.js
file into a .ts
file so I could export a function which wrapped transcode_qoi_to_png
and exported it as a Buffer
for my use cases.
export const decodeQoi = (imgBuffer: Buffer): Buffer =>
Buffer.from(new Uint8Array(transcode_qoi_to_png(new Uint8Array(imgBuffer))));
Thanks! (@DustinBrett)
I hope you enjoyed my article about adding image formats to my desktop environment in the browser. If you're interested in more stuff about my side project which I have been working on for over 2 years, I recently did a video going over 2022's progress.
Please check it out and leave a comment/like if you enjoy it or have something to say.
Posted on December 30, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.