GetImageData () hatası nasıl düzeltilir Kanvas, çapraz kaynak verileriyle lekelenmiş?


131

Kodum localhost'umda çok iyi çalışıyor ancak sitede çalışmıyor.

Bu hatayı konsoldan aldım, bu satır için .getImageData(x,y,1,1).data:

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

kodumun bir parçası:

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

Not: resim url'm (src) bir alt etki alanı url'sinden


8
Bu hatayı img.src yerel bir göreli url olsa bile alıyorum: "img / foo.png" - peki bunun çapraz orijini nedir?
Sanford Staab

Stackoverflow.com/a/16218015/5175433 sayfasına bakın : "Chrome, farklı yerel dosyaların aynı alandan kaynaklandığını düşünmez."
A_P

Yanıtlar:


116

Başkalarının da söylediği gibi, çapraz bir alandan yükleyerek tuvali "lekeliyorsunuz".

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

Ancak, bunu basitçe ayarlayarak önleyebilirsiniz:

img.crossOrigin = "Anonymous";

Bu yalnızca uzak sunucu aşağıdaki üstbilgiyi uygun şekilde ayarlarsa çalışır:

Access-Control-Allow-Origin "*"

Dropbox dosya seçici "doğrudan bağlantı" seçeneğini kullanarak bu büyük bir örnektir. Bunu oddprints.com'da , uzak dropbox resim url'sindeki resimleri tuvalime taşımak için kullanıyorum ve ardından resim verilerini sunucuma geri gönderiyorum . Hepsi javascript'te


1
Bu, jsfiddle.net'e bir imgur resmi yüklerken bu hatayı düzeltmek için çalıştı
Travis J

3
önce crossorigin'i koyarsam, sonra kaynağı ayarlarsam ve sonra veri yüküne erişirsem benim için çalıştı
jones

2
Ya yerel bir dosyaysa ve uygulamanız interneti hiç kullanmıyorsa? Bir android webview uygulaması gibi ve görüntü html dosyasıyla aynı klasördedir. Bu onu çözmez.
Curtis

44

Üstbilginin .setAttribute('crossOrigin', '')bulunmadığı bir 304 yanıtından kaçınmak için URL'nin sorgu dizesine bir zaman damgası eklemem gerektiğini ve buna bir zaman damgası eklemem gerektiğini fark ettim Access-Control-Allow-Origin.

Bu bana verir

var url = 'http://lorempixel.com/g/400/200/';
var imgObj = new Image();
imgObj.src = url + '?' + new Date().getTime();
imgObj.setAttribute('crossOrigin', '');

3
Bunu yerel bir dosyada sunucu olmadan denemek şunlara neden olur: 'file: /// C: /.../img/colorPaletteCtrl.png? 1507058959277' kaynağından 'null' adresindeki Görüntüye erişim CORS politikası tarafından engellendi: Geçersiz yanıt . Bu nedenle 'boş' kaynağına erişime izin verilmiyor.
Sanford Staab

1
imgObj.setAttribute('crossOrigin', '')Benim için basitçe kullanarak çözdüm - teşekkürler! img.crossOrigin = "Anonymous"( burada bahsedildiği gibi) de çalışır . @SanfordStaab Tarayıcılar yerel dosyaları farklı bir etki alanında kabul eder, aksi takdirde web sitesi sahipleri yerel dosyalarınızı okuyabilir. Aynı etki alanından resimler istemeniz gerekir veya isteğinize yanıt olarak üstbilgiler, tarayıcıya diğer etki alanlarından gelen kodun bu dosyayı okumasının uygun olmadığını bildirmelidir.

19

Görüntüleri doğrudan başka bir sunucudan bir tuvale çizip sonra kullanamazsınız getImageData. Bu bir güvenlik sorunu ve tuval "kirli" olarak kabul edilecek.

Görüntünün bir kopyasını PHP kullanarak sunucunuza kaydetmeniz ve ardından yeni görüntüyü yüklemeniz işe yarar mı? Örneğin, URL'yi PHP betiğine gönderebilir ve sunucunuza kaydedebilir, ardından yeni dosya adını şu şekilde javascript'inize döndürebilirsiniz:

