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

SVG with image not working in Safari #214

Closed MartinPelijak closed 2 years ago

MartinPelijak commented 2 years ago

Hi, i am using your incredible library but i have a problem. I want to convert a SVG with an image inside into a png. In Firefox and Chrome everything works perfect, but in Safari the conversion is ignoring the image inside the SVG.

Here is a codepen (the face is the image) https://codepen.io/RainPara/pen/MWvqZNz

Environment: IPhone 11 with ios 15

biiibooo[bot] commented 2 years ago

👋 @MartinPelijak

Thanks for opening your first issue here! If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. To help make it easier for us to investigate your issue, please follow the contributing guidelines.

We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can.

biiibooo[bot] commented 2 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! 💪💯

imbarwinata commented 2 years ago

Same problem

GeekyADAMS commented 2 years ago

Apparently, the fix is to do a redundant chaining as it takes a little time for IOS to capture the whole data.

This worked for me:

setTimeout(() => {
    // ios/macos redundant painting
    htmlToImage.toJpeg(document.getElementById('template'), { quality: 1 })
    .then(() => {
      htmlToImage.toJpeg(document.getElementById('template'), { quality: 1 })
      .then(() => {
        htmlToImage.toJpeg(document.getElementById('template'), { quality: 1 })
        .then((dataUrl) => {
          const link = document.createElement('a');
          link.download = 'file-name.jpeg';
          link.href = dataUrl;
          link.click();
        })
      })
    })
    .catch((error) => {
      console.error('oops, something went wrong!', error);
      alert('Ooops! Something went wrong. Try again.');
    });

  }, 1500);

Change toJpeg to toSVG or any other format

mattpilott commented 2 years ago

@GeekyADAMS i found your workaround does work mostly, but not always. Be good to get a proper solution on this!

GeekyADAMS commented 2 years ago

Well, as far as I can tell, this is the best solution for now. The problem is that IOS and MacOS find it hard to “paint” the details of an html content when converting to any image format. You would think that adding enough delay to make sure content is fully rendered would solve the problem but it doesn’t, what works is attempting conversion multiple times in a chain, to make sure it captures all the details.

So depending on the level of details in your content, you might need to increase the number of conversion chains and maybe add a lil bit more delay. Maybe a sane thing to do is to create that detect IOS and MacOS devices and then take in a number for how many repeated conversion attempts you want depending on the details of your content to make sure it works every time.

As a matter of fact, this can be demoed manually by attempting one conversion and download process after another and see how the level of details captured increases.

Maybe the library maintainer can incorporate this in a fix release.

biiibooo[bot] commented 2 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! 💪💯

mattpilott commented 2 years ago

This is still an issue

Yhozen commented 2 years ago

This is still an issue

Can confirm

TiagoSilvaPereira commented 2 years ago

I had a similar issue using this library with Electron 12 on Linux (works well on Windows)

gustavochavarria commented 2 years ago

You can use this: save-html-as-image Is a wrapper that resolves the problems with SVG in Safari

biiibooo[bot] commented 2 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! 💪💯

Aakash-suthar commented 2 years ago

Still there is issue for safari. Not able to download the image properly. Some icons are not visible. Help if anyone has fixed the issue or the solution is working for Safari browser?

biiibooo[bot] commented 2 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! 💪💯

johnkorzhuk commented 2 years ago

I was able to solve this issue by using the toBlob function in conjunction with file-saver.

 const handleDownloadCover = async () => {
    if (bannerRef.current === null) {
      return;
    }

    try {
      // import { toBlob } from 'html-to-image'
      const data = await toBlob(bannerRef.current, {
        pixelRatio: 1,
        cacheBust: true,
        width: 1500,
        height: 500,
      });

      // import filesaver from 'file-saver'
      firesaver.saveAs(data, 'my-node.png');
    } catch (error) {
      console.error(error);
    }
  };
kurzenkov-globant commented 2 years ago

I found this solution, working for me

const element = document.getElementById('template');
const imageSettings = { quality: 1 };

  const url = await htmlToImage.toJpeg(element, imageSettings);

  let img = document.createElement('img');
  img.src = url;

  const image = await new Promise((resolve) => {
    img.onload = () => {
      htmlToImage.toJpeg(element, imageSettings).then((dataUrl) => {
        resolve(dataUrl);
      });
    };
  });

  return image;
valentinbdv commented 2 years ago

The @kurzenkov-globant solution works perfectly. Thanks

biiibooo[bot] commented 2 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 2 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! 💪💯

paas10 commented 2 years ago

This is still an issue

tarjep commented 2 years ago

I am also encountering this issue.

mattpilott commented 2 years ago

@bubkoo can you reopen please

NicoADavite commented 1 year ago

please reopen

gschattenhofer commented 1 year ago

Still an issue

nazreen commented 1 year ago

still an isue

danny-dang commented 11 months ago

I fixed by adding some wait time before downloading the image as mentioned:

const url = await toPng(domElement);

const link = document.createElement('a');

await sleep(500)

link.href = url;
link.download = filename;

document.body.appendChild(link);
link.click();
document.body.removeChild(link);

Another fix is changing to another library modern-screenshot which is a fork of html-to-image.