キャンバス画像getImageData,toDataURLのクロスドメイン問題の解決方法を説明する。
まず、画像サーバーにAccess-Control-Allow-Originを設定します。
例えば、Tencentはgtimg.com、Baiduはbdimg.com、あるいはTencent CloudやAli Cloudのサービスを利用するチームも多いようです。
メインページは別ドメインにあることが多く、キャンバス画像に対して getImageData() や toDataURL() の操作が必要な場合、クロスドメインの問題が出てきてしまい、レイヤーが複数になってしまうのです。
まず、第一段階として、画像サーバーにAccess-Control-Allow-Originの情報を設定する必要があります、例えば、以下のようなものです。
PHP が応答ヘッダーメッセージを追加する場合、* ワイルドカード文字は、任意のドメイン名を許可することを示します。
header("Access-Control-Allow-Origin: *");
または、ドメイン名を指定する。
header("Access-Control-Allow-Origin: www.zhangxinxu.com");
この時点で、ChromeにはAccess-Control-Allow-Origin関連のエラーメッセージは表示されませんが、他のクロスドメインエラーメッセージは表示されます。
次に、キャンバス画像getImageDataのクロスオリジン・クロスドメイン問題
クロスドメイン画像の場合、Webページで正しく表示できる範囲であれば、canvasのdrawImage()APIで描画することが可能です。しかし、さらに進んで getImageData() メソッドで画像の全ピクセル情報を取得しようとすると、ほとんどの場合エラーが発生します。
例として、以下のコードを使って、github上の自分のアバター画像の情報を取得します。
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var img = new Image();
img.onload = function () {
context.drawImage(this, 0, 0);
context.getImageData(0, 0, this.width, this.height);
};
img.src = 'https://avatars3.githubusercontent.com/u/496048?s=120&v=4';';
その結果、Chromeで以下のようなエラーが表示されました。
Uncaught DOMException: CanvasRenderingContext2D'で'getImageData'の実行に失敗しました。キャンバスがクロスオリジンデータで汚染されています。
Firefoxブラウザのエラーは。
SecurityErrorです。この操作は安全ではありません。
canvas.toDataURL()メソッドが使用された場合、報告されます。
HTMLCanvasElement'で'toDataURL'の実行に失敗しました。汚染されたキャンバスはエクスポートされない可能性があります。
実は原因は同じで、クロスドメインです。
では、この問題を解決する方法はあるのでしょうか?
crossOriginプロパティを試してみてはいかがでしょうか。
III. HTML crossOrigin属性によるリソースクロスドメイン問題の解決
HTML5では、<img>, <video>, <script> など、CORS(クロスオリジンリソース共有)に対応した属性を提供する要素があり、その提供属性の名称が crossOrigin 属性となります。
したがって、上記のクロスドメイン問題は、次のように処理することができます。
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var img = new Image();
img.crossOrigin = '';
img.onload = function () {
context.drawImage(this, 0, 0);
context.getImageData(0, 0, this.width, this.height);
};
img.src = 'https://avatars3.githubusercontent.com/u/496048?s=120&v=4';';
img.crossOrigin = ''を追加するだけで、ここでのJSコードは空の文字列を設定しますが、実際に機能するプロパティ値は匿名です。
crossOriginには、以下の2つの値を指定できます。
<テーブル キーワード 定義 匿名 その要素に対するクロスドメインリソースリクエストは、クレデンシャルフラグの設定を必要としない。 使用証明書 要素のクロスドメインリソースリクエストでは、credentials フラグを設定する必要があります。
ここで、crossOriginの属性値がuse-credentialsでない限り、'abc'のような文字を含む空文字列も含めてすべて匿名に解決されます。
例えば
img.crossOrigin = 'abc';
console.log(img.crossOrigin); // the result is 'anonymous'
もうひとつ、crossOrigin属性を持たないことと、crossOrigin="use-credentials"を設定することはどちらもデフォルトでクロスドメインエラーを報告しますが、性質が異なり、両者の間には大きな違いがあることに留意してください。
CrossOriginの互換性
IE11+ (IE Edge)、Safari、Chrome、Firefoxのブラウザに対応しています。IE9とIE10は、以下のスクリーンショットに示すように、セキュリティエラーSecurityErrorが報告されます。
IV. なぜcrossOrigin属性は、リソースのクロスドメイン問題を解決するのか?
crossOrigin=anonymousは、相手のサーバーに「匿名でない情報を持ってくる必要はない」と伝えるための相対的なものです。例えばクッキーとか、だから今のブラウザは間違いなく安全です。
誰かの家にドレスを取りに行くとしたら、crossOrigin=anonymousと相手に「私はドレスが欲しいだけで、他には何もいらない」と伝えるのと同じです。そうしないと、相手がドレスにバグを入れたりするかもしれないので、安全とは言えず、ブラウザがブロックしてしまうからです。
V. IE10のブラウザがcrossOriginをサポートしていない場合はどうなりますか?
画像を要求するとき、new Image()を直接経由するのではなく、ajaxとURL.createObjectURL()メソッドでカーブさせています。
コードはこのようになります。
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var url = URL.createObjectURL(this.response);
var img = new Image();
img.onload = function () {
// At this point you can use canvas to do whatever you want with the img
// ... code ...
// Remember to free up memory when you run out of images
URL.revokeObjectURL(url);
};
img.src = url;
};
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.send();
この方法はIE10だけでなく、もともとcrossOriginに対応していたすべてのブラウザでOKです。
Ajaxリクエストが1つ増えるだけで、うまくいくのです!
IEでは、リクエストされた画像が数千ピクセルと大きすぎる場合、画像の読み込みに失敗することがわかりました、ブロブサイズ制限を超えているのでしょう。
VI. 結論
同じような問題に遭遇した友人の助けになれれば幸いです。また、Scripting Houseをもっとサポートしてほしいです。
関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン