问题
I'm trying to get the data URL for an image. The image is coming from a cross origin remote server, Wikipedia. I use this JavaScript to try to do it:
# get the image
const img = document.createElement('img')
img.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/26/Strychnine.svg/360px-Strychnine.svg.png'
# don't send credentials with this request
img.crossOrigin = 'anonymous'
# now copy to a <canvas /> to get data URL
const canvas = document.createElement('canvas')
canvas.width = img.width
canvas.height = img.height
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0)
canvas.toDataURL('image/jpg')
But I'm getting this error: Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported
.
I read that this is a CORS issue. The browser prevents you from getting the image data from images if the server hadn't set the Access-Control-Allow-Origin
header. But here's the weird thing. I checked the response and that header is set. So I don't understand why this isn't working. Here's the output when I make the request from the terminal (headers are the same from what was shown in the Chrome devtools).
$ http 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/26/Strychnine.svg/360px-Strychnine.svg.png'
HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Age, Date, Content-Length, Content-Range, X-Content-Duration, X-Cache, X-Varnish
Age: 6359
Connection: keep-alive
Content-Disposition: inline;filename*=UTF-8''Strychnine.svg.png
Content-Length: 11596
Content-Type: image/png
Date: Fri, 29 Dec 2017 21:00:31 GMT
Etag: 223fb180fc10db8693431b6ca88dd943
Last-Modified: Sun, 04 Sep 2016 09:13:24 GMT
Strict-Transport-Security: max-age=106384710; includeSubDomains; preload
Timing-Allow-Origin: *
Via: 1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4
X-Analytics: https=1;nocookies=1
X-Cache: cp1049 hit/4, cp2022 pass, cp4026 hit/4, cp4024 hit/3
X-Cache-Status: hit-front
X-Client-IP: 2606:6000:670c:f800:989:be22:e59d:3c3f
X-Object-Meta-Sha1Base36: 1xx5tvhafvp54zfrfx5uem0vazzuo1a
X-Timestamp: 1472980403.52438
X-Trans-Id: tx154e595e211c449d95b3d-005a469417
X-Varnish: 474505758 476375076, 160459070, 709465351 725460511, 931215054 920521958
So why isn't this working? Is something else required for my canvas not to be "tainted"?
回答1:
When you set src
on your image, the browser makes a request for the image. But at that point, you haven't yet set img.crossOrigin
. Move the img.crossOrigin
line above the img.src
line.
That fixes the tainted canvas problem, but you still won't get your URL. The request for the image is asynchronous. You're trying to draw to the canvas with an image that hasn't loaded yet. Move the rest of the code into a load
handler on your image and put the img.src
line at the end to kick the whole thing off:
const img = document.createElement('img');
img.crossOrigin = 'anonymous';
img.addEventListener('load', () => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
console.log(canvas.toDataURL('image/jpg'));
});
img.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/26/Strychnine.svg/360px-Strychnine.svg.png';
来源:https://stackoverflow.com/questions/48030496/tainted-html-canvas-even-with-cors-headers