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