Come correggere l'errore getImageData () La tela è stata contaminata da dati di origine incrociata?


131

Il mio codice funziona molto bene sul mio localhost ma non funziona sul sito.

Ho ricevuto questo errore dalla console, per questa riga .getImageData(x,y,1,1).data:

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

parte del mio codice:

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

Nota: il mio URL immagine (src) proviene da un URL sottodominio


8
Ricevo questo errore anche quando img.src è un URL relativo locale: "img / foo.png" - quindi cos'è l'origine incrociata?
Sanford Staab,

Consulta stackoverflow.com/a/16218015/5175433 : "Chrome non considera che i diversi file locali provengano dallo stesso dominio".
A_P

Risposte:


116

Come altri hanno già detto che stai "contaminando" la tela caricando da un dominio di origini incrociate.

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

Tuttavia, potresti essere in grado di impedirlo semplicemente impostando:

img.crossOrigin = "Anonymous";

Funziona solo se il server remoto imposta correttamente la seguente intestazione:

Access-Control-Allow-Origin "*"

Il selettore di file Dropbox quando si utilizza l'opzione "collegamento diretto" ne è un ottimo esempio. Lo uso su oddprints.com per eseguire l'hoover delle immagini dall'URL dell'immagine della casella personale remota nella mia tela e quindi inviare nuovamente i dati dell'immagine nel mio server. Tutto in javascript


1
Questo ha funzionato per correggere questo errore quando si caricava un'immagine imgur in jsfiddle.net
Travis J,

3
lavorato per me se ho messo crossorigin fonte prima poi set e quindi accedere ai dati OnLoad
jones

2
Cosa succede se si tratta di un file locale e la tua app non utilizza affatto Internet? Come un'app webview per Android e l'immagine si trova nella stessa cartella del file html. Questo non lo risolve.
Curtis,

44

Ho scoperto che dovevo usare .setAttribute('crossOrigin', '')e ho dovuto aggiungere un timestamp alla stringa di query dell'URL per evitare una risposta 304 priva Access-Control-Allow-Origindell'intestazione.

Questo mi dà

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

3
Provare questo senza un server su un file locale dà: L'accesso all'immagine in 'file: /// C: /.../img/colorPaletteCtrl.png? 1507058959277' dall'origine 'null' è stato bloccato dalla politica CORS: risposta non valida . L'origine 'null' non è quindi consentita l'accesso.
Sanford Staab,

1
Semplicemente usando imgObj.setAttribute('crossOrigin', '')risolto per me - grazie! img.crossOrigin = "Anonymous"funziona anche (come menzionato qui ). I browser @SanfordStaab considerano i file locali come appartenenti a un dominio diverso, altrimenti i proprietari dei siti Web potrebbero leggere i file locali. Devi richiedere immagini dello stesso dominio, oppure le intestazioni nella risposta alla tua richiesta devono dire al browser che va bene per il codice di altri domini leggere quel file.

19

Non sarai in grado di disegnare le immagini direttamente da un altro server in un'area di disegno e quindi utilizzarle getImageData. È un problema di sicurezza e la tela sarà considerata "contaminata".

Funzionerebbe per te salvare una copia dell'immagine sul tuo server usando PHP e quindi caricare la nuova immagine? Ad esempio, potresti inviare l'URL allo script PHP e salvarlo sul tuo server, quindi restituire il nuovo nome file al tuo javascript in questo modo:

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

?>

Utilizzeresti lo script PHP con alcuni javascript ajax come questo:

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

Se lo usi getImageDatasulla tela dopo, funzionerà benissimo.

In alternativa, se non si desidera salvare l'intera immagine, è possibile passare le coordinate x & y allo script PHP e calcolare il valore rgba del pixel su quel lato. Penso che ci siano buone librerie per fare quel tipo di elaborazione delle immagini in PHP.

Se vuoi usare questo approccio, fammi sapere se hai bisogno di aiuto per implementarlo.

edit-1: peeps ha sottolineato che lo script php è esposto e consente a Internet di utilizzarlo potenzialmente in modo dannoso. ci sono milioni di modi per gestirlo, uno dei più semplici è una sorta di offuscamento dell'URL ... credo che le pratiche di php sicure meritino un google separato; P

edit-2: a grande richiesta, ho aggiunto un segno di spunta per assicurarmi che sia un'immagine e non uno script php (da: controllo PHP se il file è un'immagine ).


15
Inoltre, il caricamento dell'immagine e dello script dal file system locale comporta lo stesso problema.
Guy Dafny,

2
non è molto sicuro qualcuno potrebbe inondare maliziosamente il tuo server con file di grandi dimensioni usando lo script php che sarebbe male
LAX1DUDE

1
@ Risposta LAX1DUDE migliorata con un semplice controllo di sicurezza
jumpjack

1
grazie a questo metodo è anche possibile passare un'immagine al motore OCR tesseract.js senza usare node.js (basta aggiungere la chiamata a Tesseract.recognize (img) nella funzione img.onload ().
jumpjack

