Wie behebe ich den Fehler getImageData ()? Die Zeichenfläche wurde durch Ursprungsdaten beschädigt.

131

Mein Code funktioniert auf meinem localhost sehr gut, aber auf der Site nicht.

Ich habe diesen Fehler von der Konsole für diese Zeile erhalten .getImageData(x,y,1,1).data:

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

Teil meines Codes:

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

Hinweis: Meine Bild-URL (src) stammt aus einer Subdomain-URL

Erfan Safarpoor
quelle
7
Ich erhalte diesen Fehler auch dann, wenn es sich bei img.src um eine lokale relative URL handelt: "img / foo.png" - was ist also ein Cross-Origin?
Sanford Staab
Siehe stackoverflow.com/a/16218015/5175433 : "Chrome berücksichtigt nicht, dass verschiedene lokale Dateien von derselben Domain stammen."
A_P

Antworten:

116

Wie andere gesagt haben, "beschmutzen" Sie die Leinwand, indem Sie sie aus einer Domäne mit unterschiedlichen Ursprüngen laden.

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

Möglicherweise können Sie dies jedoch verhindern, indem Sie einfach Folgendes einstellen:

img.crossOrigin = "Anonymous";

Dies funktioniert nur, wenn der Remote-Server den folgenden Header entsprechend festlegt:

Access-Control-Allow-Origin "*"

Die Dropbox-Dateiauswahl bei Verwendung der Option "Direkter Link" ist ein gutes Beispiel dafür. Ich verwende es auf oddprints.com , um Bilder von der Remote-Dropbox-Bild-URL in meine Zeichenfläche zu speichern und die Bilddaten dann wieder an meinen Server zu senden. Alles in Javascript

matte Verbrennungen
quelle
1
Dies funktionierte, um diesen Fehler beim Laden eines Imgur-Bildes in jsfiddle.net zu beheben
Travis J
3
hat für mich funktioniert, wenn ich zuerst crossorigin gesetzt habe, dann die Quelle festgelegt habe und dann auf Daten beim Laden zugegriffen habe
jones
2
Was ist, wenn es sich um eine lokale Datei handelt und Ihre App das Internet überhaupt nicht nutzt? Wie bei einer Android Webview App befindet sich das Bild im selben Ordner wie die HTML-Datei. Das löst es nicht.
Curtis
44

Ich stellte fest, dass ich .setAttribute('crossOrigin', '')einen Zeitstempel verwenden und an die Abfragezeichenfolge der URL anhängen musste, um zu vermeiden, dass einer 304-Antwort der Access-Control-Allow-OriginHeader fehlt .

Das gibt mir

var url = 'http://lorempixel.com/g/400/200/';
var imgObj = new Image();
imgObj.src = url + '?' + new Date().getTime();
imgObj.setAttribute('crossOrigin', '');
Kirby
quelle
3
Wenn Sie dies ohne Server in einer lokalen Datei versuchen, erhalten Sie: Zugriff auf Image unter 'file: /// C: /.../img/colorPaletteCtrl.png? 1507058959277' from origin 'null' wurde durch die CORS-Richtlinie blockiert: Ungültige Antwort . Origin 'null' ist daher kein Zugriff gestattet.
Sanford Staab
1
Einfach mit imgObj.setAttribute('crossOrigin', '')gelöst für mich - danke! img.crossOrigin = "Anonymous"funktioniert auch (wie hier erwähnt ). @ SanfordStaab-Browser behandeln lokale Dateien als auf einer anderen Domain befindlich, andernfalls könnten Websitebesitzer Ihre lokalen Dateien lesen. Sie müssen Bilder von derselben Domain anfordern, oder die Header in der Antwort auf Ihre Anfrage müssen dem Browser mitteilen, dass Code aus anderen Domains diese Datei lesen kann.
19

Sie können keine Bilder direkt von einem anderen Server in eine Zeichenfläche zeichnen und dann verwenden getImageData. Es ist ein Sicherheitsproblem und die Leinwand wird als "verdorben" betrachtet.

Würde es für Sie funktionieren, eine Kopie des Images mit PHP auf Ihrem Server zu speichern und dann einfach das neue Image zu laden? Sie können beispielsweise die URL an das PHP-Skript senden und auf Ihrem Server speichern und dann den neuen Dateinamen wie folgt an Ihr Javascript zurückgeben:

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

