0

I'm looping through an array of image elements (from a local folder) and attaching them to a canvas and at the end I would like to save the canvas as an image but it is not being saved properly. The resulting image matches the dimensions of the canvas but it is just a blank transparent image.

If in test.js I don't save the canvas to an image and I instead use resolve(canvas) I can display it perfectly in index.html so I know that the canvas is being written properly.

There are also no error messages displayed in the Google Chrome console.

Test.js

class Test {
    constructor() {}

    createPoster(images) {
        return new Promise((resolve, reject) => {
            let canvas = document.createElement('canvas');
            let ctx = canvas.getContext('2d');

            let locX = 0;

            for (let i = 0, len = images.length; i < len; ++i) {
                let image = images[i];

                image.onload = () => {
                    ctx.drawImage(image, locX, 0);
                    locX += image.width;
                };
            }

            let poster = new Image();
            poster.crossOrigin = 'anonymous';

            poster.onload = () => {
                resolve(poster);
            };

            poster.src = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
        });
    }
}

Index.html

<script type="module">
    const Test = require('./test.js');

    let test = new Test();

    async function main() {
       // let images = Get array of image elements from another library.
        let poster = await test.createPoster(images).catch((err) => console.log(err));

        document.body.appendChild(poster); // Displays just a transparent image with the same dimensions as the canvas.
    }
</script>

Mr.Smithyyy
  • 2,157
  • 12
  • 49
  • 95
  • Not sure if `poster.src` is set as you are resolving the promise before. Have you tried switching `.onload` functionality to the bottom of your function? – Rodrigo Mata Jul 20 '18 at 16:12
  • @RodrigoMata I did that try that with no luck but according to [this answer](https://stackoverflow.com/questions/4773966/drawing-an-image-from-a-data-url-to-a-canvas) the `onload` should be before the `src`. – Mr.Smithyyy Jul 20 '18 at 16:16
  • You need to wait for all the `image.onload` to finish. `poster.onload` will fire quickly, but the images need to wait on the network. – Mark Jul 20 '18 at 16:33
  • @Mark How would that look though, seeing as the loop needs to finish to create the poster so I cant resolve from the `image.onload` – Mr.Smithyyy Jul 20 '18 at 16:42

1 Answers1

1

You need to check for all image loaded before you create your poster image.

createPoster(images) {
  return new Promise((resolve, reject) => {
    let canvas = document.createElement('canvas');
    let ctx = canvas.getContext('2d');

    let locX = 0;
    let imageLoaded = 0;

    for (let i = 0, len = images.length; i < len; ++i) {
      let image = images[i];

      image.onload = () => {
        ctx.drawImage(image, locX, 0);
        locX += image.width;
        imageLoaded++;
        if (imageLoaded == len) {
          let poster = new Image();
          poster.crossOrigin = 'anonymous';
          poster.onload = () => {
            resolve(poster);
          };
          poster.src = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
        }
      };

      // image.src = ..
    }

  });
}
Durga
  • 15,263
  • 2
  • 28
  • 52