<?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 betiğini aşağıdaki gibi bir ajax javascript ile kullanırsınız:

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

Bundan getImageDatasonra tuval üzerinde kullanırsanız , iyi çalışır.

Alternatif olarak, görüntünün tamamını kaydetmek istemiyorsanız, x & y koordinatlarını PHP betiğinize aktarabilir ve pikselin o taraftaki rgba değerini hesaplayabilirsiniz. PHP'de bu tür görüntü işlemeyi yapmak için iyi kitaplıklar olduğunu düşünüyorum.

Bu yaklaşımı kullanmak istiyorsanız, uygulama konusunda yardıma ihtiyacınız olursa bana bildirin.

edit-1: peeps php betiğinin açığa çıktığını ve internetin potansiyel olarak kötü niyetli kullanmasına izin verdiğini belirtti. bunun üstesinden gelmenin milyonlarca yolu var, en basitlerinden biri bir çeşit URL gizlemedir ... güvenli php uygulamalarının ayrı bir google'ı hak ettiğini düşünüyorum; P

edit-2: popüler talep üzerine, bir php betiği değil de bir resim olduğundan emin olmak için bir kontrol ekledim (kaynak: PHP, dosyanın bir resim olup olmadığını kontrol et ).


15
Ek olarak - Yerel dosya sisteminden görüntü ve komut dosyasını yüklemek de aynı sorunu yaratır.
Guy Dafny

2
bu çok güvenli değil birisi php betiğini kullanarak kötü niyetli olarak sunucunuzu büyük dosyalara
boğabilir

1
@ LAX1DUDE yanıtı basit bir güvenlik kontrolü ile iyileştirildi
jumpjack