?>

Sie würden das PHP-Skript mit einem Ajax-Javascript wie dem folgenden verwenden:

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

Wenn Sie danach getImageDataauf der Leinwand verwenden, funktioniert es einwandfrei.

Wenn Sie nicht das gesamte Bild speichern möchten, können Sie alternativ x & y-Koordinaten an Ihr PHP-Skript übergeben und den rgba-Wert des Pixels auf dieser Seite berechnen. Ich denke, es gibt gute Bibliotheken für diese Art der Bildverarbeitung in PHP.

Wenn Sie diesen Ansatz verwenden möchten, lassen Sie mich wissen, wenn Sie Hilfe bei der Implementierung benötigen.

edit-1: Peeps wiesen darauf hin, dass das PHP-Skript verfügbar ist und das Internet es möglicherweise böswillig verwenden kann. Es gibt eine Million Möglichkeiten, damit umzugehen. Eine der einfachsten ist eine Art URL-Verschleierung. Ich denke, sichere PHP-Praktiken verdienen ein separates Google; P.

edit-2: Auf vielfachen Wunsch habe ich eine Prüfung hinzugefügt, um sicherzustellen, dass es sich um ein Bild und nicht um ein PHP-Skript handelt (von: PHP-Prüfung, ob die Datei ein Bild ist ).

