html2canvas icon indicating copy to clipboard operation
html2canvas copied to clipboard

CORS

Open icezeko opened this issue 6 years ago • 22 comments

i'm trying to take a shot of a google recaptcha challenge loaded by iframe from another iframe, already used allowTaint and useCORS, and all i get is a error.

0ms html2canvas: html2canvas 1.0.0-alpha.12 10ms html2canvas: DOMException: Failed to execute 'open' on 'Document': Can only call open() on same-origin documents. DOMException: Failed to execute 'open' on 'Document': Can only call open() on same-origin documents.

icezeko avatar May 26 '18 18:05 icezeko

I fixed some cors issues I was having with the combination of Google Chrome, AWS S3, and multiple origins.

I found this stackoverflow thread: https://stackoverflow.com/questions/26352083/chrome-cors-cache-requesting-same-file-from-two-different-origins

Which links to this bug report: https://bugs.chromium.org/p/chromium/issues/detail?id=260239

Anyhow as workaround solution you can try this modified version of html2canvas: https://gist.github.com/CrandellWS/6bc2078aced496004d7a045e6360f19b

use the options:

allowTaint : false,
useCORS: true

Hope that helps.

FYI, this will add the current time stamp to cors image urls to sidestep a cache issue I was having on Chrome... https://gist.github.com/CrandellWS/6bc2078aced496004d7a045e6360f19b#file-html2canvas-js-L6838

Which means it will effect performance by re-downloading those images...

CrandellWS avatar Nov 04 '18 04:11 CrandellWS

Thank you @CrandellWS I have solved it using your solution this way.

const image = "https://s3-us-west-2.amazonaws.com/github.png?1551296103"
const timestamp = new Date().getTime();
const imageWithTimestamp = image.includes('?') ? `${image}&v=${timestamp}` : `${image}?v=${timestamp}`;

render() {
  return (
    <div>
      <h1>Hello world</h1>
      <img
         src={imageWithTimestamp}
         alt={imageName}
         crossOrigin="anonymous"
      />
    </div>
  );
}

Please make sure that you image is returning CORS enable headers. Otherwise you have to add CORS policy to your s3 bucket.

pritambios avatar Mar 29 '19 15:03 pritambios

Thank you @pritam1994

Rostislav-Poleshko avatar Apr 23 '19 13:04 Rostislav-Poleshko

Hi,

I have added the following options -

allowTaint : false,
useCORS: true

Bit it is not showing captcha. Instead a blank box.

sougatabose07 avatar Jun 06 '19 11:06 sougatabose07

Without modifying html2canvas, here is an idea: First use canvas to convert cross-domain pictures into Base64 encoding, and then give it to html2canvas for processing

// 1.First get the Base64 encoding of cross-domain pictures through canvas
const img = new Image();
img.onload = () => {
  const c = this.$refs.crossImg;
  const ctx = c.getContext('2d');
  ctx.drawImage(img, 0, 0, c.width, c.height);
  this.crossImgBase64 = c.toDataURL('image/png');

  // 2.Draw
  Html2canvas(this.$refs.html, {
    // useCORS: true,
  }).then((canvas) => {
    this.pngBase64 = canvas.toDataURL('image/png');
    this.isShowPng = true;
  });
};
img.crossOrigin = 'anonymous';
img.src = 'https://secure.gravatar.com/avatar/03af4ed2fa8526e9f37c847cc4083141';

Here a example

https://vue-html2canvas-safari-bug.stackblitz.io/

gaoming13 avatar May 27 '20 02:05 gaoming13

I am using version 1.0.0-rc.0 and just adding @CrandellWS's solution didn't work The part of html2canvas.js file where the correction has to be made is like this

if (!supportsDataImages || useCORS){
    img.crossOrigin = 'anonymous';
} 
    img.onerror = reject;
    img.src = src;

Adding src alone won't work, the code has to be like this

if (!supportsDataImages || useCORS){
    img.crossOrigin = 'anonymous';
    img.src = src +'?v='+new Date().getTime();
} 
else{
    img.src = src;
}
    img.onerror = reject;

rup9823 avatar Dec 29 '20 13:12 rup9823

It seems it is not fixed yet.

SalahAdDin avatar Dec 16 '21 14:12 SalahAdDin

been stuck for days and finally found the solution from here: https://developpaper.com/question/img-add-crossorigin-anonymous-and-the-picture-will-not-be-displayed/

in addition, I added:

useCORS: true