1
Bu yöntem sayesinde, node.js kullanmadan tesseract.js OCR motoruna bir görüntü aktarmak da mümkündür (img.onload () işlevinde Tesseract.recognize (img) çağrısını ekleyin.
jumpjack

1
Kullanıcılar tarafından sağlanan dosya adını, dosya / mime türünü, konumunu ve boyutunu doğrulamanız GEREKİR. Bu kod çeşitli saldırılara karşı savunmasızdır. Bunu okuyucuya bir alıştırma olarak bırakacağım, ancak .php dosyalarını bu kodla web sunucusunun köküne yüklemenin mümkün olduğuna inanıyorum.
hiburn8

4

ChromeKodumu yerel olarak test ederken bu hatayı görüyordum . GeçtimFirefox ve artık hatayı görmüyorum. Belki başka bir tarayıcıya geçmek hızlı bir çözümdür.

İlk cevapta verilen çözümü kullanıyorsanız, değişkeni img.crossOrigin = "Anonymous";tanımladıktan hemen sonra eklediğinizden emin olun img(örneğin var img = new Image();).


2

Sizin sorununuz, başka bir etki alanından harici bir görüntü yüklemenizdir. Bu, tuval içeriğinizin herhangi bir verisine erişmeye çalıştığınızda bir güvenlik hatasına neden olur.


evet, yükleme alt etki alanından resim alıyorum ... Ne yapmalıyım?
Erfan Safarpoor

1
Resminizi almak için bir proxy kullanabilirsiniz, bu proxy, tuvalinizi çalıştırdığınız alanla aynı etki alanında olacaktır.
axelduch

1
Bilgisayarımdan yeni bir resim yüklüyorum ve tuvale yüklemeye çalışıyorum ve bu hatayı alıyorum. Herhangi bir tür sunucu görüntüsü kullanmıyorum.
Piyush Dholariya

Tuvale kopyalanan görüntü, betiğin gerçekte yürütüldüğü bilgisayarınızda oluşturulduğundan, bilgisayarınız, betiğin bulunduğu (ancak yürütülemediği) sunucu tarafından harici bir etki alanı olarak görülür.
jumpjack

2

Çapraz bir etki alanından yükleyerek tuvali "lekeliyorsunuz". Şu MDN makalesine göz atın:

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 Header set Access- Control-Allow-Origin "*" env = IS_CORS </FilesMatch> </IfModule> </IfModule> tüm etki alanlarına htaccess ama çalışmıyor!
Erfan Safarpoor

1
Hangi tarayıcıda test ediyorsunuz? Ve Apache'yi yeniden başlattığınızdan emin olun.
srquinn

apache'yi yeniden başlatamıyorum ... paylaşılan cpanel hesabım var.
Erfan Safarpoor

2
Apache kurulumunuzu yapılandırmanıza yardımcı olamıyorum, üzgünüm. O da bu sorunun kapsamı dışındadır. Apache kurulumuyla ilgili sorunlarınızı yeni bir soruya gönderin ve topluluk size yardımcı olmaktan mutluluk duyacaktır.
srquinn

1

Yerel üzerinde çalışırken bir sunucu ekleyin

Yerelde çalışırken benzer bir sorun yaşadım. URL'niz yerel dosyanın yolu olacaktır, örneğin file: ///Users/PeterP/Desktop/folder/index.html.

Lütfen bir MAC üzerinde olduğumu unutmayın.

Global olarak http-server kurarak bunu aştım. https://www.npmjs.com/package/http-server

Adımlar:

  1. Global kurulum: npm install http-server -g
  2. Sunucuyu çalıştır: http-server ~/Desktop/folder/

Not: Düğümün kurulu olduğunu varsayıyorum, aksi takdirde npm komutlarını çok fazla çalıştırmayacaksınız.


0

Matt Burns'ün cevabında dediği gibi , sorunlu görüntülerin barındırıldığı sunucuda CORS'u etkinleştirmeniz gerekebilir.

Sunucu Apache ise, bu, aşağıdaki parçacığı ( buradan ) VirtualHost yapılandırmanıza veya bir .htaccessdosyaya ekleyerek yapılabilir :

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

... bir VirtualHost'a ekliyorsanız, muhtemelen Apache'nin yapılandırmasını da yeniden yüklemeniz gerekecektir (örn. sudo service apache2 reload , Apache bir Linux sunucusunda çalışıyorsa)


0

Sorunum o kadar karışıktı ki, CORS sorunu olamayacağından emin olmak için görüntüyü sadece base64 kodladım.


-2

Bugün aynı problemle karşılaşıyorum ve aşağıdaki kod ile çözüyorum.

HTML Kodu:

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

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

yukarıdaki gibi kod ve alanlar arası sorun yoktur.


1
Src değeri hala bir çapraz kaynak kaynağıdır, öyleyse bu sorunu nasıl önler?
Loveen Dyall

Bu yaklaşım, file: /// X: /htmlfile.html gibi yerel bir html dosyası (sunucusuz) çalıştırırken işe yarar. Çoğu insan ifadelerini ";" ile bitirir. "Var data = .." ifadesinin amacı nedir? Bunun "etki alanları arası" hatasını NEDEN engellediğine dair bir AÇIKLAMA istiyorum. Ama öyle, teşekkürler.
dcromley

double smart karry
Mari Selvan

1
@dcromley "Çoğu insan ifadelerini;" Standartlara göre noktalı virgül kullanılması önerilmez. Noktalı virgül daha fazla iş ekler, çirkin görünür ve kod onlar olmadan mükemmel çalışır. Github.com/standard/standard'ı
madprops

1
@madprops developer.mozilla.org "JavaScript uygulamaları uygun bir sözdizimine sahip ifadelerden oluşur. Tek bir ifade birden çok satıra yayılabilir. Her bir ifade noktalı virgülle ayrılmışsa tek bir satırda birden çok ifade oluşabilir. Bu bir anahtar kelime değildir , ancak bir anahtar kelime grubu. " Bu yüzden ben "her zaman kullan" grubundayım. "Asla" bir hizip olduğunu bile bilmiyordum. Sanırım ikincisi de dünyanın düz olduğuna inanıyor? (Şaka yapıyorum - teşekkürler)
dcromley

-3

Aynı sorunu yaşıyordum ve benim için basitçe birleştirerek işe yaradı https:${image.getAttribute('src')}


lütfen ne yaptığını açıkla
Yehuda Schwartz
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.