Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Images are sometimes skipped via iOS #420

Open
getCryptoAddress opened this issue Jul 23, 2023 · 15 comments
Open

Images are sometimes skipped via iOS #420

getCryptoAddress opened this issue Jul 23, 2023 · 15 comments
Labels

Comments

@getCryptoAddress
Copy link

Expected Behavior

Images always render

image

Current Behavior

Images are sometimes skipped via iOS

image

For example: The background appeared only for the 3rd time
ezgif com-optimize

Possible Solution

Steps To Reproduce

  1. Open https://getcryptoaddress.github.io/paper-wallets
  2. Fill the form with random data image
  3. Click "Get Paper Wallets"
  4. Click "Download"
Error Message & Stack Trace

no errors

Additional Context

Code:

  1. https://github.com/getCryptoAddress/getCryptoAddress.github.io/blob/master/src/features/DownloadPaperWallet/ui/DownloadPaperWallet.vue#L47
  2. https://github.com/getCryptoAddress/getCryptoAddress.github.io/blob/master/src/entities/PaperWallets/lib/download/downloadPaperWallet.ts#L10
  3. https://github.com/getCryptoAddress/getCryptoAddress.github.io/blob/master/src/entities/PaperWallets/lib/download/downloadHtmlAsPng.ts#L8

Your Environment

  • html-to-image: ^1.11.11
  • iOS: iOS 16
@vivcat
Copy link
Contributor

vivcat bot commented Jul 23, 2023

👋 @getCryptoAddress

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.

@morlimoore
Copy link

Hi @getCryptoAddress, have you been able to move past this yet?
I am using the html-to-image V1.11.11 and I experience the same issue as you. The image is only visible on the third download, and I don't know the cause of that.

@it4need
Copy link

it4need commented Aug 3, 2023

Having the same issues here... I can reproduce this issue even on v1.11.0

@jonathanrstern
Copy link

Same here

@riccardoperra
Copy link

This is an iOS issue unfortunately https://bugs.webkit.org/show_bug.cgi?id=219770

I partially resolved this adding a delay of 250ms after the creation of the svg and before drawing to the canvas. 250 is just a magic number that I know in most of times image has been loaded. For images of high size and if you haven’t loaded it into the dom probably it’s not enough

toCanvas()

  • call toSvg
  • call createImage(svg)
  • add delay
  • draw canvas

@CheckCoder
Copy link

Same here

@jonathanrstern
Copy link

jonathanrstern commented Aug 6, 2023

Finally found a reliable solution: the modern-screenshot library (a fork of html-to-image). Completely fixed the problem for me!

H/t @qq15725

https://github.com/qq15725/modern-screenshot

@riccardoperra
Copy link

riccardoperra commented Aug 6, 2023

beware that this solution seems still clone image like everyone else (https://github.com/qq15725/modern-screenshot/blob/main/src/clone-image.ts), so probably it is fixed by implicitly being asynchronous and adding some delays, since it uses worker (I don't know if it's a good idea, since the major computation only concerns the dom which is not available in the worker side)

image

default drawImageInterval is 100
https://github.com/qq15725/modern-screenshot/blob/0973c6c302e91b3d49921876f5c021b5ddda833a/src/create-context.ts#L53

@jonathanrstern
Copy link

He explained the difference here:

#361 (comment)

What do you think?

@riccardoperra
Copy link

riccardoperra commented Aug 6, 2023

Delaying the final canvas rendering by a fixed timeout can be the solution for most of cases.

It’s valid in my opinion since there isn’t any way to know if safari will render the image.

What I don’t like it’s this magic number which doesn’t guarantee it works every time 😅, but probably it’s the best it can be done at the moment.

Anyway this solution seems delaying n seconds for each image present in the html structure, so if you have like 10 images, it will be delayed for 1000ms~ (10 * 100ms) 🤔 but I don’t have the full understand of the code so I may be wrong.

Another important thing: what’s the device we are using to render that image, and how much mb is it?

Assuming we are trying to render an image around 0-1mb, most of iOS and macOS device can render it with a timeout of 100. If the image gets bigger, we surely need to increment this timeout. But I think there are others factors like device speed (what if energy save mode is on?)

currently I think the most safest way of rendering an image without having issues is using puppeteer/playwright with chrome under the hood 🤷🏻‍♂️ doing this will also allows to export the same image for all sort of devices (e.g. safari still can’t handle box-shadow), but it may be expensive

@qq15725
Copy link

qq15725 commented Aug 7, 2023

10 image ref = 10 (canvasContext2d.drawImage('data:image/svg+xml,html-to-svg-data') and await 100ms)

I don't know how it works, but it works 😄

@jonathanrstern
Copy link

jonathanrstern commented Aug 7, 2023

Can confirm that it's working beautifully! Thanks again @qq15725 :)

(For me, it's working on photos >5MB... will post an update if it stops working but for now I think we're good to go)

@CheckCoder
Copy link

10 image ref = 10 (canvasContext2d.drawImage('data:image/svg+xml,html-to-svg-data') and await 100ms)

I don't know how it works, but it works 😄

Thanks, work for me too.

@getCryptoAddress
Copy link
Author

getCryptoAddress commented Aug 7, 2023

https://github.com/bubkoo/html-to-image/blob/master/src/index.ts#L58
if add

await new Promise((resolve) => setTimeout(resolve, 1));
image

Safari will render always

__ UPDATED__
ok, I created PR #423

__ UPDATED__
I'm wrong. I reproduced bug again. Not 8 times from 10, but 3 times from 10. It is better, but not solution

getCryptoAddress added a commit to getCryptoAddress/html-to-image that referenced this issue Aug 7, 2023
@getCryptoAddress
Copy link
Author

getCryptoAddress commented Aug 11, 2023

Vue code example

<script lang="ts" setup>
     // ....

     // get svg from "html-to-image" for html
     canvasSvgElement.value = decodeURIComponent(await toSvg(targetElement));

    // wait vue render
    await nextTick();

    // get images into svg
    const images = canvasImageWrapperElement.value?.querySelectorAll("img");

    // wait all images
    if (images) {
      await Promise.all(
        [...images].map((img) => {
          return new Promise((resolve, reject) => {
            if (img.complete) {
              resolve(null);
            } else {
              img.onload = resolve;
              img.onerror = reject;
            }
          });
        })
      );

      console.log("images loaded"); // <--- it's true for safari

How I understand, safari needs time to render, not just load
https://github.com/bubkoo/html-to-image/blob/master/src/embed-images.ts#L57
This is just a hypothesis, anyway the code above works in safari

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants