Як виправити помилку 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.