Как исправить ошибку getImageData() Холст был испорчен данными перекрестного происхождения?

Мой код работает очень хорошо на моем localhost, но он не работает на сайте.

Я получил эту ошибку с консоли, для этой строки .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) - из URL поддомена

Ответ 1

Как уже говорили другие, вы "портите" холст, загружая его из домена перекрестного происхождения.

https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image

Однако вы можете предотвратить это, просто установив:

img.crossOrigin = "Anonymous";

Это работает, только если удаленный сервер устанавливает следующий заголовок соответствующим образом:

Access-Control-Allow-Origin "*"

Отличным примером этого является средство выбора файлов Dropbox при использовании опции "прямая ссылка". Я использую его на oddprints.com для перемещения изображений из URL- адреса удаленного изображения в Dropbox на свой холст, а затем отправляю данные изображений обратно на мой сервер. Все в JavaScript

Ответ 2

Я обнаружил, что мне пришлось использовать .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', '');

Ответ 3

Вы не сможете рисовать изображения с другого сервера на холст, а затем использовать getImageData. Это проблема безопасности, и полотно будет считаться "испорченным".

Будет ли работать для вас, чтобы сохранить копию изображения на ваш сервер с помощью PHP, а затем просто загрузить новое изображение? Например, вы можете отправить URL-адрес на PHP script и сохранить его на свой сервер, а затем вернуть новое имя файла в свой 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 script с некоторым 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 script и вычислить значение пикселя rgba на этой стороне. Я думаю, что есть хорошие библиотеки для выполнения такой обработки изображений в PHP.

Если вы хотите использовать этот подход, дайте мне знать, если вам нужна помощь в его реализации.

Ответ 4

Ваша проблема заключается в том, что вы загружаете внешнее изображение, то есть из другого домена. Это приводит к ошибке безопасности при попытке доступа к любым данным вашего контекста canvas.

Ответ 6

Я видел эту ошибку в Chrome когда тестировал свой код локально. Я перешел на Firefox и больше не вижу ошибки. Возможно, переключение на другой браузер - это быстрое решение.

Если вы используете решение, указанное в первом ответе, обязательно добавьте img.crossOrigin = "Anonymous"; сразу после объявления переменной img (например, var img = new Image();).

Ответ 7

Как матовый ожог говорит в его ответ, вам может потребоваться включить 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)

Ответ 8

При работе на локальном сервере добавь сервер

У меня была похожая проблема при работе на местном. Ваш 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.

Ответ 9

Сегодня я сталкиваюсь с той же проблемой и решаю ее с помощью кода.

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 code:

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)
}

как указано выше, и нет проблемы между доменами.

Ответ 10

У меня https:${image.getAttribute('src')} та же проблема, и для меня это сработало простым объединением https:${image.getAttribute('src')}