Detailed explanation canvas.toDataURL () the wrong solutions are all here

Time:2020-9-18

Error reporting details

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

key word

preface

Recently, I’m doing a creative image synthesis tool. It’s about to create a product picture by splicing custom text and picture information. Similar functions are used in the project fabric.js The last step of this Sketchpad library is to report a long series of errors when saving the pictures. I searched the walls inside and outside the walls, but the solutions given were not comprehensive. In order to avoid the students from repeating Step on the pit, so there is this article

text

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

Therefore, in troubleshooting, the first thing to determine

  • Whether the web server allows cross domain, we take nginx as an example, and access control allow must exist in the response header- Orgin:xxxx (it can be *, and those with high security requirements can be customized according to the main domain name)
  • If it is an img tag, whether crossorigin = anonymous is added; if it is an image object, is the property changed obj.crossOrigin= ‘anonymous’
  • If not, let’s take a look at chestnuts instead

In the following 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 changed Base64 image code to the background image server, which stores or generates an image directly;
//So the todataurl is used
console.log(canvas.toDataURL('image/jpeg'))
return canvas;
}

Chestnut 1

Cross domain permission option crossorigin = anonymous is not set locally, and cross domain permission option is not set on Web server

<div id="d1">
<img style="width: 300px;height: 240px;" src="https://imgs.developpaper.com/imgs/cover_thumbnail_3rd.jpg" alt="">
<p>Cross domain permission option crossorigin = anonymous is not set locally, and cross domain permission option is not set on Web server</p>
</div>
< button onclick = "setcanvas ('d1 ')" > canvas save < / button >

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

Obviously, the report is wrong

Chestnut 2

The cross domain permission option is set in the local tag, but not in the web server

I can’t even get the pictures this time. I’ll report the error directly

This is easy to understand. The same source policy is restricted by browsers

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 allow option not set locallycrossorigin=anonymous, web-serverSet cross domain allow options

It’s a good report.

Chestnut 4

Setting cross domain permission options in local Tagscrossorigin=anonymous, web-serverSet cross domain allow options

<div id="d4">
<img style="width: 300px;height: 240px;" src="https://imgs.developpaper.com/imgs/TB1_uT8a5ERMeJjSspiXXbZLFXa-143-59.png" alt="" crossorigin="anonymous">
<p>Set cross domain permission options' crossorigin = anonymous' locally and 'web server' to allow cross domain options</p>
</div>
< button onclick = "setcanvas ('d4 ')" > canvas save < / button >

Actually, but what about setting 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

What I mean by the official document is 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 the canvas

What should I do? Take the picture again, add a random number, the picture is still that picture, but add a vest, the browser does not know

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

Therefore, in the development process, we should add a random number every time in the function code, such as creating new pictures, changing pictures and restoring pictures, so as to ensure that the source is up-to-date and does not go to cache

A little more about it fabric.js The cross domain configuration of is shown below

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'})

github:http://github.com/phillyx

Here is a detailed explanation canvas.toDataURL () the solutions for reporting errors are all here. This is what the article introduces here canvas.toDataURL () please search the previous articles of developeppaer or continue to browse the related articles below. I hope you can support developeppaer more in the future!

Recommended Today

How to share variables in promise chain?

Translator’s note:usePromiseI’ll find out if I write asynchronous codePromiseSharing variables in a chain is a big headache, and that’s also trueAsync/AwaitBetter thanPromiseWe have mentioned six reasons for async / await to replace promise, which will be more detailed in this blog. Passing data between promise callbacks Translator: fundebug In order to ensure the readability, this […]