Search code examples
javascriptfilereaderfigma

Selecting Multiple Images and storing them in a data array (FIGMA)


I am building a plugin for FIGMA, where the user selects multiple images, which I then save in an array, that I send to be interpreted.

I have 2 issues with my code

  • img.src = bin; does not trigger img.onload, but if I set img.src = "literal string", the onload method workds.
  • the imageData array sent at the end is undefined, I assume because of my bad understanding of async functions.

I would appreciate your help figuring this out. Thank you P.S. this is pure javascript, and you don't need to know FIGMA to follow the code.

<input type="file" id="images" accept="image/png" multiple />
<button id="button">Create image</button>

<script>
    const button = document.getElementById('button');

    button.onclick = () => {
        const files = document.getElementById('images').files;      
        
        function readFile(index) {
            console.log(1);
            if (index >= files.length) {return};
            console.log(2);

            const file = files[index];
            const imageCaption = file.name;

            var reader = new FileReader();
            reader.readAsArrayBuffer(file);
            reader.onload = function (e) {
                console.log(4);
                // get file content  
                const bin = e.target.result;
                const imageBytes = new Uint8Array(bin);

                //Get Image width and height
                var img = new Image();
                img.src = bin;
                img.onload = function () {
                    console.log(6);
                    const width = img.width;
                    const height = img.height;  
                    
                    console.log("imageCaption: " + imageCaption);
                    console.log("width: " + width);
                    console.log("height: " + height);
                    console.log("imageBytes: " + imageBytes);

                    var data = {imageBytes, imageCaption, width, height};

                    //Read Next File
                    nextData = readFile(index + 1);
                    if( nextData ) {
                        data.concat(nextData)
                    }
                    return data;
                }
            }
        }

        //Call function to Read and Send Images
        const imageData = readFile(0);

        //Send Data
        parent.postMessage({
            pluginMessage: {
                type: 'send-image',
                imageData,
            }
        }, '*');

Solution

  • A friend ended up helping me with it. Thank you Hiba!

    const button = document.getElementById('button');
    const input = document.getElementById('input');
    
    button.addEventListener('click', async () => {
        const files = input.files ? [...input.files] : [];
    
        const data = await Promise.all(
            files.map(async (file) => await getImageData(file))
        );
    
        console.log(data);
    });
    
    async function getImageData(file) {
        // get binary data from file
        const bin = await file.arrayBuffer();
    
        // translate bin data into bytes
        const imageBytes = new Uint8Array(bin)
    
        // create data blob from bytes
        const blob = new Blob([imageBytes], { type: "image/png" });
    
        // create html image element and assign blob as src
        const img = new Image();
        img.src = URL.createObjectURL(blob);
    
        // get width and height from rendered image
        await img.decode();
        const { width, height } = img;
    
        const data = { image: blob, caption: file.name, width, height };
    
        return data;
    }