How do I handle CORS with html2Canvas and AWS S3 images?

17,160

Solution 1

See the edit, I did try setting the crossOrigin attribute with no luck, and I use useCORS set to true (forgot to mention that sorry). Still no luck.

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

I found this stackoverflow thread: 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...

original post: https://github.com/niklasvh/html2canvas/issues/1544#issuecomment-435640901

Solution 2

I solved this error with adding crossOrigin attribute at IMG tag. So, your code will look like (tag at React js):

<Image crossOrigin="true" />

And my configuration at S3 bucket with CORS:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>http://localhost:8000</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
<CORSRule>
    <AllowedOrigin>https://testing.d1wr8lk28mi6l0.amplifyapp.com</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>

HTML2CANVAS:

 html2canvas(getWrapper, { allowTaint: true, useCORS: true, logging: true })
  .then((canvas) => {
    const imgData = canvas.toDataURL('image/png');
    console.log(imgData);
  });

Solution 3

I solved this problem by adding proxy:( image src ) option in html2canvas. Now your image is also included in pdf

Typescript Code:

download() {
        var data = document.getElementById('view-eob');
        html2canvas(data, { proxy: this.eobDetail.member.parentCompany.logo })
        .then(canvas => {
            var imgWidth = 208;
            var imgHeight = canvas.height * imgWidth / canvas.width;
            const contentDataURL = canvas.toDataURL('image/png')
            let pdf = new jsPDF('p', 'mm', 'a4');
            var position = 0;
            pdf.addImage(contentDataURL, 'PNG', 0, position, imgWidth, imgHeight)
            pdf.save(`${this.eobDetail.episode.name}-EOB.pdf`);
        });
    }

HTML Code:

<div>
     <img [src]="this.eobDetail.member.parentCompany.logo"/>
</div>
<button type="button" (click)="download()"> Download</button>
Share:
17,160

Related videos on Youtube

G4bri3l
Author by

G4bri3l

Lead Engineer at MongoDB, advocate of functional programming and critical thinking! I also ❤️ React, Go and Machine Learning!

Updated on September 18, 2022

