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.
Top comments (2)
Great project. Looks like a lot of fun to work on.
Thanks very much! Ya it was important to me that the project I worked on would allow me to jump around to different things to keep learning and not get bored. This month has been adding image format support I guess.