Управление изображениями перекрестного происхождения с помощью HTML Canvas
Интерфейс HTML canvas
реализует ряд функций, связанных с безопасностью, которые предотвращают междоменные манипуляции, если это явно не разрешено исходным доменом.
Что это означает на практике? Чтобы иметь возможность читать данные пикселей изображения в другом домене, хост-сервер должен сначала объявить соответствующий заголовок Access-Control-Allow-Origin
. После этого потребитель сможет загрузить изображение на холст:
var img = new Image(), canvas = document.createElement("canvas"), ctx = canvas.getContext("2d"), src = "http://example.com/image.jpg";
img.onload = function() { canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); } img.src = src;
Однако, к сожалению, этого недостаточно. Если мы попытаемся вызвать canvas.toDataURL()
, браузер пожалуется и выдаст ошибку безопасности:
Uncaught SecurityError: Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported.
Что ?? Изображение уже отрисовано на холсте, поэтому данные должны быть там! Верно, но спецификация HTML5 представила еще один атрибут, связанный с безопасностью, в теге img
. Мы должны вручную установить атрибут crossOrigin
даже при использовании конструктора Image
, чтобы браузер мог считывать данные пикселей обратно с холста. Раздражает то, что мы не можем сделать это по умолчанию, поскольку есть два значения, которые могут быть установлены в зависимости от контекста: anonymous
, который извлекает изображения без отправки файлов cookie или заголовков аутентификации в сторонний домен, или use-credentials
, который отправляет файлы cookie и заголовки аутентификации по запросу.
Итак, лучше всего проверять всякий раз, когда источник является перекрестным, и устанавливать атрибут в соответствии с вашими потребностями:
var img = new Image(), canvas = document.createElement("canvas"), ctx = canvas.getContext("2d"), src = "http://example.com/image.jpg";
img.onload = function() { canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); console.log(canvas.toDataUrl());
} // check if //domain.com or http://domain.com is a different origin if (/^([\w]+\:)?\/\//.test(src) && src.indexOf(location.host) === -1) {img.crossOrigin = "anonymous"; // or "use-credentials" } img.src = src;