
canvas を苛めていたら気づいたことがあったので書きます。(この記事は2011年5月現在の情報です。あなたがこの記事を読んでいる時点で、より新しくて良い方法が無いか確認して下さい)
canvas には、図形を描画する機能だけでなく、描かれている内容を読み取る機能があります。getImageData を使うと、canvas の内容をピクセル単位で読み取って画像処理をかけたりできます。また、toDataURL を使うと canvas の内容を Data URI として出力でき、サーバに送信したりできます。
しかし、この機能にはリスクがあります。例えば、悪意のあるページを開いただけで、社内SNSにしか公開していないあなたの顔写真を canvas 経由で抜き取られるかもしれません。そういう事が起きないように、他のサイトから読み込んだ画像が canvas に描画されている場合(以下、canvas が汚染されている と表現)は getImageData や toDataURL が使用禁止になり、呼び出すと例外が出ます。
ここまではよく知られている話。
しかし、同じサイトの画像であっても SVG は問答無用で「汚染」扱いになります。スクリプト内で完結している Data URI ですらダメ。 とにかく、canvas に SVG を描画した時点で読み取り禁止(図1)
理由はFrom SVG to Canvas and Backという文書に書いてあり、SVG は PNG や JPEG などと違い、外部のファイルを参照できるので、SVG ファイル自体が同じサイト内にあっても安心できないということ。
これでは、アプリケーションが getImageData や toDataURL を使っている場合は SVG をアセットとして使えないという事になってしまい、デザイナの顰蹙を買う事になります。
余談: Firefox はローカルディスク上で同じディレクトリ内にあるPNG/JPEGファイルも「汚染」扱いするようですが、一方で XmlHttpRequest は許可されており(mala さんの記事参照)、しかも XmlHttpRequest でバイナリファイルを読み込むテクニックが存在するので、canvas を封じても意味が無いように思えます(試してみたところ、XmlHttpRequest → drawImage → toDataURL でPNGが読めました)
先程のFrom SVG to Canvas and Back では、SVGElement にも toDataURL を実装し、さらにこれに外部を参照する要素を取り除いて「クリーンな」SVG をエクスポートする機能を付けて、このクリーンな SVG へのアクセスは許可しよう、と提案していますが、これは将来の話。今すぐ解決したい場合は canvg などの JS+Canvas で SVG をレンダリングするライブラリを使うことを薦めています。
実際に試してみたところ、確かに canvas を汚染せずに SVG をレンダリングできました(以下はIE9)
iPhone でも動きます