Bagaimana cara memperbaiki kesalahan getImageData () Kanvas telah dinodai oleh data cross-origin?

131

Kode saya berfungsi dengan baik di localhost saya tetapi tidak berfungsi di situs.

Saya mendapatkan kesalahan ini dari konsol, untuk baris ini .getImageData(x,y,1,1).data:

Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data. 

bagian dari kode saya:

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

Catatan: url gambar saya (src) berasal dari url subdomain

Erfan Safarpoor
sumber
8
Saya mendapatkan kesalahan ini bahkan ketika img.src adalah url relatif lokal: "img / foo.png" - jadi apa asal-usul silang ini?
Sanford Staab
Lihat stackoverflow.com/a/16218015/5175433 : "Chrome tidak menganggap file lokal yang berbeda berasal dari domain yang sama."
A_P

Jawaban:

116

Seperti orang lain katakan Anda "mencemari" kanvas dengan memuat dari domain asal silang.

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

Namun, Anda mungkin dapat mencegahnya hanya dengan mengatur:

img.crossOrigin = "Anonymous";

Ini hanya berfungsi jika server jauh menetapkan header berikut dengan tepat:

Access-Control-Allow-Origin "*"

The Dropbox pemilih file ketika menggunakan "link langsung" pilihan adalah contoh yang bagus dari ini. Saya menggunakannya di oddprints.com untuk membawa gambar dari url gambar dropbox jarak jauh, ke kanvas saya, dan kemudian mengirimkan data gambar kembali ke server saya. Semua dalam javascript

Matt terbakar
sumber
1
Ini berfungsi untuk memperbaiki kesalahan ini saat memuat gambar imgur ke jsfiddle.net
Travis J
3
bekerja untuk saya jika saya meletakkan crossorigin pertama kali kemudian mengatur sumber dan kemudian mengakses data onload
jones
2
Bagaimana jika itu file lokal, dan aplikasi Anda tidak menggunakan internet sama sekali? Seperti aplikasi tampilan web android dan gambar hanya di folder yang sama dengan file html. Ini tidak menyelesaikannya.
Curtis
44

Saya menemukan bahwa saya harus menggunakan .setAttribute('crossOrigin', '')dan harus menambahkan stempel waktu ke string kueri URL untuk menghindari respons 304 yang tidak memiliki Access-Control-Allow-Originheader.

Ini memberiku

var url = 'http://lorempixel.com/g/400/200/';
var imgObj = new Image();
imgObj.src = url + '?' + new Date().getTime();
imgObj.setAttribute('crossOrigin', '');
Kirby
sumber
3
Mencoba ini tanpa server pada file lokal memberikan: Akses ke Gambar di 'file: /// C: /.../img/colorPaletteCtrl.png? 1507058959277' from origin 'null' telah diblokir oleh kebijakan CORS: Respons tidak valid . Karena itu, 'nol' tidak diizinkan untuk diakses.
Sanford Staab
1
Cukup menggunakan imgObj.setAttribute('crossOrigin', '')diselesaikan untuk saya - terima kasih! img.crossOrigin = "Anonymous"berfungsi juga (seperti yang disebutkan di sini ). @SanfordStaab Browser memperlakukan file lokal sebagai berada pada domain yang berbeda, jika tidak, pemilik situs web dapat membaca file lokal Anda. Anda perlu meminta gambar dari domain yang sama, atau tajuk dalam menanggapi permintaan Anda perlu memberi tahu browser bahwa tidak apa-apa jika kode dari domain lain membaca file itu.
19

Anda tidak akan dapat menggambar gambar langsung dari server lain ke dalam kanvas dan kemudian gunakan getImageData. Ini masalah keamanan dan kanvas akan dianggap "ternoda".

Apakah ini akan berhasil bagi Anda untuk menyimpan salinan gambar ke server Anda menggunakan PHP dan kemudian hanya memuat gambar baru? Misalnya, Anda dapat mengirim URL ke skrip PHP dan menyimpannya ke server Anda, lalu mengembalikan nama file baru ke javascript Anda seperti ini:

<?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;

?>

Anda akan menggunakan skrip PHP dengan beberapa javascript ajax seperti ini:

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

Jika Anda menggunakan getImageDatakanvas setelah itu, itu akan berfungsi dengan baik.

Atau, jika Anda tidak ingin menyimpan seluruh gambar, Anda bisa meneruskan koordinat x & y ke skrip PHP Anda dan menghitung nilai rgba piksel di sisi itu. Saya pikir ada perpustakaan yang bagus untuk melakukan pemrosesan gambar semacam itu di PHP.

Jika Anda ingin menggunakan pendekatan ini, beri tahu saya jika Anda membutuhkan bantuan untuk mengimplementasikannya.

sunting-1: peeps menunjukkan bahwa skrip php terbuka dan memungkinkan internet untuk menggunakannya dengan jahat. ada sejuta cara untuk menangani ini, salah satu yang paling sederhana adalah semacam kebingungan URL ... saya rasa praktik-praktik php aman layak mendapatkan google yang terpisah; P

sunting-2: berdasarkan permintaan populer, saya telah menambahkan tanda centang untuk memastikan itu adalah gambar dan bukan skrip php (dari: PHP periksa apakah file adalah gambar ).

jaya
sumber
15
Sebagai tambahan - Memuat gambar dan skrip dari sistem file lokal, membuat masalah yang sama.
Guy Dafny
2
itu tidak aman seseorang dapat membanjiri server Anda dengan file besar menggunakan skrip php yang buruk
LAX1DUDE
1
@ LAX1DUDE jawaban ditingkatkan dengan pemeriksaan keamanan sederhana
jumpjack
1
berkat metode ini, dimungkinkan juga untuk mengirimkan gambar ke tesseract.js mesin OCR tanpa menggunakan node.js (cukup tambahkan panggilan ke Tesseract.recognize (img) dalam fungsi img.onload ().
jumpjack
1
Anda PERLU untuk memvalidasi nama file, jenis file / pantomim, lokasi & ukuran unggahan yang disediakan oleh pengguna. Kode ini rentan terhadap beberapa serangan. Saya akan meninggalkannya sebagai latihan untuk pembaca, tetapi saya percaya ini mungkin untuk mengunggah file .php ke root server web dengan kode ini.
hiburn8
4

Saya melihat kesalahan ini Chromesaat saya menguji kode saya secara lokal. Saya beralih ke Firefoxdan saya tidak melihat kesalahan lagi. Mungkin beralih ke browser lain adalah perbaikan cepat.

Jika Anda menggunakan solusi yang diberikan dalam jawaban pertama, maka pastikan Anda menambahkan img.crossOrigin = "Anonymous";tepat setelah Anda mendeklarasikan imgvariabel (misalnya. var img = new Image();).

Safwan
sumber
2

Masalah Anda adalah Anda memuat gambar eksternal, artinya dari domain lain. Ini menyebabkan kesalahan keamanan ketika Anda mencoba mengakses data konteks kanvas Anda.

kapak
sumber
ya, saya mendapatkan gambar dari subdomain unggah ... Apa yang harus saya lakukan?
Erfan Safarpoor
1
Yah Anda bisa menggunakan proxy untuk mengambil gambar Anda, proxy ini akan berada di domain yang sama dengan yang Anda jalankan kanvas Anda.
axelduch
1
Saya mengunggah gambar baru dari Komputer Saya & mencoba memuatnya di kanvas & saya mendapatkan kesalahan ini. Saya tidak menggunakan jenis gambar server apa pun.
Piyush Dholariya
komputer Anda dilihat oleh server tempat skrip berada (tetapi tidak dieksekusi) sebagai domain eksternal, karena gambar yang disalin ke kanvas dibuat di komputer Anda, tempat skrip sebenarnya dieksekusi.
jumpjack
2

Anda "mencemari" kanvas dengan memuat dari domain asal silang. Lihat artikel MDN ini:

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

srquinn
sumber
saya menambahkan <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> untuk htaccess semua domain tetapi tidak berfungsi!
Erfan Safarpoor
1
Peramban apa yang Anda uji? Dan pastikan Anda me-restart Apache.
srquinn
saya tidak dapat memulai kembali apache ... saya memiliki akun cpanel berbagi.
Erfan Safarpoor
2
Tidak dapat membantu Anda mengkonfigurasi pengaturan Apache Anda, maaf. Ini juga di luar ruang lingkup pertanyaan ini. Poskan masalah Anda tentang pengaturan Apache ke pertanyaan baru dan komunitas akan dengan senang hati membantu Anda di sana.
srquinn
1

Saat bekerja di lokal menambahkan server

Saya memiliki masalah serupa ketika bekerja di lokal. Anda url akan menjadi path ke file lokal misalnya file: ///Users/PeterP/Desktop/folder/index.html.

Harap dicatat bahwa saya menggunakan MAC.

Saya mengatasinya dengan menginstal http-server secara global. https://www.npmjs.com/package/http-server

Langkah:

  1. Instalasi global: npm install http-server -g
  2. Jalankan server: http-server ~/Desktop/folder/

PS: Saya berasumsi Anda telah menginstal node, jika tidak, Anda tidak akan mendapatkan perintah npm berjalan sangat jauh.

Anas
sumber
0

Seperti yang dikatakan matt burns dalam jawabannya , Anda mungkin perlu mengaktifkan CORS di server tempat gambar masalah di-host.

Jika servernya adalah Apache, ini dapat dilakukan dengan menambahkan cuplikan berikut (dari sini ) ke konfigurasi VirtualHost Anda atau .htaccessfile:

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

... jika menambahkannya ke VirtualHost, Anda mungkin perlu memuat ulang konfigurasi Apache juga (mis. sudo service apache2 reloadjika Apache berjalan di server Linux)

Nick F
sumber
0

Masalah saya sangat kacau sehingga saya hanya mengkodekan gambar base64 untuk memastikan tidak ada masalah CORS

papan bumsover
sumber
-2

Saya menemui masalah yang sama hari ini, dan menyelesaikannya dengan kode berikut.

kode 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>

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

kode seperti di atas, dan tidak ada masalah lintas-domain.

Karry
sumber
1
Nilai src masih merupakan sumber asal silang, jadi bagaimana cara menghindari masalah ini?
Loveen Dyall
Pendekatan ini berfungsi saat menjalankan file html lokal (tanpa server) seperti file: /// X: /htmlfile.html. Kebanyakan orang mengakhiri pernyataan mereka dengan ";". Apa gunanya pernyataan "var data = .."? Saya ingin PENJELASAN MENGAPA ini menghindari kesalahan "lintas domain". Tapi ya, terima kasih.
dcromley
double smart karry
Mari Selvan
1
@dcromley "Kebanyakan orang mengakhiri pernyataan mereka dengan;" Menggunakan titik koma tidak direkomendasikan sesuai standar. Titik koma hanya menambah lebih banyak pekerjaan, terlihat jelek, dan kode berfungsi sempurna tanpa mereka. Periksa github.com/standard/standard
madprops
1
@madprops developer.mozilla.org mengatakan "Aplikasi JavaScript terdiri dari pernyataan dengan sintaksis yang tepat. Pernyataan tunggal dapat menjangkau beberapa baris. Banyak pernyataan dapat terjadi pada satu baris jika setiap pernyataan dipisahkan oleh tanda titik koma. Ini bukan kata kunci , tetapi sekelompok kata kunci. " Jadi saya berada di fraksi "selalu gunakan". Aku bahkan tidak tahu ada faksi "tidak pernah". Saya berasumsi yang terakhir juga percaya bumi itu datar? (Hanya bercanda - terima kasih)
dcromley
-3

Saya mengalami masalah yang sama, dan bagi saya itu berhasil hanya dengan menyatukan https:${image.getAttribute('src')}

Livia Rett
sumber
tolong jelaskan apa yang Anda lakukan
Yehuda Schwartz