Jaya
quelle
15
Als Ergänzung - Das Laden des Bildes und des Skripts aus dem lokalen Dateisystem verursacht das gleiche Problem.
Guy Dafny
2
Das ist nicht sehr sicher. Jemand könnte Ihren Server mit dem PHP-Skript böswillig mit großen Dateien überfluten, was schlecht wäre
LAX1DUDE
1
@ LAX1DUDE Antwort verbessert mit einer einfachen Sicherheitsüberprüfung
Jumpjack
1
Dank dieser Methode ein Bild zu tesseract.js OCR - Engine übergibt es auch möglich ist node.js ohne Verwendung (nur um den Anruf zu Tesseract.recognize (img) in img.onload () Funktion hinzufügen.
jumpjack
1
Sie MÜSSEN den Dateinamen, den Datei- / MIME-Typ, den Speicherort und die Größe der von Benutzern bereitgestellten Uploads überprüfen. Dieser Code ist anfällig für mehrere Angriffe. Ich überlasse es dem Leser als Übung, aber ich glaube, es ist möglich, mit diesem Code .php-Dateien in das Stammverzeichnis des Webservers hochzuladen.
hiburn8
4

Ich habe diesen Fehler gesehen, Chromeals ich meinen Code lokal getestet habe. Ich habe zu gewechselt Firefoxund sehe den Fehler nicht mehr. Vielleicht ist der Wechsel zu einem anderen Browser eine schnelle Lösung.

Wenn Sie die in der ersten Antwort angegebene Lösung verwenden, stellen Sie sicher, dass Sie diese img.crossOrigin = "Anonymous";unmittelbar nach der Deklaration der imgVariablen hinzufügen (z. B. var img = new Image();).

Safwan
quelle
2

Ihr Problem ist, dass Sie ein externes Image laden, dh von einer anderen Domain. Dies führt zu einem Sicherheitsfehler, wenn Sie versuchen, auf Daten Ihres Canvas-Kontexts zuzugreifen.

Axelduch
quelle
Ja, ich bekomme ein Bild von der Upload-Subdomain ... Was mache ich?
Erfan Safarpoor
1
Nun, Sie könnten einen Proxy verwenden, um Ihr Bild abzurufen. Dieser Proxy befindet sich in derselben Domäne wie die, auf der Sie Ihre Zeichenfläche ausführen.
Axelduch
1
Ich lade ein neues Bild von meinem Computer hoch und versuche, es auf Leinwand zu laden. Ich erhalte diesen Fehler. Ich verwende kein Server-Image.
Piyush Dholariya
Ihr Computer wird vom Server, auf dem sich das Skript befindet (aber nicht ausgeführt wird), als externe Domäne angezeigt, da das in die Zeichenfläche kopierte Bild auf Ihrem Computer erstellt wird, auf dem das Skript tatsächlich ausgeführt wird.
Jumpjack
2

Sie "beschmutzen" die Leinwand, indem Sie sie aus einer Domain mit unterschiedlichen Ursprüngen laden. Lesen Sie diesen MDN-Artikel:

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

srquinn
quelle
Ich habe <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 </ FileMatch> </ IfModule> </ IfModule>, um auf alle Domänen zuzugreifen, aber nicht zu funktionieren!
Erfan Safarpoor
1
In welchem ​​Browser testen Sie? Und stellen Sie sicher, dass Sie Apache neu gestartet haben.
Srquinn
Ich kann Apache nicht neu starten ... Ich habe ein freigegebenes Cpanel-Konto.
Erfan Safarpoor
2
Ich kann Ihnen leider nicht bei der Konfiguration Ihres Apache-Setups helfen. Es ist auch außerhalb des Rahmens dieser Frage. Veröffentlichen Sie Ihre Probleme bezüglich des Apache-Setups in einer neuen Frage, und die Community hilft Ihnen gerne weiter.
Srquinn
1

Wenn Sie lokal arbeiten, fügen Sie einen Server hinzu

Ich hatte ein ähnliches Problem bei der Arbeit an lokalen. Ihre URL wird der Pfad zur lokalen Datei sein, z. B. Datei: ///Users/PeterP/Desktop/folder/index.html.

Bitte beachten Sie, dass ich auf einem MAC bin.

Ich habe dies umgangen, indem ich den http-Server global installiert habe. https://www.npmjs.com/package/http-server

Schritte:

  1. Globale Installation: npm install http-server -g
  2. Server ausführen: http-server ~/Desktop/folder/

PS: Ich gehe davon aus, dass Sie einen Knoten installiert haben, sonst werden Sie npm-Befehle nicht sehr weit ausführen.

Anas
quelle
0

Wie Matt Burns in seiner Antwort sagt , müssen Sie möglicherweise CORS auf dem Server aktivieren, auf dem die Problembilder gehostet werden.

Wenn der Server Apache ist, können Sie dazu das folgende Snippet (von hier ) entweder zu Ihrer VirtualHost-Konfiguration oder zu einer .htaccessDatei hinzufügen :

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

... wenn Sie es einem VirtualHost hinzufügen, müssen Sie wahrscheinlich auch die Konfiguration von Apache neu laden (z. B. sudo service apache2 reloadwenn Apache auf einem Linux-Server ausgeführt wird).

Nick F.
quelle
-2

Ich treffe heute das gleiche Problem und löse es durch den folgenden Code.

HTML Quelltext:

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

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

Code wie oben, und es gibt kein domänenübergreifendes Problem.

Karry
quelle
1
Der src-Wert ist immer noch eine Ursprungsquelle. Wie kann das Problem dadurch vermieden werden?
Loveen Dyall
Dieser Ansatz funktioniert, wenn eine lokale HTML-Datei (kein Server) wie file: /// X: /htmlfile.html ausgeführt wird. Die meisten Leute beenden ihre Aussagen mit ";". Was ist der Sinn der Anweisung "var data = .."? Ich möchte eine Erklärung, warum dies den "domänenübergreifenden" Fehler vermeidet. Aber danke.
Dcromley
Double Smart Karry
Mari Selvan
1
@dcromley "Die meisten Leute beenden ihre Aussagen mit;" Die Verwendung von Semikolons wird gemäß den Standards nicht empfohlen. Semikolons fügen einfach mehr Arbeit hinzu, sehen hässlich aus und der Code funktioniert perfekt ohne sie. Überprüfen Sie github.com/standard/standard
madprops
1
@madprops developer.mozilla.org sagt: "JavaScript-Anwendungen bestehen aus Anweisungen mit einer geeigneten Syntax. Eine einzelne Anweisung kann mehrere Zeilen umfassen. Mehrere Anweisungen können in einer einzelnen Zeile auftreten, wenn jede Anweisung durch ein Semikolon getrennt ist. Dies ist kein Schlüsselwort , aber eine Gruppe von Schlüsselwörtern. " Also bin ich in der "Use Always" -Fraktion. Ich wusste nicht einmal, dass es eine "nie" -Fraktion gibt. Ich nehme an, letztere glauben auch, dass die Erde flach ist? (Nur ein Scherz - danke)
Dcromley
-3

Ich hatte das gleiche Problem, und für mich funktionierte es durch einfaches Verketten https:${image.getAttribute('src')}

Livia Rett
quelle
Bitte erklären Sie, was Sie getan haben
Yehuda Schwartz