Canvas使用background Image时的神奇bug
有问题问Stack Overflow
canvas.drawImage with computedStyleMap().get("background-image"), DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
<div id='img3'>background-image with this</div>
#img3 {
background-image: url("../icons/we-flow.png");
}
var img = img3.computedStyleMap().get("background-image");
//img=img1;
var canvas=document.createElement('canvas');
img.crossOrigin="Anonymous";
var ctx=canvas.getContext('2d');
try {
ctx.drawImage(img, 0, 0);
var data=ctx.getImageData(0, 0, canvas.width, canvas.height).data;
}catch (error) {
console.log('refresh page will get this', img.toString(), {error, img});
}
run this code with chrome 83, first time load the code, everything is ok, but when i refresh the page in browser, i will get the console.log. my question is why? an how can i fix it?
经过一天的分析, 又重新提了一个问题, 这个问题终于惊动了大神: wOxxOm
In development, I need to judge the color of the picture. Therefore, canvas is used, but it will face cross-domain problems when processing,
so I am solving it by modifying the http header, but this method is useful for image tags, but for background-image, It will be invalid,
do you have any good solutions?
I know that extracting the background-image url, and then creating a new image should solve this problem,
I would like to ask if there is a better and more convenient way?
In html
<div id='imgwiki'>this is wrong, because use background-image</div>
<img id="imgb" src="https://ssl.gstatic.com/images/icons/material/system_gm/2x/content_copy_black_24dp.png" alt="imgb"> this is allways ok. because it is a img tag
In my content.js
var img=document.getElementById("imgwiki");
img=img.computedStyleMap().get("background-image");
img.crossOrigin="Anonymous";
var canvas=document.createElement('canvas');
var ctx=canvas.getContext('2d');
ctx.drawImage(img,0,0);
var data=ctx.getImageData(0,0,canvas.width,canvas.height).data; //here cross-domain
In my background.js
chrome.webRequest.onHeadersReceived.addListener(
function(details) {
luoism.log({details}, details.url);
return {responseHeaders: [...details.responseHeaders,{name: "Access-Control-Allow-Origin",value: "*"}]};
},
{urls: ['<all_urls>']}, // filters
['blocking','responseHeaders','extraHeaders'] // extraInfoSpec
);
@wOxxOm, actually this code is ok, but i want a more directly solution:
!async function getcssimage(e) {
var stylestr=e.computedStyleMap().get('background-image').toString();
//get url
var url='',ur=/url\("([^)"]+)/,x=false;
if(!ur.test(stylestr)) return false;
url=ur.exec(stylestr);
url=url[1];
//deal mix http & https
url=luoism.config.ishttps? url.replace(/^https*/,'https'):url;
//from background-image url to <img> tag
function makeimg(url) {
return new Promise(resolve => {
let img=new Image();
img.addEventListener("load",e => {
resolve(e.currentTarget);
});
img.onerror=e => {
let t=e.currentTarget;
t.onerror="";
t.style.display='none';
e.stopPropagation();
e.preventDefault();
resolve(false);
};
img.crossOrigin="anonymous";
img.src=url;
});
}
// deal this <img>, anything is ok
var img=await makeimg(url);
var canvas=document.createElement('canvas');
var ctx=canvas.getContext('2d');
luoism.log('消息begin',img.toString(),{img});
ctx.drawImage(img,0,0);
var data=ctx.getImageData(0,0,canvas.width,canvas.height).data;
return x;
}(img);