getImageData()エラーを修正する方法キャンバスはクロスオリジンデータによって汚染されていますか?


131

私のコードは私のローカルホストでうまく機能していますが、サイトでは機能していません。

コンソールからこのエラーを受け取りました、この行.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 2017年

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
これは、画像をjsfiddle.netにロードするときにこのエラーを修正するために機能しました
Travis J

3
私が最初にcrossoriginを置き、次にソースを設定し、次にオンロードのデータにアクセスした場合、私のために機能しました
ジョーンズ

2
ローカルファイルであり、アプリがインターネットをまったく使用しない場合はどうなりますか?Android WebViewアプリのように、画像はHTMLファイルと同じフォルダーにあります。これはそれを解決しません。
カーティス、

44

ヘッダーが.setAttribute('crossOrigin', '')ない304応答を回避するために、URLのクエリ文字列にタイムスタンプを追加する必要があることに気付きました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
ローカルファイルでサーバーなしでこれを試行すると、次の結果が得られます。「file:/// C:/.../img/colorPaletteCtrl.png?1507058959277」の画像へのアクセス元「null」がCORSポリシーによってブロックされました:無効な応答。したがって、オリジン 'null'はアクセスを許可されません。
Sanford Staab 2017年

1
imgObj.setAttribute('crossOrigin', '')私のために単にそれを解決して使用する-ありがとう!img.crossOrigin = "Anonymous"同様に動作します(ここで説明されています)。@SanfordStaabブラウザーはローカルファイルを別のドメインにあるものとして扱います。そうしないと、Webサイトの所有者がローカルファイルを読み取る可能性があります。同じドメインの画像をリクエストする必要があります。または、リクエストに対するレスポンスのヘッダーで、他のドメインのコードがそのファイルを読み取ってもよいことをブラウザに通知する必要があります。

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;

?>

次のようなajax javascriptでPHPスクリプトを使用します。

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:phpスクリプトが公開されており、インターネットが悪意を持って使用する可能性があることを指摘しました。これを処理するには100万通りの方法がありますが、最も簡単な方法の1つは、ある種のURLの難読化です...安全なphpの実践は、別のgoogleに値すると思います; P

edit-2:よくある要望により、phpスクリプトではなく画像であることを確認するためのチェックを追加しました(from:PHP check fileが画像かどうか)。


15
さらに、ローカルファイルシステムからイメージとスクリプトをロードすると、同じ問題が発生します。
Guy Dafny 14

2
これはあまり安全ではありません。誰かが悪意のあるphpスクリプトを使用してサーバーに大きなファイルを悪意を持ってあふれ
させる

1
@ LAX1DUDEの回答は、簡単なセキュリティチェックで改善されました
-Jumpjack

1
このメソッドのおかげで、node.jsを使用せずに画像をtesseract.js OCRエンジンに渡すことも可能です(img.onload()関数でTesseract.recognize(img)への呼び出しを追加するだけです
jumpjack

1
ユーザーが提供するアップロードのファイル名、ファイル/ MIMEタイプ、場所とサイズを検証する必要があります。このコードは、いくつかの攻撃に対して脆弱です。読者への演習として残しておきますが、このコードを使用して.phpファイルをWebサーバーのルートにアップロードすることは可能だと思います。
hiburn8

4

Chromeローカルでコードをテストしているときに、このエラーが発生しました。に切り替えましたがFirefox、エラーは表示されなくなりました。多分別のブラウザに切り替えることは簡単な修正です。

最初の回答で与えられたソリューションを使用している場合はimg.crossOrigin = "Anonymous";img変数を宣言した直後に追加するようにしてください(例:)var img = new Image();


2

問題は、別のドメインからの外部イメージをロードすることです。これにより、キャンバスコンテキストのデータにアクセスしようとすると、セキュリティエラーが発生します。


はい、アップロードサブドメインから画像を取得します...
Erfan Safarpoor 2014

1
プロキシを使用して画像を取得することもできます。このプロキシは、キャンバスを実行しているドメインと同じドメインにあります。
axelduch

1
マイコンピュータから新しい画像をアップロードして、キャンバスにロードしようとすると、このエラーが発生します。どのタイプのサーバーイメージも使用していません。
Piyush Dholariya、2015

キャンバスにコピーされたイメージは、スクリプトが実際に実行されるコンピューター上に作成されるため、コンピューターは、スクリプトが配置されている(ただし実行されていない)サーバーから外部ドメインとして認識されます。
ジャンプジャック

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ヘッダーセットアクセスを追加しました- Control-Allow-Origin "*" env = IS_CORS </ FilesMatch> </ IfModule> </ IfModule>は、すべてのドメインにhtaccessしますが機能しません。
Erfan Safarpoor 2014

1
どのブラウザでテストしていますか?そして、Apacheを再起動したことを確認してください。
srquinn 2014

Apacheを再起動できません... cpanelアカウントを共有しています。
Erfan Safarpoor 2014

2
申し訳ありませんが、Apacheのセットアップを構成することはできません。また、この質問の範囲外です。Apacheの設定に関する問題を新しい質問に投稿してください。コミュニティがお手伝いします。
srquinn 2014

1

ローカルで作業する場合はサーバーを追加します

ローカルで作業しているときに同様の問題がありました。あなたのURLはローカルファイルへのパスになります。例えば、file:///Users/PeterP/Desktop/folder/index.html。

私はMACを使用していることに注意してください。

私はhttp-serverをグローバルにインストールすることでこれを回避しました。 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

私の問題はめちゃくちゃだったので、CORSの問題が発生しないように、画像をbase64でエンコードしました


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

このアプローチは、file:/// X:/htmlfile.htmlのようなローカルhtmlファイル(サーバーなし)を実行するときに機能します。ほとんどの人はステートメントを「;」で終了します。「var data = ..」ステートメントの意味は何ですか?「クロスドメイン」エラーを回避する理由を説明してください。しかし、そうです、ありがとう。
dcromley 2017年

ダブルスマートkarry
マリSelvan

1
@dcromley「ほとんどの人はステートメントを;で終わります。」標準では、セミコロンの使用は推奨されていません。セミコロンは作業を追加するだけで見栄えが悪く、コードはそれらがなくても完全に機能します。小切手github.com/standard/standardを
madprops

1
@madprops developer.mozilla.orgは、「JavaScriptアプリケーションは適切な構文のステートメントで構成されています。1つのステートメントが複数行にまたがる場合があります。各ステートメントがセミコロンで区切られている場合、1行に複数のステートメントが発生することがあります。これはキーワードではありません。 、しかしキーワードのグループ。」だから私は「常に使用」派閥にいる。「決して」派閥が存在することすら知らなかった。後者も地球は平らだと思いますか?(冗談です-ありがとう)
dcromley

-3

私は同じ問題を抱えていました、そして私にとってそれは単に連結することによってうまくいきました https:${image.getAttribute('src')}


あなたがしたことを説明してください
Yehuda Schwartz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.