21

I am attempting to download a large canvas image (several thousand pixels height and width) on the click of a button using toBlob in the following code, which doesn't seem to work:

document.getElementById("download_button").onclick = function() {

  var link = document.createElement("a");
  link.download = "image.png";

  canvas.toBlob(function(blob){
    link.href = URL.createObjectURL(blob);
    console.log(blob);
  },'image/png');

  console.log(link.href);
  link.click();

}

console.log(blob) in the callback function returns: Blob {size: 64452, type: "image/png"}

But console.log(link.href) returns nothing.

Am I not using .createObjectURL correctly?

I used to work with toDataURL, but it stopped working above a certain canvas size. And this post canvas.toDataURL() download size limit suggested to try toBlob.

tvoirand
  • 347
  • 1
  • 3
  • 12

2 Answers2

27

Your code is fine.. just use it at the right time :)

 canvas.toBlob(function(blob){
    link.href = URL.createObjectURL(blob);
    console.log(blob);
    console.log(link.href); // this line should be here
  },'image/png');
ymz
  • 6,602
  • 1
  • 20
  • 39
  • 2
    Right, thanks ! It works correctly with `console.log(link.href);` and `link.click();` inside the callback function. – tvoirand Jun 15 '17 at 12:38
  • 1
    @ymz why is that though? I thought that would only be the case if .href was a custom property being added to the link element but it wasnt, yet the link element was defined in the event function scope too so should be accessible too or is it because it's nested within another function? – brandito Jul 18 '18 at 04:43
  • @ymz I just tried a little something to attempt to test it and this is what I get: `var link = document.createElement("a"); link.download = "image.png"; function test() { link.href = "#Test"; console.log(link.href); }` result: "image.png" – brandito Jul 18 '18 at 04:45
  • in addition, my first thought is that link.href shouldn't be accessible outside of that function or atleast, return "image.png" based on the above behavior strangely enough, yet link.href outside of the function scope gives an empty string. – brandito Jul 18 '18 at 04:46
13

My solution to the problem:

async function getImage({
  canvas,
  width,
  height,
  mime = 'image/jpeg',
  quality = 0.8,
}) {
  return new Promise(resolve => {
    const tmpCanvas = document.createElement('canvas');
    tmpCanvas.width = width;
    tmpCanvas.height = height;

    const ctx = tmpCanvas.getContext('2d');
    ctx.drawImage(
      canvas,
      0,
      0,
      canvas.width,
      canvas.height,
      0,
      0,
      width,
      height,
    );

    tmpCanvas.toBlob(resolve, mime, quality);
  });
}

const photo = await getImage({ canvas, width: 500, height: 500 });
s.meijer
  • 3,403
  • 3
  • 26
  • 23