2012年7月6日金曜日

jsziptoolsを使ってインラインsvgの内容をsvgzに変換する.

これまでの検証でインラインsvgのコードをjavascriptで取得するのはそれほど難しくない.それならば,これを更にsvgz形式に変換出来るんじゃなかろうか?と考え,色々と調べてみた.

svgzはファイル形式で説明するならテキストベースのsvgファイルをgzip形式で圧縮したものである.従って,javascriptによるgzip形式への圧縮が出来ればそれで終わりとなるはずだ.gzip圧縮そのものは標準規格であり,その実装としては様々なものが考えられるが,中でも有名なライブラリの一つにzlibがある.zlibのソースコードはcで書かれていてフリーソフトウェアとして一般に公開されているため,このzlibをjavascriptに移植するのが正攻法と言える.

一方,gzipが広範な分野で利用されている事を鑑みると,既に似たような事をしている方がいてもおかしくないので調べてみたところ,概ね下の3つあたりが引っかかってきた.(「javascript圧縮」と「javascrpt圧縮」が混ざって検索が色々と面倒だったのは秘密だ.)
  1. 高度な JavaScript 技集
    古くから公開されている圧縮・解凍ライブラリ.なお,zlib.jsは現在作成中とのこと.
  2. pure JavaScript の Zlib, Deflate 実装を作りました
    byte配列からpng画像ファイルを生成するライブラリ.内部で画像の圧縮をするためにzlibの機能を実装している.
  3. Jsziptools
    zip,gzip形式の圧縮・解凍ライブラリ.
ここでちょっと疑問が起こる.「svgはテキストだが,svgzはバイナリである」ことだ.javascriptでバイナリデータはどのように扱えば良いのだろうか?これには大体パターンがあって,次のようにしているようだ.
  • 圧縮アルゴリズム適用時は数値データの配列として扱う.
  • 1バイトデータ毎にString.fromCharCodeを使って文字列型に変換する.
  • 上の文字群を結合して1つの文字列データを取得する.
もちろん得られた文字列はそのままでは意味を持たないが,base64形式に変換することでdataスキーム形式としてa要素のhref属性や, img要素のsrc属性に設定することが出来る.
例)data:application/x-gzip;base64,[base64形式のバイナリデータ]
このa要素やimg要素を経由してjavascriptによる圧縮結果をブラウザ外部に取り出すことが可能となるのだ.

と,大体はこの流れで済むのだが,ここからが面倒だった.
  1. 高度な JavaScript 技集
    ライブラリにバグが存在する模様で,圧縮するファイルのサイズが大きくなると外部ツールによる解凍結果が壊れる.
  2. pure JavaScript の Zlib, Deflate 実装を作りました
    圧縮処理は為されるものの,png画像生成に特化しているため,gzipに必要となるヘッダーが付加されないため,生成したデータがsvgz形式として不正となる.
何れも特定の環境下でsvg画像に復元可能ではあったものの,確実性に欠けinkscape等のツールで開けなくなることから何らかの問題が発生していることが考えられる.(base64変換時に問題が発生している可能性も考えたが,そうではないらしい)いずれもライブラリ製作者の意図していない方法で使ってみたことが原因だろうが,正直どこに問題があるのか調査が難しい.

そこで Jsziptoolsである.このライブラリはhtml5で追加されたblobオブジェクトを用いて先ほどのようなバイナリ-文字列の不安定な相互変換を完全に隠蔽しており,使い方も明快だ.例を示す.

function getSVGZUrl(){
 var URL = window.URL || window.webkitURL;
 var svg = getSVGSource();
 var gzbuff = jz.gz.compress(jz.utils.stringToArrayBuffer(svg));
 var bb = new jz.BlobBuilder();
 bb.append(gzbuff);var d = bb.getBlob();
 return URL.createObjectURL(d);
}

インラインsvgのソースコードは,そのsvg要素を囲んでいるhtml要素のinnerHTMLプロパティを参照することで取り出すことが出来る.その際は若干スタンドアロンのsvgとして不足している部分(xlinkが落ちるとか,xml宣言が足りないとか)があるので,補うことを忘れずに.

最後の部分で生成されているのがblobオブジェクトへのリンク文字列(キー情報)で,この値をa要素のhref属性に設定することでjavascript内部のバイナリを直接ブラウザ外部に取り出すことが可能となる.無用な文字列形式への変換を経由しない分動作も軽快で,chromeで引っかかるdataスキームの長さ制限(経験的だが1MBを超過するとクラッシュする)も考慮せずに済む.

実際にsvgzを出力してみたが,inkscapeやその他のツールでも正しくグラフィックが展開された.どうやらgzip形式として正しいようだ.

このように非常に強力なライブラリなのだが,一点注意すべき点がある.現在利用可能な環境が狭いということだ.firefox,chrome(及びie10)とのことで,それ以外のブラウザでは動作しないのだ.現状でも基底となるオブジェクト群がベンダプレフィクス付きであり,将来的にapiが変更となる可能性も否定できない.

と言ったわけで,積極的に利用するにはちょっと時期尚早の感はあるが,早速potraceHtmlに組み込んでみた.本当に最近のブラウザは既にアプリケーションプラットフォーム化しているんだなぁと.

0 件のコメント:

コメントを投稿