Як виправити помилку getImageData () Полотно було пошкоджено даними перехресного походження?


131

Мій код дуже добре працює на мій 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-адреси субдомену


8
Я отримую цю помилку навіть тоді, коли img.src є місцевим відносним URL-адресом: "img / foo.png" - тож, що стосується перехресного походження?
Sanford Staab

Див. Stackoverflow.com/a/16218015/5175433 : "Chrome не вважає, що різні локальні файли можна отримувати з одного домену."
A_P

Відповіді:


116

Як говорили інші, ви "підфарбовуєте" полотно, завантажуючи з домену хрестового походження.

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

Однак ви можете запобігти цьому, просто встановивши:

img.crossOrigin = "Anonymous";

Це працює лише в тому випадку, якщо віддалений сервер встановить наступний заголовок належним чином:

Access-Control-Allow-Origin "*"

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


1
Це допомогло виправити цю помилку під час завантаження зображення imgur у jsfiddle.net
Travis J

3
працював для мене , якщо я ставлю crossorigin перший то набір джерел , а потім доступ до даними OnLoad
Джоунс

2
Що робити, якщо це локальний файл, а ваш додаток взагалі не використовує Інтернет? Як і Android-додаток для веб-перегляду, і зображення знаходиться просто в тій же папці, що і файл HTML. Це не вирішує.
Кертіс

44

Я виявив, що мені потрібно було використовувати .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
Спробу цього без локального сервера в локальному файлі дає: Доступ до зображення у файлі '//: C: /.../img/colorPaletteCtrl.png? 1507058959277' from origin 'null' був заблокований політикою CORS: Недійсна відповідь . Таким чином, джерело "null" не має доступу.
Санфорд Штаб

1
Просто використовуючи imgObj.setAttribute('crossOrigin', '')вирішене для мене це - дякую! img.crossOrigin = "Anonymous"працює також (про що тут говорилося ). Браузери @SanfordStaab вважають, що локальні файли знаходяться на іншому домені, інакше власники веб-сайтів можуть читати ваші локальні файли. Вам потрібно запитати зображення з того самого домену, або заголовки у відповіді на ваш запит повинні повідомити браузеру, що добре, щоб код з інших доменів читав цей файл.

19

Ви не зможете малювати зображення безпосередньо з іншого сервера на полотні, а потім використовувати getImageData. Це питання безпеки, і полотно буде вважатися "заплямованим".

Чи вдасться вам зберегти копію зображення на сервері за допомогою PHP, а потім просто завантажити нове зображення? Наприклад, ви можете надіслати URL у скрипт PHP і зберегти його на своєму сервері, а потім повернути нове ім'я файлу у ваш javascript таким чином:

<?php //The name of this file in this example is imgdata.php

  $url=$_GET['url'];

  // prevent hackers from uploading PHP scripts and pwning your system
  if(!@is_array(getimagesize($url))){
    echo "path/to/placeholderImage.png";
    exit("wrong file type.");
  }

  $img = file_get_contents($url);

  $fn = substr(strrchr($url, "/"), 1);
  file_put_contents($fn,$img);
  echo $fn;

?>

Ви б використовували сценарій PHP з деяким ajax javascript таким:

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.

Якщо ви хочете скористатися цим підходом, повідомте мене, чи потрібна вам допомога в його здійсненні.

edit-1: peeps вказує на те, що скрипт php відкритий і дозволяє Інтернету потенційно його використовувати зловмисно. Є мільйон способів впоратися з цим, один з найпростіших - це якась обтурація URL-адрес ... я вважаю, що безпечні практики PHP заслуговують на окремий google; P

edit-2: на вимогу населення, я додав чек, щоб переконатися, що це зображення, а не php-скрипт (від: перевірка PHP чи файл є зображенням ).


15
Крім того - завантаження зображення та сценарію з локальної файлової системи створює таку ж проблему.
Гай Дафні

2
це не дуже безпечно, хтось може зловмисно затопити ваш сервер великими файлами, використовуючи скрипт php, що було б погано
LAX1DUDE

1
@ LAX1DUDE відповідь покращилася простою перевіркою безпеки
jumpjack

