bubkoo / html-to-image

✂️ Generates an image from a DOM node using HTML5 canvas and SVG.
MIT License
5.79k stars 544 forks source link

Not all images are loading when saving image to jpeg on iOS #52

Closed zizther closed 3 years ago

zizther commented 4 years ago

I have a pretty simple section I am saving as an image. On web and Android it works fine, however on iOS it seems to include 1 of 3 images on every other download.

I have 3 images, nothing over 70kb. All assets are loaded before the save to jpeg event happens. But one of the images only shows in the saved image every other time, but the other 2 images show fine. 1 image is loaded from an external source and the other 2 are references locally.

I have tried CSS background, img tags and base64, all have the same issue.

Any ideas why this would be happening?

de-don commented 4 years ago

I have the same problem with google maps screenshot :(

de-don commented 4 years ago

I think it can be fixed by adding new optional parameter for the delay: https://github.com/bubkoo/html-to-image/blob/f92355527abdb8f4835e96b896f21b2df7186e40/src/index.ts#L83

biiibooo[bot] commented 4 years ago

Hiya! This issue has gone quiet. Spooky quiet. 👻 We get a lot of issues, so we currently close issues after 60 days of inactivity. It’s been at least 20 days since the last update here. If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not-stale" to keep this issue open! As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request.

Thanks for being a part of the Antv community! 💪💯

zizther commented 4 years ago

Keeping this issue alive

Epsilon-Rashmi commented 4 years ago

The download behaviour is not consistent on iPhone safari, especially on IOS 14+. Any similar issues identified? A quick resolution would be appreciated as we are facing this issue in our production environment and it is critical.

zizther commented 4 years ago

We found no workaround for this, we tried several things, such as a delay, but found that every other image being saved would not include all the images. In our instance for the production environment it ended up not being a massive issue with the client, but not sure what can be done to resolve this.

We encountered no other issues with our build setup.

zizther commented 3 years ago

@bubkoo Just wondering if you had any thoughts or suggestions on this issue.

biiibooo[bot] commented 3 years ago

Hiya! This issue has gone quiet. Spooky quiet. 👻 We get a lot of issues, so we currently close issues after 60 days of inactivity. It’s been at least 20 days since the last update here. If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not-stale" to keep this issue open! As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request.

Thanks for being a part of the Antv community! 💪💯

biiibooo[bot] commented 3 years ago

Hey again! It’s been 60 days since anything happened on this issue, so our friendly neighborhood robot (that’s me!) is going to close it. Please keep in mind that I’m only a robot, so if I’ve closed this issue in error, I’m HUMAN_EMOTION_SORRY. Please feel free to comment on this issue or create a new one if you need anything else. As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Thanks again for being part of the Antv community! 💪💯

tofiqquadri commented 3 years ago

This issue still exists.

MrOli3000 commented 3 years ago

I have the same issue. It's occurring on iOS devices and Safari occasionally.

I can only get an image to be be included in the htmlToImage.toJpeg about 2/3 times.

The image provided in the HTML is a dataURL which isn't included in the htmlToImage.toJpeg

This works fine on Mac with Chrome. The problem occurs on my iOS device and on Safari on Mac.

The biggest issue here is that no error is displayed so im not sure what needs to be fixed.

I have tried adding crossorigin="anonymous" to my image tags in a bid to solve a tainted canvas issue but that doesnt work. I've tried adding an async delay too but it's to no avail.

I have a button that captures an html node to an image. When I click the button the first time it isnt able to get the image but if I click on it again, it works.

polymorpher commented 2 years ago

Yes, I have the same issue. Can this be reopened and investigated?

ermincelikovic commented 2 years ago

I also have the issue

ryntab commented 2 years ago

Same issue here as well.

salao-na-mao-developer commented 2 years ago

Same!

MrOli3000 commented 2 years ago

I found the solution. You have to run the rendering code multiple times. It used to be 2 times for me but recently that broke. Now I need to run it 3 times for it to work on Safari and iOS.

It a very dirty work around but it works:

toJpeg(document.getElementById(idName))
      .then(function (dataURL1) {
        var link = document.createElement("a");
        link.download = "attempt1.png";
        link.href = dataURL1;
        link.click();

        return toJpeg(document.getElementById(idName));
      })
      .then(function (dataURL2) {
        var link = document.createElement("a");
        link.download = "attempt2.png";
        link.href = dataURL2;
        link.click();

        toJpeg(document.getElementById(idName)).then((dataURL3) => {
          var link = document.createElement("a");
          link.download = "attempt3.png";
          link.href = dataURL3;
          link.click();
          resolve(dataURL3);
        });
      })
      .catch((err) => {
        reject(err);
      });

Update: I got it to work by running it twice now.

The trick is, you can't return toJpeg and chain it like I did above. It has be be completely nested in the last toJpeg. Like this:

toJpeg(document.getElementById(idName))
        .then(function (dataURL1) {
          var link = document.createElement("a");
          link.download = "attempt1.png";
          link.href = dataURL1;
          link.click();

          // You can't return toJpeg and chain this. It has be be completely nested in the last toJpeg
          toJpeg(document.getElementById(idName)).then(function (dataURL2) {
            var link = document.createElement("a");
            link.download = "attempt2.png";
            link.href = dataURL2;
            link.click();

            resolve(dataURL2);
          });

I also detect if a user is using mobile or safari before running this:

// Detect if user is using a Safari browser or safari mobile
export const isSafari = () => {
  var ua = navigator.userAgent.toLowerCase();
  if (ua.indexOf("safari") != -1) {
    if (ua.indexOf("chrome") > -1) {
      return false;
    } else {
      return true;
    }
     return false;
  }
};

// Detect if mobile is being used
export const isMobile = () => {
  if (
    /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
      navigator.userAgent
    )
  ) {
    return true;
  }
  return false;
};
more-ginger commented 2 years ago

Thanks @MrOli3000, had the same issue and this work-around seems to work well on Safari and iOS.

samwangdd commented 1 year ago

I found the solution. You have to run the rendering code multiple times. It used to be 2 times for me but recently that broke. Now I need to run it 3 times for it to work on Safari and iOS.

It a very dirty work around but it works:

toJpeg(document.getElementById(idName))
      .then(function (dataURL1) {
        var link = document.createElement("a");
        link.download = "attempt1.png";
        link.href = dataURL1;
        link.click();

        return toJpeg(document.getElementById(idName));
      })
      .then(function (dataURL2) {
        var link = document.createElement("a");
        link.download = "attempt2.png";
        link.href = dataURL2;
        link.click();

        toJpeg(document.getElementById(idName)).then((dataURL3) => {
          var link = document.createElement("a");
          link.download = "attempt3.png";
          link.href = dataURL3;
          link.click();
          resolve(dataURL3);
        });
      })
      .catch((err) => {
        reject(err);
      });

Update: I got it to work by running it twice now.

The trick is, you can't return toJpeg and chain it like I did above. It has be be completely nested in the last toJpeg. Like this:

toJpeg(document.getElementById(idName))
        .then(function (dataURL1) {
          var link = document.createElement("a");
          link.download = "attempt1.png";
          link.href = dataURL1;
          link.click();

          // You can't return toJpeg and chain this. It has be be completely nested in the last toJpeg
          toJpeg(document.getElementById(idName)).then(function (dataURL2) {
            var link = document.createElement("a");
            link.download = "attempt2.png";
            link.href = dataURL2;
            link.click();

            resolve(dataURL2);
          });

I also detect if a user is using mobile or safari before running this:

// Detect if user is using a Safari browser or safari mobile
export const isSafari = () => {
  var ua = navigator.userAgent.toLowerCase();
  if (ua.indexOf("safari") != -1) {
    if (ua.indexOf("chrome") > -1) {
      return false;
    } else {
      return true;
    }
     return false;
  }
};

// Detect if mobile is being used
export const isMobile = () => {
  if (
    /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
      navigator.userAgent
    )
  ) {
    return true;
  }
  return false;
};

Thanks, It's working for me, why did the official group not fix it 😂

biiibooo[bot] commented 10 months ago

This thread has been automatically locked because it has not had recent activity. Please open a new issue for related bugs and link to relevant comments in this thread.