2012年7月6日金曜日

画像にsvgのfilterを掛けてcanvasに書き込むと

jpeg画像やpng画像についてsvgのfilter機能を施すと,ぼかしや色の変更等の様々な画像効果を簡単に得ることが出来る.この機能をcanvas要素に応用できないかと考えるのは自然なことだろう.しかしこれを実際に行うとなると意外な落とし穴が存在した.



処理フローとしては次の通り.
  1. ラスタ画像をロードし,dataスキーム形式に変換する
  2. 上記の画像データを含んだsvg文字列(<svg>・・・</img xlink:href="[元の画像]"></svg>,)を生成する.この時,内部のimg要素にfilter要素で画像効果を施しておく.
  3. このsvg文字列をもう一度dataスキーム形式に変換し,img要素に設定する.
  4. 上のimg要素をcanvasに書き込む.
  5. canvasからtoDataURL等のorigin-cleanフラグに関わるメソッドを実行する.
いずれも静的なリソース(svgファイル)を参照しているなら問題なさそうなケースに見える.
これをfirefox,chrome,operaのそれぞれで実行してみた.
  • firefoxの場合
    なんの問題もなく最後の処理まで実行可能だ.
  • chromeの場合
    1〜4までは正しく動作するが,5の処理においてエラーが発生する.
  • operaの場合
    1〜3までは正しく動作するが,4においてimg要素の内容が真っ白になってしまう.
このように,ブラウザごとにバラバラの動作となる. なぜこのような結果となるのか?この記事によれば,元来canvas要素はorigin-cleanフラグというセキュリティーを保持する機構を持っており,クロスドメインでの画像の混合は表示のみとなる.これによりスクリプトに依るスクリーン情報の詐取を防いでいるのだが,dataスキームに対する取扱いがバラバラなためにこのような事態になっているとのことだ.

今回試した例ではcanvasを描画する際に2つのdataスキームを経由しているが,firefoxではこれらが同一のドメインの描画として扱い,chrome(及びwebkit)では異なるドメインの描画として扱っているため,chromeでエラーが発生する結果となったのだ.(operaについてはエラーとしない方針なのかもしれない)※ここ憶測含む

先ほどの記事ではchromeの挙動をバグとして切り捨てているが,正直な所,firefoxの挙動も正しいのか判らない(個人的にはchromeの動作の方に分がある気がする.).従って将来的に動作しなくなりそうなコードは極力避けた方が良いということで,結論.

画像処理はcanvasからsvgへの一方向で行うべし.

0 件のコメント:

コメントを投稿