1
завдяки цьому методу можна також передати зображення в двигун OCR tesseract.js без використання node.js (просто додайте виклик Tesseract.recognize (img) у функції img.onload ().
jumjack

1
Вам потрібно підтвердити ім’я файлу, тип файлу / mime, місцезнаходження та розмір завантажень, наданих користувачами. Цей код вразливий до декількох атак. Я залишу це як вправу для читача, але я вважаю, що можливо завантажувати .php файли до кореня веб-сервера з цим кодом.
hiburn8

4

Я бачив цю помилку під Chromeчас тестування свого коду локально. Я перейшов Firefoxі більше не бачу помилки. Можливо, перехід на інший веб-переглядач - це швидке виправлення.

Якщо ви використовуєте рішення, наведене в першій відповіді, то переконайтеся, що ви додали img.crossOrigin = "Anonymous";відразу після оголошення оголошень imgзмінної (наприклад, var img = new Image();).


2

Ваша проблема полягає в тому, що ви завантажуєте зовнішнє зображення, тобто з іншого домену. Це викликає помилку безпеки під час спроби отримати доступ до будь-яких даних вашого полотна.


так, я отримую зображення з піддомену завантаження ... Що робити?
Ерфан Сафарпур

1
Ну, ви можете використовувати проксі-сервер для отримання свого зображення, цей проксі-сервер буде в тому ж домені, що і той, на якому ви працюєте з полотном.
axelduch

1
Я завантажую нове зображення з "Мій комп'ютер" і намагаюся завантажити його на полотно, і я отримую цю помилку. Я не використовую жодного типу зображення сервера.
Піюш Доларія

Ваш комп'ютер розглядається сервером, де знаходиться сценарій (але не виконується) як зовнішній домен, оскільки зображення, скопійоване на полотно, створюється на вашому комп'ютері, де фактично виконується сценарій.
стрибок

2

Ви "підфарбовуєте" полотно, завантажуючи з домену хрестового походження. Перегляньте цю статтю MDN:

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


я додав <IfModule mod_setenvif.c> <IfModule mod_headers.c> <FilesMatch "\. (cur | gif | ico | jpe? g | png | svgz? | webp) $"> SetEnvIf Origin ":" IS_CORS Набір заголовків Access- Control-Allow-Origin "*" env = IS_CORS </FilesMatch> </IfModule> </IfModule> для htaccess усіх доменів, але не працює!
Ерфан Сафарпур

1
У якому браузері ви тестуєте? І переконайтеся, що ви перезапустили Apache.
srquinn

я не можу перезапустити apache ... у мене є аккаунт cpanel.
Ерфан Сафарпур

2
Не можу допомогти вам налаштувати налаштування Apache, вибачте. Це також виходить за межі цього питання. Повідомте свої проблеми щодо налаштування Apache на нове запитання, і громада буде рада допомогти вам там.
srquinn

1

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

У мене було подібне питання під час роботи над місцевими. У вашому URL-адресі буде шлях до локального файлу, наприклад, файл: ///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.


0

Як говорить у своїй відповіді матовий опік , можливо, вам потрібно буде включити 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)


0

Моя проблема була настільки розгублена, що я просто base64 закодував зображення, щоб переконатися, що проблем із CORS не може бути


-2

Я зустрічаюся з тією ж проблемою сьогодні, і вирішувати її слід за кодом.

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

код, як вище, і немає міждоменної проблеми.


1
Значення src все ще є джерелом перехресного походження, тож як це уникнути проблеми?
Loveen Dyall

Цей підхід працює при запуску локального html-файлу (без сервера), такого як файл: /// X: /htmlfile.html. Більшість людей закінчують свої заяви на ";". У чому сенс заяви "var data = .."? Я хотів би пояснити, Чому це дозволяє уникнути помилки "домен". Але це, дякую.
dcromley

подвійний розумний каррі
Марі Селван

1
@dcromley "Більшість людей закінчують свої заяви;" Використання крапки з комою не рекомендується відповідно до стандартів. Точки з комою просто додають більше роботи, виглядають некрасиво, і код ідеально працює без них. Перевірте github.com/standard/standard
madprops

1
@madprops developer.mozilla.org говорить: "Програми JavaScript складаються з висловлювань із відповідним синтаксисом. Один оператор може охоплювати декілька рядків. Кілька висловлювань можуть виникати в одному рядку, якщо кожне твердження розділено крапкою з комою. Це не ключове слово , але група ключових слів. " Тож я перебуваю у фракції "Використовуй завжди". Я навіть не знав, що існує фракція "ніколи". Я припускаю, що останні також вважають, що земля плоска? (Просто жартую - дякую)
dcromley

-3

У мене було те саме питання, і для мене це працювало просто об'єднанням https:${image.getAttribute('src')}


поясніть, будь ласка, що ви зробили
Єгуда Шварц
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.