1
È NECESSARIO convalidare il nome del file, il tipo di file / mime, la posizione e la dimensione dei caricamenti forniti dagli utenti. Questo codice è vulnerabile a numerosi attacchi. Lo lascerò come esercizio per il lettore, ma credo che sia possibile caricare file .php sulla radice del server web con questo codice.
hiburn8,

4

Stavo vedendo questo errore Chromementre stavo testando il mio codice localmente. Sono passato a Firefoxe non vedo più l'errore. Forse passare a un altro browser è una soluzione rapida.

Se stai usando la soluzione fornita nella prima risposta, assicurati di aggiungere img.crossOrigin = "Anonymous";subito dopo aver dichiarato la imgvariabile (ad es. var img = new Image();).


2

Il tuo problema è che carichi un'immagine esterna, ovvero da un altro dominio. Ciò provoca un errore di sicurezza quando si tenta di accedere a qualsiasi dato del contesto del canvas.


sì, ricevo l'immagine dal sottodominio del caricamento ... Cosa devo fare?
Erfan Safarpoor,

1
Bene, potresti usare un proxy per recuperare la tua immagine, questo proxy si troverebbe sullo stesso dominio di quello su cui stai eseguendo il tuo canvas.
axelduch,

1
Sto caricando una nuova immagine da Risorse del computer e provo a caricarla su tela e visualizzo questo errore. Non sto usando alcun tipo di immagine del server.
Piyush Dholariya,

il tuo computer viene visto dal server in cui si trova lo script (ma non eseguito) come dominio esterno, poiché l'immagine copiata nell'area di disegno viene creata sul tuo computer, dove lo script viene effettivamente eseguito.
Jumpjack,

2

Stai "contaminando" la tela caricando da un dominio di origini incrociate. Dai un'occhiata a questo articolo MDN:

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


ho aggiunto <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> per accedere a tutti i domini ma non funziona!
Erfan Safarpoor,

1
In quale browser stai testando? E assicurati di aver riavviato Apache.
srquinn,

non riesco a riavviare apache ... ho un account cpanel condiviso.
Erfan Safarpoor,

2
Spiacenti, non posso aiutarti a configurare la tua configurazione di Apache. È anche fuori dal campo di applicazione di questa domanda. Pubblica i tuoi problemi relativi alla configurazione di Apache a una nuova domanda e la community sarà felice di aiutarti.
srquinn,

1

Quando lavori su locale aggiungi un server

Ho avuto un problema simile quando lavoravo su locale. L'URL sarà il percorso del file locale, ad esempio il file: ///Users/PeterP/Desktop/folder/index.html.

Si prega di notare che sono su un MAC.

Ho risolto il problema installando http-server a livello globale. https://www.npmjs.com/package/http-server

passi:

  1. Installazione globale: npm install http-server -g
  2. Esegui server: http-server ~/Desktop/folder/

PS: Presumo che tu abbia un nodo installato, altrimenti non otterrai comandi npm molto lontani.


0

Come dice matt burns nella sua risposta , potrebbe essere necessario abilitare CORS sul server in cui sono ospitate le immagini problematiche.

Se il server è Apache, questo può essere fatto aggiungendo il seguente frammento (da qui ) alla configurazione di VirtualHost o a un .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>

... se lo aggiungi a VirtualHost, probabilmente dovrai ricaricare anche la configurazione di Apache (es. sudo service apache2 reloadse Apache è in esecuzione su un server Linux)


0

Il mio problema era così incasinato che ho solo codificato in base64 l'immagine per garantire che non potessero esserci problemi CORS


-2

Oggi incontro lo stesso problema e lo risolvo con il codice seguente.

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

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

codice come sopra e non esiste alcun problema tra domini.


1
Il valore src è ancora una fonte di origine incrociata, quindi come si evita il problema?
Loveen Dyall,

Questo approccio funziona quando si esegue un file html locale (nessun server) come file: /// X: /htmlfile.html. Molte persone terminano le loro dichiarazioni con ";". Qual è il punto dell'istruzione "var data = .."? Vorrei una SPIEGAZIONE DEL PERCHÉ questo evita l'errore "interdominio". Ma grazie.
Dcromley,

double smart karry
Mari Selvan

1
@dcromley "Molte persone finiscono le loro dichiarazioni con;" L'uso dei punti e virgola non è raccomandato secondo gli standard. I punti e virgola aggiungono altro lavoro, sembrano brutti e il codice funziona perfettamente senza di essi. Controlla github.com/standard/standard
madprops

1
@madprops developer.mozilla.org dice "Le applicazioni JavaScript sono costituite da istruzioni con una sintassi appropriata. Una singola istruzione può estendersi su più righe. Possono verificarsi più istruzioni su una singola riga se ogni istruzione è separata da un punto e virgola. Questa non è una parola chiave , ma un gruppo di parole chiave ". Quindi sono nella fazione "usa sempre". Non sapevo nemmeno che ci fosse una fazione "mai". Presumo che quest'ultimo creda anche che la terra sia piatta? (
Sto

-3

Stavo avendo lo stesso problema, e per me ha funzionato semplicemente concatenando https:${image.getAttribute('src')}


per favore, spiega cosa hai fatto
Yehuda Schwartz,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.