Как исправить ошибку getImageData() Холст был испорчен данными из разных источников?
Мой код работает очень хорошо на моем локальном хосте, но он не работает на сайте.
Я получил эту ошибку из консоли, для этой строки .getImageData(x,y,1,1).data
:
Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
часть моего кода:
jQuery.Event.prototype.rgb=function(){
var x = this.offsetX || (this.pageX - $(this.target).offset().left),y = this.offsetY || (this.pageY - $(this.target).offset().top);
if (this.target.nodeName!=="CANVAS")return null;
return this.target.getContext('2d').getImageData(x,y,1,1).data;
}
Примечание. URL-адрес моего изображения (src) взят из субдомена.
14 ответов
Как уже говорили другие, вы "портите" холст, загружая его из домена перекрестного происхождения.
https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image
Однако вы можете предотвратить это, просто установив:
img.crossOrigin = "Anonymous";
Это работает только в том случае, если удаленный сервер правильно устанавливает следующий заголовок:
Access-Control-Allow-Origin "*"
Отличным примером этого является средство выбора файлов Dropbox при использовании параметра "прямая ссылка". Я использую его на http://www.oddprints.com/ для перемещения изображений из URL- адреса удаленного изображения в Dropbox на свой холст, а затем отправляю данные изображений обратно на мой сервер. Все в яваскрипте:)
Я обнаружил, что мне пришлось использовать .setAttribute('crossOrigin', '')
и должен был добавить метку времени к строке запроса URL, чтобы избежать ответа 304 без Access-Control-Allow-Origin
заголовок.
Это дает мне
var url = 'http://lorempixel.com/g/400/200/';
var imgObj = new Image();
imgObj.src = url + '?' + new Date().getTime();
imgObj.setAttribute('crossOrigin', '');
Вы не сможете рисовать изображения непосредственно с другого сервера на холст, а затем использовать getImageData
, Это проблема безопасности, и холст будет считаться "испорченным".
Будет ли работать для вас, чтобы сохранить копию изображения на ваш сервер с помощью PHP, а затем просто загрузить новое изображение? Например, вы можете отправить URL-адрес в сценарий PHP и сохранить его на своем сервере, а затем вернуть новое имя файла в свой javascript следующим образом:
<?php //The name of this file in this example is imgdata.php
$url=$_GET['url'];
$img = file_get_contents($url);
$fn = substr(strrchr($url, "/"), 1);
file_put_contents($fn,$img);
echo $fn;
?>
Вы бы использовали скрипт PHP с некоторым javascript ajax, как это:
xi=new XMLHttpRequest();
xi.open("GET","imgdata.php?url="+yourImageURL,true);
xi.send();
xi.onreadystatechange=function() {
if(xi.readyState==4 && xi.status==200) {
img=new Image;
img.onload=function(){
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
}
img.src=xi.responseText;
}
}
Если вы используете getImageData
на холсте после этого все будет работать нормально.
В качестве альтернативы, если вы не хотите сохранять все изображение целиком, вы можете передать координаты x & y в ваш PHP-скрипт и вычислить значение rgba пикселя на этой стороне. Я думаю, что есть хорошие библиотеки для такой обработки изображений в PHP.
Если вы хотите использовать этот подход, дайте мне знать, если вам нужна помощь в его реализации.
При работе на локальном сервере добавь сервер
У меня была похожая проблема при работе на местном. Ваш URL будет путь к локальному файлу, например, file: ///Users/PeterP/Desktop/folder/index.html.
Обратите внимание, что я нахожусь на MAC.
Я обошел это, установив http-сервер по всему миру. https://www.npmjs.com/package/http-server
шаги:
- Глобальная установка:
npm install http-server -g
- Запустить сервер:
http-server ~/Desktop/folder/
PS: я предполагаю, что у вас установлен узел, в противном случае вы не будете слишком далеко запускать команды npm.
Моя проблема была настолько запутанной, что я просто закодировал изображение base64, чтобы убедиться, что не может быть никаких проблем с CORS
Я видел эту ошибку на Chrome
пока я тестировал свой код локально. Я перешел на Firefox
и я больше не вижу ошибки. Возможно, переключение на другой браузер - это быстрое решение.
Если вы используете решение, указанное в первом ответе, обязательно добавьте img.crossOrigin = "Anonymous";
сразу после того, как вы объявите img
переменная (например, var img = new Image();
).
УстановитьImage
хcrossOrigin
приписыватьAnonymous
.
let image = new Image();
// image.src = ...;
image.crossOrigin = `Anonymous`;
Ваша проблема в том, что вы загружаете внешнее изображение, то есть из другого домена. Это вызывает ошибку безопасности при попытке получить доступ к любым данным вашего контекста холста.
Вы "портите" холст, загружая его из домена перекрестного происхождения. Проверьте эту статью MDN:
https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image
обходное решение, преобразовать URL-адрес исходного изображения в данные Base64 и назначить img
например, используйте Axios
const getBase64 = async(url)=>{
try {
let image = await axios.get(url, { responseType: 'arraybuffer' });
let raw = Buffer.from(image.data).toString('base64');
return "data:" + image.headers["content-type"] + ";base64,"+raw;
} catch (error) {
console.log(error)
}
}
var image = new Image()
image.src=getBase64(url)
нет перекрестной зависимости от холста
Как говорит Мэтт Бернс в своем ответе, вам может потребоваться включить CORS на сервере, где размещены образы проблем.
Если сервер Apache, это можно сделать, добавив следующий фрагмент ( отсюда) в конфигурацию VirtualHost или .htaccess
файл:
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
<FilesMatch "\.(cur|gif|ico|jpe?g|png|svgz?|webp)$">
SetEnvIf Origin ":" IS_CORS
Header set Access-Control-Allow-Origin "*" env=IS_CORS
</FilesMatch>
</IfModule>
</IfModule>
... если вы добавите его в VirtualHost, вам, вероятно, потребуется перезагрузить конфигурацию Apache (например, sudo service apache2 reload
если Apache работает на сервере Linux)
вы можете преобразовать изображение в строку данных, так как используйте источник изображения вместо фактического источника изображения.
[https://www.base64-image.de/[1], чтобы преобразовать изображение в строку данных. Преобразуйте и скопируйте строковые данные с указанного выше веб-сайта. установите image.src = <copied_data_string>.
Сегодня я сталкиваюсь с той же проблемой и решаю ее по коду.
HTML-код:
<div style='display: none'>
<img id='img' src='img/iak.png' width='600' height='400' />
</div>
<canvas id='iak'>broswer don't support canvas</canvas>
JS код:
var canvas = document.getElementById('iak')
var iakImg = document.getElementById('img')
var ctx = canvas.getContext('2d')
var image = new Image()
image.src=iakImg.src
image.onload = function () {
ctx.drawImage(image,0,0)
var data = ctx.getImageData(0,0,600,400)
}
код, как указано выше, и нет междоменной проблемы.
У меня была та же проблема, и для меня это сработало, просто сцепив https:${image.getAttribute('src')}