Sasikanth
Sasikanth

Reputation: 3043

Cropping Image inside promises using canvas not working

I'm trying to crop multiple images using canvas and I want to run some other function after I'm done with cropping all the images.

This is my promise function to crop images

const checkImage = url => {
  return new Promise(resolve => {
    const workingURL = url;
    const canvas = document.createElement('canvas');
    canvas.width = 200;
    canvas.height = 200;
    const ctx = canvas.getContext('2d');  
    img = new Image();
    img.setAttribute('crossOrigin', '');
    img.onload = function(){
      var w = img.width;
      var h = img.height;

      var rw = 200;
      var rh = 200;

      if (w > h) {
        var ar = (w / h).toFixed(2);
        var dar = (200/h);
        rw = Math.floor(w * dar);
      } else if (h > w) {
        var ar = (h / w).toFixed(2);
        var dar = (200/w);
        rh = Math.floor(h * dar);
      }

      var sx = 200 / 2 - rw / 2;
      var sy = 200 / 2 - rh / 2;
      console.log(sx, sy, rw, rh);
      console.log(img);
      ctx.drawImage(img,sx,sy, rw , rh);
      var s = canvas.toDataURL();
      console.log('done cropping ', url, s);
      resolve({url: workingURL, res: s});
    }
    img.onerror = (err) => {
      console.log('onload error ',err);
      resolve({url: workingURL, res: false});
    };
    img.src = url;
  });
}

now I have couple of images need to be called, so I'm calling promise with each image

cropImageForGIFFn = () => {
  const needCropImgs = [
    {
      "src": "https://s3.amazonaws.com/tech-turing/event-images/ydgPwb28ThtgeATC8/img-Hrc7otKvJZTg6D5Rp.png",
    },
    {
      "src": "https://s3.amazonaws.com/tech-turing/event-images/ydgPwb28ThtgeATC8/img-ZAnRMDHfAGz2Xe9oX.png",
    },
  ];
  const needCropImgsLen = needCropImgs.length;
  let resolvedPromises = 0;

  needCropImgs.forEach(function (imgInfo) {      
    checkImage(imgInfo.src).then((info) => {
      console.log('promise resolved');
      console.log(info);

      resolvedPromises += 1;
      if (resolvedPromises === 1) {
        document.getElementById('img1').src = info.res;
      }

       if (resolvedPromises === 2) {
        document.getElementById('img2').src = info.res;
      }
      console.log({resolvedPromises});
      if (resolvedPromises >= needCropImgsLen) {
        console.log('all are resolved');
      }
    });
  });
};

I'm checking all promises are resolved or not and then calling some other function.

If I send multiple images to my promises function, first image is coming as transparent if I send only one image then everything working fine.

If I comment any of the images then cropping works fine.

I created Codepen here https://codepen.io/sasikanth1/pen/rQjxXL

try commenting one of the array values of needCropImgs then image will be displayed fine.

Upvotes: 0

Views: 98

Answers (1)

Kaiido
Kaiido

Reputation: 136707

Typo,
You forgot a const or let or var before img declaration.

   img = new Image();
 // ^- scope leak

This means your img variable in all the async callbacks will refer to the latest declared Image(). This could indeed lead to some transparent result if the last image didn't load before the other ones.

So simply add this keyword and you'll be fine.

Upvotes: 1

Related Questions