and on the img tag: <img imageUrl + '?time=' + new Date().valueOf() crossorigin='anonymous'>

hope this helps

yulisartika avatar Dec 27 '21 05:12 yulisartika

@yulisartika Well, when i put crossorigin='anonymou' the brower simply can't fetch the image, hence, it can't show them.

SalahAdDin avatar Dec 27 '21 15:12 SalahAdDin

@SalahAdDin as @yulisartika said

and on the img tag: <img imageUrl + '?time=' + new Date().valueOf() crossorigin='anonymous'>

setting the image url to have an unique parameter is key

CrandellWS avatar Dec 27 '21 17:12 CrandellWS

been stuck for days and finally found the solution from here: https://developpaper.com/question/img-add-crossorigin-anonymous-and-the-picture-will-not-be-displayed/

in addition, I added:

useCORS: true

and on the img tag: <img imageUrl + '?time=' + new Date().valueOf() crossorigin='anonymous'>

hope this helps

@yulisartika Well, when i put crossorigin='anonymou' the brower simply can't fetch the image, hence, it can't show them.

Adding crossOrigin="" did it for me.

arohablue avatar Jan 26 '22 17:01 arohablue

@arohablue for me did not =´(

cezarcozta avatar Apr 02 '22 03:04 cezarcozta

@arohablue for me did not =´(

We had to make a proxy server.

SalahAdDin avatar Apr 03 '22 10:04 SalahAdDin

@arohablue for me did not =´(

For me the image is stored on WAS so I also added a cors filter there and used the below to fetch it. <img src={bucketURL+ '?time=' + new Date().valueOf()} crossOrigin=""/>

arohablue avatar Apr 03 '22 14:04 arohablue

As i need to get screenshot for iframe from other page but its in same domain but then also getting this error:- Failed to execute 'open' on 'Document': Can only call open() on same-origin documents Getting this error on html2canvas any help appreciated

IntelligaiaVivek avatar May 20 '22 13:05 IntelligaiaVivek

As i need to get screenshot for iframe from other page but its in same domain but then also getting this error:- Failed to execute 'open' on 'Document': Can only call open() on same-origin documents Getting this error on html2canvas any help appreciated

Proxy server I would say.

SalahAdDin avatar May 20 '22 19:05 SalahAdDin

Has anyone had the same situation as me? some images can be downloaded, but some give cors error even though they are in the same bucket s3 bucket setup cors AllowOriginls: ["*"] I use the option useCORS: true

yanghoxom avatar Aug 09 '22 07:08 yanghoxom

for people still having the issue, for me what worked was a mix of some replies here.. I have:

<img imageUrl + '?time=' + new Date().valueOf() crossorigin="">

plus { allowTaint: true, useCORS: true } in html2canvas and then it worked! Image is hosted on S3.

RSchneider94 avatar Oct 06 '22 19:10 RSchneider94

@RSchneider94 i wish it wa that easy for some reason when I have crossorigin="" or anonymous my images don't even render at all.

@memsenpai I have the exact same issue as you my S3 bucket has AllowOrigin wildcard

xrzhuang avatar Dec 18 '22 05:12 xrzhuang

been stuck for days and finally found the solution from here: https://developpaper.com/question/img-add-crossorigin-anonymous-and-the-picture-will-not-be-displayed/ in addition, I added: useCORS: true and on the img tag: <img imageUrl + '?time=' + new Date().valueOf() crossorigin='anonymous'> hope this helps

@yulisartika Well, when i put crossorigin='anonymou' the brower simply can't fetch the image, hence, it can't show them.

Adding crossOrigin="" did it for me.

For me was the response!!

w4cernesto avatar Apr 18 '23 01:04 w4cernesto

@xrzhuang I must use a server as a proxy to solve that issue :(

yanghoxom avatar May 08 '23 12:05 yanghoxom

For anyone who may have run into this seemingly simple issue. As long your application can make cross origin requests fine and your only issue is html2canvas not being able to reach those URLs, you can convert your visible images to data URLs prior to the canvas printing to bypass the need for html2canvas to fetch them cross origin.

This is the only way I was able to get around this without proxy or reworking CORS in my functions or server.

-- Loop over your node for img tags, set the src to await toDataURL(img.src)

const toDataURL = async (src) => {
  let blob = await fetch(src).then((r) => r.blob());
  let d = await new Promise((resolve) => {
    let reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.readAsDataURL(blob);
  });
  return d;
};

zakpucci avatar Apr 03 '24 21:04 zakpucci