SVGのようなベクトルグラフィックスは図形を組み合わせて全体を構成していくため、どうしても輪郭のはっきりした画像になります。グラフや略図のようなものであれば問題ありませんが、凝ったイラストを描くにはどうしても限界があるでしょう。
こうした欠点を補うのが「SVGフィルタ」です。その名前のとおり、Photoshopなどのグラフィックツールによくあるぼかしや色変換などのフィルタをSVGの描画結果に適用する機能です。
SVGフィルタの使い方は、前回取り上げたグラデーションとよく似ています。filterタグを使ってあらかじめフィルタリングの内容を定義しておき、適用先の図形のfilter属性でそれを参照します。以下は単純なぼかし(ガウシアンブラー)フィルタを適用する例です。
このように、SVGフィルタではfilterタグ内に各フィルタに対応するタグを記述することで、適用する効果を選択します。ここで使っているfeGaussianBlurタグは、ガウシアンブラーを表現するタグです。stdDeviation属性はブラーの半径になります。
とても直感的ですが、1つ落とし穴があります。このままブラーの半径(stdDeviation属性の値)を大きくしていくと、下の例のように境界線のようなものが見えてしまいます。
これは、フィルタの効果範囲が限られていることによるものです。デフォルトでは、適用対象のバウンディングボックスの上下左右に10%のマージンを取った領域が効果範囲となり、その領域より外側にはフィルタの結果が描画されません。効果範囲を変更するには、filterタグのx、y、width、heightにそれぞれ効果範囲の左上座標と幅、高さを指定します。上の例も、それらの属性で効果範囲を上下左右20%に調整すると、正しく表示されます。
もう1つの注意点として、各フィルタのパラメータ(stdDeviation属性など)がユーザー座標系(適用先の図形が乗っている座標系)で定義されることです。通常はこの方が値の調整などがしやすいはずですが、図形のサイズを変更しても効果が調整されないという欠点があります。
フィルタのパラメータを適用先のオブジェクトのサイズに連動させるためには、filterタグのprimitiveUnits属性に「objectBoundingBox」を指定します。こうすると、各パラメータは図形の幅・高さを1とする座標系で解釈され、図形のサイズに効果が追従するようになります。
ガウシアンブラーを実現するfeGaussianBlurタグはすでに説明済みですが、同じようにフィルタリング方法を定義するためタグとして、以下のものが用意されています。
このリストを見てどう感じるでしょうか。「ああ、なるほどね」と納得されるのは、おそらく画像処理に関する知識のある方だと思います。多くの読者は、普段馴染みのあるフィルタが見当たらないことに戸惑ってしまうでしょう。
SVGでプリセットされているフィルタは、実はグラフィックツールなどに実装されているフィルタを構成するパーツのようなもので、「フィルタプリミティブ」と呼ばれています。複数のフィルタプリミティブを組み合わせることで、多彩な効果が実現できます。
それでは、複数のフィルタプリミティブを組み合わせる方法を見ていきましょう。まず、あるフィルタの出力に別のフィルタをかける、つまりフィルタプリミティブを直列につなぐには、単にfilterタグ内に複数のフィルタプリミティブを並べます。以下は、feColorMatrixによる色変換(色相変換)の後にガウシアンブラーをかける例です。
フィルタプリミティブを並列にかけてその結果を合成するには、いくつかの方法があります。まず、複数のフィルタの結果を単純に重ね合わせるには、feMergeタグを使います。以下は、feColorMatrixによる色相変換の結果と、アルファチャンネルの平行移動(feOffset)による影を重ねる例です。
※ 上記のコード例はfilterタグの内部のみを示しています。以下同様です。
feColorMatrixタグとfeOffsetタグには、result属性が記述されています。これは出力結果に名前を付けて、後続のフィルタプリミティブで参照できるようにするものです。
さらにfeOffsetタグ(およびfeMergeNodeタグ)には、in属性も記述されています。これはフィルタの入力元を指定する属性で、result属性で定義した名前か、もしくは以下のいずれかになります。
※ BackgroundImage、BackgroundAlphaを使うには、背景に含める図形とフィルタの対象の図形の両方を含むコンテナ要素(svg、g、useなど)にenable-background="new"を指定する必要があります。
feColorMatrixとfeOffsetの出力を1つに重ねているのがfeMergeタグです。子要素として記述したfeMergeNodeタグのin属性で指定された出力画像を、上から順番に重ねます。描画結果では、先に書いたfeMergeNodeタグの画像が奥になる点に注意してください。
単純に重ねるのではなく、Photoshopのレイヤーエフェクトのような効果を得られるのがfeBlendタグです。mode属性に以下のいずれかを指定すると、in、in2属性で指定された出力画像をその演算方法でブレンドします。
※ 上記の説明はあくまで概要なので、正確な計算は仕様書を参照してください。
normalモードはfeMergeと同じなので、他の4つのブレンド方法を実装したデモを以下に示します。
2つのフィルタリング結果に対して集合演算的な合成を行うのがfeCompositeタグです。使い方はfeBlendと似ており、in、in2属性で合成する出力画像を、operator属性で指定した方法で合成します。指定できる合成方法は以下のとおりです。
上記のうちoverとarithmeticを除いたものを実装したデモを以下に示します。arithmeticについてはライティングの説明で取り上げます。
SVGフィルタのちょっと変わった機能として、feDiffuseLighting、およびfeSpecularLightingフィルタプリミティブの使い方を取り上げます。Photoshopのレイヤースタイルにある「ベベルとエンボス」のような立体的なライティングを施すものです。
feDiffuseLightingは、入力画像をハイトマップ(アルファチャンネルに各ピクセルの高さを格納した画像)と考えて、拡散光によるライティング計算を実行します。拡散光とは、光沢のない質感をモデル化した計算方法で、布やゴムなどの表現に適しています。以下に使用例を示します。
先頭にあるfeGaussianBlurは、feDiffuseLightingの入力となるハイトマップを生成するものです。正確な計算とはいえませんが、輪郭をぼかしたシルエット画像をハイトマップに見立てるわけです。feDiffuseLightingタグの属性は、それぞれ以下の意味を持っています。
光源となるライトの情報は、feDiffuseLightingタグの子要素として記述します。ライトにはfeDistanceLight、fePointLight、feSpotLightの3種類がありますが、ここでは最も直感的なfePointLightを使用しています。属性はライトの座標です。
feDiffuseLightingの結果は、feCompositeのoperator="arithmetic"を利用して元の画像と合成します。合成方法がarithmeticの場合、feCompositeタグにはk1〜k4の4つの属性を指定でき、以下の計算式で合成を行います。
result = in*in2*k1 + in*k2 + in2*k3 + k4
拡散光の場合、物体の色とライティング結果は乗算するのが普通です。従って、k1の値は1にすべきです。これだけでは光の当たっていない部分が真っ黒になるので、k3に適当な値(ここでは0.5)を指定して、環境光をエミュレートします。k2、k4の項は不要なので0としてください。
feDiffuseLightingが光沢のない質感を表現するのに対して、プラスチックや金属のような鏡面反射光(いわゆるハイライト)を計算するのがfeSpecularLightingです。基本的な記述方法はfeDiffuseLightingと同じですが、指定すべき属性が若干異なります。以下に例を示します。
feSpecularLightingタグに指定されている属性のうち、specularConstantはdiffuseConstantと同じくライトの強さを示します。specularExponentは独自のもので、この値を大きくするとより金属的な、鋭いハイライトになります。その他の属性、およびライトの指定方法はfeDiffuseLightingと同じです。
鏡面反射光と物体の色の合成方法は加算が普通なので、feCompositeの属性はk2とk3が1で、それ以外が0になります。2つめのfeCompositeは元画像のアルファ値で結果をマスクするためのものです。加算合成では先頭のガウシアンブラーで外に漏れたアルファ値が残ってしまうので、その影響を取り除くために必要です。
現実のほとんどの物体では、拡散光と鏡面反射光の両方の性質を持ちます。そのため、feDiffuseLightingとfeSpecularLightingの両方を計算して結果を足し合わせれば、よりリアルなライティングになります。それを実装したのが以下の例です。
もっとも、SVGの主な守備範囲である二次元の図形描画やイラストの世界では、そこまでのリアリティが求められることは少ないかもしれません。このため、現実の用途ではfeSpecularLightingだけで済ませてしまうことも多いようです。その場合、specularExponentとspecularConstantの値を小さくすることで質感が拡散光に近づくことを覚えておくとよいでしょう。
SVGフィルタの解説の最後に、まだ取り上げていないフィルタプリミティブの説明を……といきたいところですが、それがなかなか難しいことです。SVGのフィルタプリミティブは前述のとおり低レベルな処理を行うものなので、望みの処理を記述するには画像処理の知識が必要です。そこで、少し裏技的な方法をご紹介しましょう。オープンソースのグラフィックツールであるInkscapeを利用します。
Inkscapeの最大の特徴は、ツール自体がSVGをベースに作られていることです。標準のファイルフォーマットがSVGであるだけでなく、ツール上でSVGのXMLコードを閲覧・編集したり、属性を直接変更することもできます。多数実装されているフィルタも、すべてSVGフィルタによって実現されています。
このため、Inkscape上で適当な図形にフィルタをかけて保存すれば(保存形式は「プレーンSVG」にしてください)、そのファイル中にSVGのフィルタ定義がそのまま含まれています。それをコピー&ペーストすれば、自分のSVGファイルでも同じ効果が利用できるというわけです。
また、InkscapeにはSVGフィルタを編集するエディタもあるので、フィルタプリミティブの効果を確かめつつ、オリジナルのフィルタを作れます。
フィルタ関連以外でも、InkscapeはSVGを扱う上でとても便利なツールです。公式サイトではWindowsやMac OS Xのバイナリも配布されており、容易にインストールできるので、ぜひ使ってみてください。
Copyright © ITmedia, Inc. All Rights Reserved.