tsayen / dom-to-image

Generates an image from a DOM node using HTML5 canvas

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Safari Support

allenhwkim opened this issue · comments

I got Event error when I run it on Safari 8.0.7

OOOOOOOPS, something went wrong! 
Event
bubbles: false
cancelBubble: false
cancelable: false
clipboardData: undefined
currentTarget: null
defaultPrevented: false
eventPhase: 0
returnValue: true
srcElement: null
target: null
timeStamp: 1459283334222
type: "error"
__proto__: EventPrototype

the function I ran is like the following

function () {
      domtoimage.toPng(document.querySelector('body'))
        .then(function (dataUrl) {
          var img = new Image();
          img.src = dataUrl;
          document.body.appendChild(img);
        })
        .catch(function (error) {
          console.error('OOOOOOOOPS, something went wrong!', error);
        });
    }

Unfortunately I don't have access to Safari. Can you at least share complete example via, say, jsfiddle?

In Safari 9.1, I get

Error: SecurityError: DOM Exception 18
toDataURL
(anonymous function) — dom-to-image.min.js:15
promiseReactionJob

on toPng, however the toSvg function appears to work fine

@nsonnad your problem might be that some resources you're trying to render are loaded from different domain, that makes it impossible to read rendered data back from the canvas that the library uses internally (see MDN). Do you think that would be the case?

@tsayen Is this the same problem I'm experiencing in Firefox?

No error in Chrome though.

My page imports google fonts - and I get Error while reading CSS rules from https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,700,700italic,900" SecurityError: The operation is insecure. error while rendering.

@kirilledelman I think your issue is the same as #13

Hi tsayen. I've been developing a functionality similar to this repo and meet the same problem. toDataURL() in Chrome Desktop works fine but failed in Safari Mobile and Desktop.

Pseudo code is like this:

var canvas1 = document.getElementById("canvas-id");
var myImage = canvas1.toDataURL("image/png");  

Canvas is generated by html2canvas and not tainted by cross-origin images.

I googled about this and find nothing useful. Do you have any clue?

In Cordova iOS I am also getting this event error.

After investigation, it appears that it is thrown by onerror in this code:

    function inline(get) {
            if (util.isDataUrl(element.src)) return Promise.resolve();

            return Promise.resolve(element.src)
                .then(get || util.getAndEncode)
                .then(function (data) {
                    return util.dataAsUrl(data, util.mimeType(element.src));
                })
                .then(function (dataUrl) {
                    return new Promise(function (resolve, reject) {
                        element.onload = resolve;
                        element.onerror = reject;
                        element.src = dataUrl;
                    });
                });
        }

When this error occurs, the src attribute value is: data:image/svg+xml,base64,. The URL that was previously in the src attribute couldn't be resolved (by get || util.getAndEncode) probably because of a security restriction and the src attribute has an invalid value. It is the reason why the onerror handler is called with the associated event.

Note that I get this behavior only in a Cordova context and not when using Safari over HTTP. In Cordova, all resources are embedded in the application and served through file:///.

When I test the same code served by HTTP I get the SecurityError: DOM Exception 18 error.

I keep investigating to understand why I don't get the same behavior.

The reason for the SecurityError is the canvas getting tainted in Safari.
When the canvas.toDataURL() is applied on a tainted canvas, the Security error is encountered

Apparently in Safari whenever a <foreignObject> is encountered inside a canvas, it gets tainted

As the canvas is drawn with this foreignObject the origin-clean flag is set to false and the canvas is hence being shown to be tainted. From a tainted canvas when the toDataURl function is called the Security Error is encountered.

https://html.spec.whatwg.org/multipage/scripting.html#security-with-canvas-elements

@tsayen Do you have any opinion regarding how this issue may be addressed
Any workarounds!!!

+1
also have same issue, BTW, I had same code better working with html2canvas lib (no security error gotten)

      html2canvas(document.getElementById(this.map_id), {
          useCORS: true,
          onrendered: (canvas) => {
            download(canvas.toDataURL(), "map.png", "image/png"); // Call to global js plugin
          }
        });
commented

Don't know if it's fixed since then, but I tried this package on Safari 12.0 (MacOS Mojave 10.14) and it's working perfectly. My tag img is nicely created with no glitch or something else :)

Just to let you know

commented

Works perfectly on Safari 12.1 (macOS Mojave 10.14.4)

Still facing the issue in Safari 12.1. Any workarounds??

I managed to successfully create PNG on safari 14.0 (on both desktop & iOS), which came out last september! I hope I'm not the only one.

According to caniuse and MDN, safari now supports foreignObject.

I confirm it works on Safari 14.0.3

commented

According to caniuse and MDN, safari now supports foreignObject.

I confirm it works on Safari 14.0.3

Safari supports foreignObject since 18th March of 2008, way back when Safari 3 was a thing. Also, Safari 12.1 already works (#27 (comment))

I managed to successfully create PNG on safari 14.0 (on both desktop & iOS), which came out last september! I hope I'm not the only one.

Can you please let us know how you solve the problem, so that we can check and fix the problem in our end.