The solution of canvas.toDataURL() error reporting is all here

Error reporting details

Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

Key word

canvas.toDataURL()

crossOrigin

Access-Control-Allow-Origin

Preface

Recently, I am making a creative image synthesis tool, which is to generate a product image by splicing customized text and image information. In the project, I used fabric.js as the sketchpad library. In the last step, when saving the image, I reported a long series of errors. I searched inside and outside the wall once, and the solutions were not comprehensive, so as to avoid the students from going back The second time I stepped on the pit, I got this article

text

When we convert dom2image, if there is a picture resource in the DOM, the web server where the resource is located does not support cross domain, and saving pictures will not succeed.

Therefore, when troubleshooting problems, first determine

  1. Whether the web server is allowed to cross domains? Take nginx as an example. Access control allow origin: XXXX (it can be * and the one with high security requirements can be customized according to the primary domain name) should exist in the response header

  2. If it is an img tag, whether to add the crossrigin = "anonymous", if it is an Image object, whether to add the modified attribute obj. Crossorigin ='anonymous'

  3. If not, let's look at the chestnuts first

In the next chestnut, we will use the method of converting Image to canvas object

  function convertImageToCanvas(image) {
    // Create the canvas DOM element and set its width and height to be the same as the picture   
    let canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;
    canvas.getContext("2d").drawImage(image, 0, 0);
    // In the actual development, we need to transfer the base64 image code after grabbing and replacing to the background image server, which can directly store or generate a picture;
    // So toDataURL is used
    console.log(canvas.toDataURL('image/jpeg'))
    return canvas;
  }

Chestnut 1

Cross domain permission option is not set locally, cross domain permission option is not set for web server

  <div id="d1">
    <img style="width: 300px;height: 240px;" src="http://es6.ruanyifeng.com/images/cover_thumbnail_3rd.jpg" alt="">
    <p>Cross domain allow option is not set locally crossorigin=anonymous,web-server Cross domain allow option not set</p>
  </div>
  <button onclick="setCanvas('d1')">canvas Preservation</button>
    function setCanvas(DOMID) {
      let img = document.getElementById(DOMID).querySelector('img')
        document.body.appendChild(convertImageToCanvas(img))
    }

Obviously, it's wrong

Chestnut 2

Cross domain permission option is set in the local label, and web server does not set cross domain permission option

This time, I can't even get the pictures out. I'll report the error directly

This is easy to understand, browser Homologous strategy Restriction

Access to image at 'xxxx' (redirected from 'xxxx') from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Chestnut 3

Cross domain permission option is not set locally. Cross domain permission option is set for web server

It's a good report.

Chestnut 4

Cross domain permission options are set in the local tag, cross domain permission options are set in web server

  <div id="d4">
    <img style="width: 300px;height: 240px;" src="https://img.alicdn.com/tfs/TB1_uT8a5ERMeJjSspiXXbZLFXa-143-59.png" alt="" crossorigin="anonymous">
    <p>Set cross domain allow options locally`crossorigin=anonymous`,`web-server`Set cross domain allow options</p>
  </div>
  <button onclick="setCanvas('d4')">canvas Preservation</button>

It's OK, but ~ what about setting up cross domain in the code?

Chestnut 5

  function setCanvas(DOMID) {
    let img = document.getElementById(DOMID).querySelector('img')
    
    img.crossOrigin= 'anonymous'
    
    document.body.appendChild(convertImageToCanvas(img))
  }

Report errors
I see Official documents This means that crossorigin = anonymous must be set synchronously for the image certificate to be trusted

This means that CORS is enabled and credentials are sent if the image is fetched from the same origin from which the document was loaded.

Otherwise, the cached image data will still be regarded as contaminated cross - source content by canvas

What should I do? Take the picture again. Add a random number. The picture is still that picture. But with a vest, the browser doesn't know it

Chestnut 6

  function setCanvas(DOMID) {
    let img = document.getElementById(DOMID).querySelector('img')
    
    img.src =img.src+'?v='+Math.random()
    img.crossOrigin= 'anonymous'
    
    img.onload=()=>{
      document.body.appendChild(convertImageToCanvas(img))
    }
  }

binggo, perfect solution

So in the process of development, it's better to add a random number every time in the function codes such as new pictures, replacement pictures and restoration pictures, so as to ensure that the source is up-to-date and does not go through the cache

Let's talk more about the cross domain configuration of fabric.js. See the following

    let _fabricConfig = {
        // ....
        crossOrigin:'anonymous'
    };
    /* fabric object */
    let _fabricObj = new fabric.Canvas(id, _fabricConfig);


    // When creating a new picture object
    let imgInstance = new fabric.Image.fromURL(url + '?v='+ Math.random(), img => {}, {crossOrigin: 'anonymous'})
    
    // When updating pictures dynamically
    let currentActive = _fabricInstance.getActiveObj();
    currentActive.setSrc(randomURL, img =>{}, {crossOrigin: 'anonymous'})

Keywords: Javascript Web Server Nginx Attribute

Added by mckooter on Sun, 29 Mar 2020 15:54:49 +0300