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 .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 = '.jpg';
fabric.Image.fromURL(stockImageSrc, function (oImg) {
oImg.setWidth(640);
oImg.setHeight(390);
canvas.add(oImg);
canvas.renderAll();
}, { crossOrigin: '' });
Here is a demo
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
Share Improve this question edited Jun 24, 2015 at 22:20 NullReference asked Jun 24, 2015 at 22:11 NullReferenceNullReference 4,48414 gold badges57 silver badges91 bronze badges 3- 1 The remote site needs to allow you to use their images in that way on your domain – they have to do that, it is nothing you can decide. – C3roe Commented Jun 24, 2015 at 22:25
- @CBroe As far as I can tell these images, YT thumbnails, are returned from their API and designed to be used on different domains. Is there a way to tell if they're not allowing that? – NullReference Commented Jun 24, 2015 at 22:33
- 1 That example URL you have shown does not send any CORS headers. So no, it doesn’t seem to be designed to be used in that way. I’d suggest you go look into their documentation/FAQ to see if they mention CORS anywhere. – C3roe Commented Jun 24, 2015 at 22:35
5 Answers
Reset to default 17In 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.
Try to add the image like this:
var imgObj = new Image();
imgObj.crossOrigin = "Anonymous";
imgObj.src = http://example.com/50/50 ; //the source of your image
imgObj.onload = function () {
// start fabricJS stuff
imgObj.width = 100
imgObj.height = 100
var image = new fabric.Image(imgObj);
image.set({
top: 100,
left: 100 ,
padding: 10,
cornersize: 10,
});
//image.scale(0.1).setCoords();
canvas.add(image);
}
You can try that way(ofcourse thats only a proof of concept)
function getCORSImage(url) {
var oIm=document.createElement("img");
oIm.setAttribute('src', url);
return new fabric.Image(oIm,{
width: 640
height: 390
});
}
Tried all above solutions but but didn't worked in my case. i was using AWS s3
image URL. Work well in local environment but didn't deploy in cloud.
So this works for me.
const toDataUrl = (url, callback) => {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
}
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
}
//it cal be on load OR call it manually
useEffect(() => {
//s3 image url
let testimonial_bg = 'https://s3.amazonaws.com/bucketname/foldername/imagename.jpg';
toDataUrl(`${testimonial_bg}?time=${Date.now()}`, (myBase64) => {
var img = new Image();
img.onload = () => {
let loadedImage = new fabric.Image(img, {
selectable: false,
id: 'mainbg',
left: 0,
top: 0,
crossOrigin: 'Anonymous'
});
loadedImage.scaleToHeight(canvasWidth);
loadedImage.scaleToWidth(canvasWidth);
canvas.current.setBackgroundImage(loadedImage);
canvas.current.renderAll();
}
img.src = myBase64;
});
}, []);
Hope it helps. :)
After searching for 1 day i found this
Instead of fabric.Image.fromURL
fabric.util.loadImage
worked for me
like over here