Comments

  • G4bri3l
    G4bri3l over 1 year

    I know similar questions have been asked before but I still can't make it work. I have a div with images inside of it loaded from a bucket in AWS s3, they load perfectly no problem.

    Now I want to be able to save as a jpeg whatever is in that specific div (like taking a screenshot), the plugin html2canvas helps with that. The problem is that when I try to actually save it (or simply show immediately the result of such screenshot) I run into these issues:

    • Canvas is tainted => I set allowTaint: true in the plugin but it would throw this error, so I disabled it and the error went away. I keep useCORS set to true though to allow images from another source.

    • Access to image has been blocked by CORS policy

    In order to solve this I set up CORS on my AWS S3 bucket, but that didn't seem to work (or it worked partially). I noticed that the response header of those images don't have CORS metadata when the plugin uses them to generate the jpeg. I then tried to set crossOrigin="anonymous" in those images inside the div but it would throw a CORS error right away, which shouldn't happen since the AWS bucket has been set up for that as follows:

    <?xml version="1.0" encoding="UTF-8"?>
    <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
        <CORSRule>
            <AllowedOrigin>*</AllowedOrigin>
            <AllowedMethod>GET</AllowedMethod>
            <AllowedHeader>Authorization</AllowedHeader>
        </CORSRule>
    </CORSConfiguration>
    

    I am running out of options on how to make this work. Any idea on how to proceed from here would be very appreciated.

    EDIT: More details, I am using React and the images urls are retrieved from a server. This means that as soon as I get this array of urls I generate:

    <div>
      { urls.map(url => <img src={url} alt="some alt" />) }
    </div>
    

    If I add the crossOrigin="anonymous" I get the CORS error. If I leave that out, the images display but then the html2canvas plugin throws a CORS error as well when trying to generate the "screenshot".

    More details about the HTTP requests. So the first time I load an image inside the div, this is the Response Header:

    Accept-Ranges:bytes
    Access-Control-Allow-Methods:GET
    Access-Control-Allow-Origin:*
    Cache-Control:max-age=2592000
    Content-Length:508208
    Content-Type:image/png
    Date:Thu, 16 Feb 2017 18:25:05 GMT
    Last-Modified:Wed, 15 Feb 2017 19:09:44 GMT
    Server:AmazonS3
    Vary:Origin, Access-Control-Request-Headers, Access-Control-Request-Method 
    

    Now this works if crossOrigin='anonymous' and the picture is not from the cache. If the crossOrigin attribute is not set I get:

    Accept-Ranges:bytes
    Cache-Control:max-age=2592000
    Content-Length:508208
    Content-Type:image/png
    Date:Thu, 16 Feb 2017 19:03:53 GMT
    Last-Modified:Wed, 15 Feb 2017 19:09:44 GMT
    Server:AmazonS3
    

    or it throws a CORS error on the console without showing any meta data on the response header. I tried adding a random string at the end of the url (?somethingsomething) so that they would never be grabbed from the cache, and that fixed the issue completely. But this is just a hack and it works for now but it is not definitely the solution I am looking for. I think Chrome is doing something with the cache and I have a hard time tracking the source of the issue, other than the fact that it's hard to reproduce this problem on my machine since it always retrieved the screenshot from cache even if I am using completely new images and disable/clear cache. It's very confusing.

    • Jaromanda X
      Jaromanda X about 7 years
      Access to image has been blocked by CORS policy - show the code you are using to get the image
    • Kaiido
      Kaiido about 7 years
      You have to either load your image with the crossOrigin attribute set to 'anonymous' directly in your document, or you can try useCORS h2c option. allowTaint option does just say that you don't care if it taints the canvas or not.
    • G4bri3l
      G4bri3l about 7 years
      See the edit, I did try setting the crossOrigin attribute with no luck, and I use useCORS set to true (forgot to mention that sorry). Still no luck.
    • Kaiido
      Kaiido about 7 years
      Ah so you've got a problem with your bucket's settings. It's been a while but your conf seems ok to me, maybe remove the Allowed header field, I think it's not necessary. You can check this answer, quite old, and I don't have s3 account anymore to test...
    • Michael - sqlbot
      Michael - sqlbot about 7 years
      Can you capture and show us the complete request and response headers for a failed request, and the entire CORS error?
    • G4bri3l
      G4bri3l about 7 years
      I updated my question with more info.
    • G4bri3l
      G4bri3l about 7 years
      @Kaiido Thanks for the link, I simplified my CORS settings as suggested there and cleared my cache, it keeps working for me on Chrome, but I tried with other laptops and it doesn't, then I tried a PC and it worked. I'm so lost.
    • seuling
      seuling almost 6 years
      It's far late response, but try remove cache for s3. I got similar problem, and just solve with add some random string after url (?_324) and it works!
    • Rahul Sagore
      Rahul Sagore over 5 years
      I am having the same usecase as yours of generating Screenshot of S3 Image. Unable to find a solution. Seems like issue with Chrome. bugs.chromium.org/p/chromium/issues/detail?id=718352
    • CrandellWS
      CrandellWS over 5 years
      @RahulSagore try this stackoverflow.com/a/53137836/1815624 for Chrome.
  • parse
    parse over 5 years
    I saw your edits you have added to html2canvas.. it helped to avoid showing blank image after rendering. I can see you have added date.getTime() as a random number at the end of img's src! could you explain why? and is that has a relationship with caching issues?
  • CrandellWS
    CrandellWS over 5 years
    @Wowali for me that was mostly for AWS Bucket a way to not use cache version and set it to anonymous as was needed for cors to work...to prevent tainting...
  • CrandellWS
    CrandellWS over 5 years
    I posted this on the githubs issues list for the project at github.com/niklasvh/html2canvas/issues/…
  • parse
    parse over 5 years
    Yep, it helped me to resolve an issue with CORS with one domain name… thank you so much
  • KcH
    KcH over 3 years
    Does html2pdf has fixed cors version ? or any updated solution please ... Thanks
  • Sophie
    Sophie over 3 years
    @CrandellWS Hey crandell may i know how can i include the fix as a script tag ? Thanks..
  • CrandellWS
    CrandellWS over 3 years
    @Sophie I dont understand what you mean script tag...
  • Sophie
    Sophie over 3 years
    @CrandellWS I saw the workaround here but may i know how can i include this in project ? like a CDN script tag ... hope its clear
  • CrandellWS
    CrandellWS over 3 years
    just download it and server it on your system there is no CDN just this one off fix as a gist
  • SalahAdDin
    SalahAdDin over 2 years
    what if they are multiple images?