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.

machine.png

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();
});