Search code examples
javascripthtmlcanvashtml5-canvasfabricjs

Why does adding crossOrigin break fabric.Image.fromURL?


I have an image editor that I'm trying to add external images to.

When I add the crossOrigin property to the img object it fails to load the image on the canvas and I get an error in the console "Error loading https://i.ytimg.com/vi/JphpLkmimVo/hqdefault.jpg". If I remove the crossOrigin it allows the image to be added but then when I export the canvas as an image I get a security error. I've read that adding it without the crossOrigin taints the canvas. Can anyone tell me why I can just keep the crossOrigin property?

var stockImageSrc = 'https://i.ytimg.com/vi/JphpLkmimVo/hqdefault.jpg';
fabric.Image.fromURL(stockImageSrc, function (oImg) {
                        oImg.setWidth(640);
                        oImg.setHeight(390);
                        canvas.add(oImg); 
                        canvas.renderAll();
                    }, { crossOrigin: '' });

Here is a demo


Solution

  • In my experience, you have to set the crossOrigin to Anonymous. In an example:

    var stockImageSrc = 'https://i.ytimg.com/vi/JphpLkmimVo/hqdefault.jpg';
    fabric.Image.fromURL(stockImageSrc, function (oImg) {
        ... other code here...
     }, { crossOrigin: 'Anonymous' });
    

    This comes directly from the Mozilla developer documentation.

    HOWEVER, you'll also see on that documentation that this is not supported by all browsers - namely Internet Explorer. I've found that it does NOT work in IE10 and older - IE11 does work. I am using a workaround for this for IE10 and older - see below. The reason this does not work is that older versions of IE do not have the full CORS ruleset implemented as well as a lack of full HTML5 (which Canvas is a part of) added to it's codebase. Firefox and Webkit browsers however (Chrome, Safari, etc.) are always updating and thus they are far ahead of the IE counterparts in these newer standards.

    The other piece to this however is that the server hosting the image does need to have the Access-Control-Allow-Origin header set to either the domain of the page that is making the request or to *. This comes from the Mozilla CORS documentation. As @CBroe mentioned above, the youtube image you reference does NOT have have that header set. Therefore this image will taint your canvas.

    The way to work around the crossOrigin for IE10 and older, and I'm guessing this workaround might work for images that do not have the Access-Control-Allow-Origin header set, is to use a server-side proxy. The concept here is that you send a request for the YouTube image to a server on the same domain that your webpage is hosted from. This keeps all image requests on the same domain, thus passing CORS rules. But the YouTube image of course isn't hosted on that server. The script that responds on your server would then request the YouTube server (or any other for that matter), capture the image on the server, and then pass it back to the browser. This can be done via a CURL request or some other methods. Make sure to set the Access-Controls-Allow-Origin header from the proxy server. You can find more information on a CORS Server Proxy here.

    All that said, sadly there isn't a quick/simple answer to your question. Browsers are trying to offer it's users top security, and cross site scripting can create some issues that can steal identities, etc. That's the reason for the extra hoops to jump through.

    Also of note, you could look at JSONP solutions (an alternative to CORS), however it's an older standard and has some negatives - I believe it's not fully supported in some of the more modern browsers and has some security concerns. Do a quick Google search to find out more on that option.