二つの変換方向
本ツールは,「SVGからPNGへの変換」および「ラスタ画像からSVGへの変換」という二つの異なるベクトル・ラスタ間の相互変換機能を備えています.ユーザーインターフェース上ではこれら二つのモードがタブによって明確に区別されており,利用者は目的に応じて処理の方向を選択します.
ファイル入力においては,OSの標準的なダイアログを経由するファイル選択,または指定された領域へのドラッグアンドドロップによる読み込みに対応しています.一方,SVGのソースコードを直接テキストエリアに貼り付けて描画させるようなUIは実装されておらず,あくまでファイルオブジェクトをFileReaderによって読み込む方式に限定されています.
データの解析と各種描画処理は,入力されたファイルをブラウザ内のメモリ空間に展開し,JavaScriptを介してDOM APIやCanvas APIを操作することによって行われます.変換対象のファイルが外部のサーバーに送信されることはなく,ファイルの展開からピクセル情報の取得,最終的なBlobオブジェクトの生成に至る一連の変換プロセスは利用者のブラウザ内でのみ実行されます.
処理の進捗や結果は,一時的に生成されたオブジェクトURLを通じてプレビュー領域に即座に表示されます.「SVGからPNG」と「画像からSVG」のそれぞれのモードは独立した状態管理(ReactのState)を保持しており,SVGの文字列データ,基準寸法,ラスタ画像のファイル参照などは各モード固有の変数として格納されます.
タブを切り替えても入力状態は維持されますが,別URLの更新によって無関係なプレビューが交差することはありません.
SVG寸法と倍率
SVGファイルをPNG画像へとラスタライズする際,最初に行われるのが元となるベクター画像の基準寸法の決定です.DOMParserを用いて読み込んだSVG文字列を解析し,ルートのsvg要素から幅(width)と高さ(height)の属性値を取得します.この際,数値に「px」が付与されている場合や単位のない純粋な数値表現であれば正常な寸法として解釈されますが,cmや%など表示環境に依存する相対的・物理的な単位の換算は行われません.
幅や高さが直接指定されていない,あるいは数値としてパースできない場合,ツールはフォールバックとしてviewBox属性に記載された4つの値から後者2つの寸法を抽出します.どちらからも有効な正の数値が得られなかった場合には,縦横300pxを暗黙のデフォルト値として扱います.
基準寸法が決定した後,利用者は出力時の解像度倍率を1,2,4,8倍の選択肢から指定できます.初期状態では2倍に設定されており,この倍率と基準寸法を乗算して出力予定寸法が算出され,小数点以下は丸め処理されます.このスケール機能はCanvasの描画サイズを拡大するものであり,元の画像やテキストの品質自体を改善する機能ではありません.
また,ブラウザの描画負荷による負荷を抑えるため,出力寸法には上限が設けられています.計算された出力予定寸法の一辺が8192pxを超える場合,または総画素数が16,777,216を超える場合にはアラートが表示され,処理が停止される仕組みとなっています.
PNGの透過と描画制約
SVGからPNGへの変換プロセスは,ブラウザが提供するHTML5のCanvas APIに依存して実行されます.パースされたSVG文字列は,MIMEタイプを「image/svg+xml」として設定したBlobに変換され,そこから生成されたURLがImageオブジェクトのソースとして割り当てられます.
Imageオブジェクトのロードが完了すると,前章で算出された出力寸法のCanvasが用意され,まずclearRectメソッドを用いてCanvas領域全体のピクセル情報が完全に消去されます.これにより,背景が透明な状態が初期化され,その上にSVGの内容がdrawImageメソッドによって転写されるため,元SVGの透明部分をPNGの透明部分として出力することが可能になります.
しかし,この描画プロセスにはブラウザの仕様に起因する制約が存在します.SVGコード内に外部ドメインの画像ファイルへの参照が含まれている場合や,Webフォントを読み込んでいる場合,リソースの解決タイミング等の問題によってCanvas上にレンダリングされず,欠けた状態で画像が出力されることがあります.
また,SVGの構文に致命的なエラーが含まれている場合,Imageオブジェクトの読み込み自体が失敗し,描画不可能のアラートが表示されます.変換が成功した場合でも失敗した場合でも,リソースの消費を防ぐため,読み込み用に作成された一時的なオブジェクトURLは即座にrevokeObjectURLによって破棄される実装となっています.
画像を縮小画素へ展開
もう一方の変換モードである「画像からSVGへの変換」では,JPEG,PNG,WebP,GIFといったブラウザで標準的に読み込み可能な画像を対象とします.利用者が画像ファイルを選択すると,それをCanvas上に描画してピクセルごとのRGBAデータを抽出する前処理が行われます.この際,元の画像サイズがそのまま処理されるわけではなく,「トレース解像度上限」というパラメータに基づく縮小が行われます.
トレース解像度上限は,スライダーを用いて32から256の範囲(16刻み)で指定でき,初期値は128に設定されています.読み込んだ画像の幅または高さのいずれかがこの上限値を超えている場合,元の縦横比を維持したまま,長辺が指定された上限値に一致するように縮小計算が行われます.短辺の長さは1以上の整数値に丸められ,この縮小された寸法を持つ一時的なCanvasに対して画像が描画されます.
この処理は,後続のピクセル解析ループの試行回数を物理的に減らし,計算対象を減らすための処置です.あくまでピクセルデータを格子状の矩形要素へ変換するためのベースとなる画像情報を生成する工程であり,高度な輪郭抽出アルゴリズムを用いて滑らかな曲線を描画したり,無損失で変換したりする目的ではありません.元の解像度が高い実写画像であっても,強制的にこの解像度上限の枠内に収められた画素データとして扱われます.
横rectと透明度の近似
解像度が調整されたCanvasからgetImageDataによって一次元配列化されたRGBAデータを取得した後,ツールは独自のランレングス方式でSVG要素を生成します.色境界の輪郭を検出しpath要素を用いるのではなく,画像のピクセルを左から右へと走査し,rect要素の連続として表現します.
走査の際,対象ピクセルのアルファ値が10未満である場合,わずかな不透明度があっても指定の閾値で省略され,SVG要素の描画対象から除外されます.一方,描画対象となるピクセルについては,隣接する右側のピクセルとの色情報の比較が行われます.RGBの各値が完全に一致し,かつアルファ値の差が10未満の近似範囲内に収まっている場合,それらは同一の連続した色と判定されます.
この連続が途切れるまで水平方向に走査を進め,まとめられた長さを幅とする単一のrect要素が生成されます.
生成されるrect要素の塗りの色は,rgb(R,G,B)形式の文字列として記述されます.さらに,ピクセルが完全な不透明(アルファ値255)でない場合には,fill-opacity属性が追加されます.この際の透明度は,アルファ値(0〜255)を255で除算したうえで,toFixed(2)を用いて小数点以下2桁の文字列にフォーマットされ(例:0.85),半透明な状態を近似的に表現します.
縦方向への連結は行われないため,出力コードは水平ラインごとのrect群で構成されます.
保存結果と容量の判断
画像からSVGへの変換処理が完了すると,生成されたrect要素群を包含するSVG文字列が構築されます.この際,SVGのルート要素のwidthおよびheight属性には元画像が持っていた本来のピクセルサイズが記述され,viewBox属性には縮小格子として用いたトレース後の寸法が指定されます.
これにより,ブラウザ上で表示した際には,粗い描画結果が元画像のサイズに拡大されて表示される構造となります.生成されたSVGコードはBlobに変換され,ダウンロード用のURLが発行されます.
このピクセルベクター化手法は,ドット絵のような同色が水平に連続しやすい画像に対しては少数のrect要素で表現できるため有効ですが,写真のようなグラデーションやノイズが多く含まれる画像を入力した場合は,ほぼ1ピクセルごとに新しいrect要素が生成されます.結果として,出力されるSVGファイルのテキスト容量が,元の画像のファイル容量を大きく上回る可能性があります.
ツール側では小容量化を保証する機能は持っていません.
操作におけるメモリ管理として,新しいファイルが読み込まれたり,トレース処理が実行されたりした場合には,Reactのクリーンアップ処理が働き,以前に発行されていた古いプレビュー用URLは直ちに解放されます.変換に失敗した場合や新素材を読み込んだタイミングで旧結果を破棄することで,旧プレビュー参照を解放しています.メモリの完全消去を保証するものではありません.