Как исправить ошибку 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

шаги:

  1. Глобальная установка: npm install http-server -g
  2. Запустить сервер: 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')}

Другие вопросы по тегам