Convert images to mask
Lately, I've been thinking to make this website more appealing and what I would like is use some images of patents or inventions to attach the word of Ideabile next to it, with a small vocabulary definition.
Usually, I would use photoshop for this kind of image manipulation and to be fair I still consider it the best option.
I do believe there is a wide range of options nowadays that WebGL is here and we've Webassembly at our service.
So I want to create a simple way to do the same but with open tools, so at my service, I will use imagemagic
and some canvas
.
So let's start!
The first problem to solve is how to get the dependency working.
Let's install this with npm
.
npm install -S wasm-imagemagick
If you meant to use this package from node
there would be fewer issues in running wasm
, if you want then run this code from the browser, you must consider some way to public expose magick.wasm
.
In documentation they specified this as a step:
cp ../../node_modules/wasm-imagemagick/dist/magick.js ../../dist/ cp ../../node_modules/wasm-imagemagick/dist/magick.wasm ../../dist/
I would rather use the unpkg
version for this small demo, seems to have less issues 🤷.
Now we have some sort of superpower so let's see what we can do.
I want to start with an image.
Rare Book Division, The New York Public Library. "Arts et métiers. Plan, coupe et détails de la roue à pots ou machine à arroser." The New York Public Library Digital Collections. 1809 - 1828. http://digitalcollections.nypl.org/items/510d47e0-21b4-a3d9-e040-e00a18064a99
So the firs thing to do is read the image through javascript and convert it to the Uint8Array
.
const url = 'https://unpkg.com/wasm-imagemagick/dist/bundles/magickApi.js'; import(url).then(Magick => { async function fetchImage(url: string) { const image = await fetch(url, { headers: { 'Sec-Fetch-Dest': 'image' } }); return new Uint8Array(await image.arrayBuffer()) } async function getProcessedImage(url: string) { const image = document.createElement('img'); const processed = await Magick.Call([ await Magick.buildInputFile(url, 'in.png') ], [ //Let's initialise the image 'convert', 'in.png', '-bordercolor', 'white', '-border', '1x1', // Set Alpha to most of the image '-alpha', 'set', '-channel', 'RGBA', '-fuzz', '20%', // Fill the image with white '-fill', 'none', '-floodfill', '+0+0', 'white', // Clean and set transparent '-shave', '1x1', '-transparent', 'white', // Increase the saturation '-level', '30%', // Convert to grey '-modulate', '100,0', '-channel', 'RGBA', '-transparent', 'white', '-evaluate', 'Divide', '1.5', // Export 'out.png', ]); const processed_grey = await Magick.Call([ { name: 'in.png', content: processed[0]['buffer'] } ], [ 'convert', 'in.png', // Convert to grey '-modulate', '100,0', '-channel', 'RGB', '-threshold', '80%', '-channel', 'RGBA', '-transparent', 'white', 'out.png' ]); const firstImage = processed[0]; image.src = URL.createObjectURL(firstImage['blob']); return image; } async function init() { const img = document.querySelector('img[alt="machine.png"]').src const image = await getProcessedImage(img); document.getElementById('demo').appendChild(image); } init(); });