PerfectVector
著者: Irene Kim2 分で読める

SVGのアルファしきい値:透明度を明確に切り替える

feFuncAでSVGのアルファを明確なしきい値で切り替えます。既知のPNGピクセルでdiscreteとtableを比較し、穴の保持と不透明な白が残る理由を確認します。

目次

アルファのしきい値を 0.5 にするには、feComponentTransfer と <feFuncA type="discrete" tableValues="0 1"/> を使います。入力アルファが 0.5 未満なら透明になり、0.5 以上なら不透明になります。RGBの変換を恒等写像のままにしたい場合は、RGBの関数を省略します。

このフィルターは描画されるアルファを変えるもので、元の図形の構造は変えません。アルファが 1 の白いピクセルは、不透明な色付きピクセルと同じようにしきい値を通過するため、不透明な白背景は除去できません。また、SVGに埋め込まれたPNGはラスター画像のままです。

しきい値を選ぶ前に既知の元ピクセルを比較する

私たちは、アルファが段階的に変わる部分、透明な正方形の穴、不透明な白い部分、値を制御した6つの色見本を持つ小さな8ビットRGBA PNGを作成しました。このテストの各SVGは、同じPNGバイト列を1つのimage要素に埋め込んでいます。フィルターなし、discrete、補間tableの3種類で異なるのはフィルター設定だけです。

以下の市松模様はSVGの外側にある周囲のページの背景です。画像のアルファチャンネルの一部に見せかけているのではなく、透明な部分を見えるようにしています。

同じ元のRGBA PNGを、フィルターなし、discreteによるアルファしきい値、補間tableで実際にSVG描画して比較。白い部分が残り、下には既知のアルファ値の測定結果が表示されています
discrete版は低アルファのピクセルを除き、残すピクセルを不透明にします。同じ0 1を使ったtable版は、測定したアルファ値を維持します。3つとも元のPNGを1つの画像として含み、パスは0個です。

このページでは実際のSVG各版を読み込み、ブラウザーのcanvasに描画して、6つの色見本の内部を測定しました。出力アルファのバイト値は次のとおりです。

入力PNGのアルファバイト値フィルターなしの出力discrete 0 1table 0 1
0000
6464064
1271270127
128128255128
192192255192
255255255255

正規化したアルファ値は、これらのバイト値を 255 で割った値です。そのため 127/255 は 0.5 より少し小さく、128/255 は少し大きくなります。このサンプルは数学的なしきい値を挟んでいます。8ビットPNGのバイト値は、ちょうど 0.5 を表現できません。

元画像の穴は、どの版でもアルファ 0 と測定されました。白い部分は、どの版でも 255 でした。これは値を制御した今回の例での観察結果であり、任意の図形でしきい値処理後も必要な細部がすべて残るという主張ではありません。

アルファに変換を適用する

中心となるフィルターは短い記述です。

<filter id="alpha" filterUnits="userSpaceOnUse"
  x="0" y="0" width="320" height="240">
  <feComponentTransfer in="SourceGraphic">
    <feFuncA type="discrete" tableValues="0 1"/>
  </feComponentTransfer>
</filter>

画像に filter="url(#alpha)" を指定して適用します。このサンプルのフィルター領域は、320 × 240 の元画像とビューポート全体を覆います。無関係なファイルにこの寸法をそのまま写すのではなく、自分の図形に合う境界を使ってください。

MDNのfeFuncAリファレンスでは、これを feComponentTransfer 内のアルファ変換関数としています。component-transferのリファレンスでは、チャンネルごとの値の変換と、アルファを事前乗算していない色値に対する計算を説明しています。

現在のFilter Effects仕様では、指定されていないチャンネル関数は恒等写像になります。このマークアップは feFuncR、feFuncG、feFuncB を省略し、アルファの変換関数だけを変えています。ただし、背景上で見える色まで同じになるという意味ではありません。アルファが変われば、合成後の見た目も変わります。

元のPNGを含む完全なテスト例を実行する

次の自己完結したSVGを alpha-test.svg として保存し、ブラウザーで開いてください。data URLには、値を制御して作った元のPNGが含まれています。table版を比較するには、type="discrete" だけを type="table" に変えます。フィルターなしの版と比較するには、画像のfilter属性を除きます。ページの背景を色付きや市松模様にすると、透明な領域を確認しやすくなります。

<svg xmlns="http://www.w3.org/2000/svg" width="320" height="240" viewBox="0 0 320 240">
<defs><filter id="alpha" filterUnits="userSpaceOnUse"
  x="0" y="0" width="320" height="240">
  <feComponentTransfer in="SourceGraphic">
    <feFuncA type="discrete" tableValues="0 1"/>
  </feComponentTransfer>
</filter></defs>
<image href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAADwCAYAAABxLb1rAAAJ6ElEQVR4nO3UVexsZxXG4eLBnRXcIVD3tKey66krENwhuEPQHjTFneAOwR2CM2hw6ql7m3rx4If3kgsCf+ierpk9z5c89+/6Ln4b1bphI4BV1D4AoEv7AIAu7QMAurQPAOjSPgCgS/sAgC7tAwC6tA8A6NI+AKBL+wCALu0DALq0DwDo0j4AoEv7AIAu7QMAurQPAOjSPgCgS/sAgC7tAwC6tA8A6NI+AKBL+wCALu0DALq0DwDo0j4AoEv7AIAu7QMAurQPAOjSPgCgS/sAgC7tAwC6tA8A6NI+AKBL+wCALu0DALq0DwDo0j4AoEv7AIAu7QMAurQPWKOrxdXjGnHNuFZcO64T143rxfXjBnHDuFHcOG4SN42bxc3jFnHLuFVU3DpuE7eN28Xt4w5xx7hT3DnuEneNu8Xd4x5xz7hX3Ds2jk1i09gsNo8tYsvYKraObWLb2C62jx1ix1gXO8XOsUvsGkPsFrvHHrFn7BV7xz6xb+wX+8cBcWAcFAfHIXFoHBaHxxFxn7hv3C/uHw+IB8aD4sHxkHhoPCweHo+IR8aj4tHxmHhsPC4eH0+IJ8aT4snxlHhqPC2eHs+IZ8az4tnxnHhuPC+eHy+IF8aL4shYHy+Ol8RL42Xx8nhFHBWvjFfFq+M18dp4Xbw+3hBvjDfFm+Mt8dZ4W7w93hHvjHfFu+M98d54X7w/PhAfjA/Fh+Mj8dH4WHw8PhGfjE/Fp+Mz8dn4XHw+vhBfjC/Fl+Mr8dX4Wnw9vhHfjG/Ft+M7MYvvxvfi+/GD+GH8KH4cP4mfxs/i5/GL+GX8Ko6OY+LYOC6OjxPixDgpTo5T4tQ4LU6PM+LMOCvOjnPi3Dgvzo8L4sK4KC6OS+LSuCwujyvi1/Gb+G38Ln4ff4g/xp/iz/GX+Gv8Lf4e/4gN1d8OASwBFEABFEABFMASQAEUQAEsARRAARTA7gFrJIACKIACKIAlgAIogAIogAJYAiiAAiiAJYACKIACKIACWAIogAIogCWAAiiAAiiAAlgCKIACKIAlgAIogAIogAJYAiiAAiiAJYACKIACuOAEUAAFUAAFsARQAAVQAAVQAEsABVAABbAEUAAFUAAFUABLAAVQAAWwBFAABVAABVAASwAnEcANTa8EsJ0ACqAACqAAlgAKoAAKoAAKYAmgAAqgAJYACqAACqAACmAJoAAKoACWAAqgAAqgAApgCaAACqAAlgAKoAAKoAAKYAmgAAqgAJYACqAACuCCE0ABFEABFMASQAEUQAEUQAEsARRAARTAEkABFEABFEABLAEUQAEUwBJAARRAARRAASwBFEABFMASQAEUQAEUQAEsARRAARTAuvIB7P6b/0YABVAABVAASwAFUAAFsARQAAVQAAVQAEsABVAAF54ACqAACqAAlgAKoAAKoAAK4BoJoAAKoAAKYAmgAAqgAJYACqAACqAACmAJoAAK4MITQAFc+QDG0XFMHBvHxfFxQpwYJ8XJcUqcGqfF6XFGnBlnxdlxTpwb58X5cUFcGBfFxXFJXBqXxeVxRQlgOwEUQAEUQAEsARRAARRAARTANRJAARRAARTAEkABFEABLAEUQAEUQAEUwBJAARTAhSeAAiiAAiiAJYACKIACKIACuEYCKIACKIACWAIogAIogCWAAiiAAiiAAlgCKIACuPAEUAAFUAAFsARQAAVQAAVQANdIAAVQAAVQAEsABVAABbAEUAAFUAAFUABLAAVQABeeAAqgAAqgAJYACqAACqAACuAaCaAACqAACmAJoAAKoACWAAqgAAqgAApgCaAACuDCE0ABFEABFMASQAEUQAEUQAFcIwEUQAEUQAEsARRAARTAEkABFEABFMBRArhxbBKbxmaxeWwRW8ZWsXVsE9vGdrF97BA7xrrYKXaOXWLXGGK32D32iD1jr9g79ol9Y7/YPw6IA+OgODgOiUPjsDg8jigBFEABFMASQAEUQAEUQAEsARRAARTAEkABFEABXAICKIACKIACWAIogAIogAIogCWAAiiAAlgCKIACKIACKIAlgAIogAJYAiiAAiiAAiiAJYACKIACWAIogAIogAIogCWAAiiAAlgCKIACKIALTgAFUAAFUABLAAVQAAVQAAWwBFAABVAASwAFUAAFUAAFsARQAAVQAEsABVAABVAABbAEUAAFUABLAAVQAAVQAAWwBFAABVAASwAFUAAFcMEJoAAKoAAKYAmgAAqgAAqgAJYACqAACmAJoAAKoAAKoACWAAqgAApgCaAACqAACqAAlgAKoAAKYAmgAAqgAAqgAJYACqAACmAJoAAKoAAuOAEUQAEUQAEsARRAARRAARTAEkABFEABLAEUQAEUQAEUwBJAARRAASwBFEABFMCJBJDFssgB7P4blkj7AJaSADIJ7QNYWosYwO4/Ycm0D2CpLVIAu/+CJdQ+gKUmgCy19gEsvUUIYPcfsKTaBzAJnQHsvp0l1j6ASRBAllL7ACajI4DdN7Pk2gcwKVdlALtvZQLaBzApAshSaR/A5FwVAey+kYloH8AkzTOA3bcxIe0DmCQBZCm0D2Cy5hHA7puYmPYBTNqYAey+hQlqH8CkCSALrX0AkzdGALtvYKLaB7ASrkwAu7czYe0DWAkCyEJqH8DK+H8C2L2ZiWsfwEr5XwLYvZUV0D6AlSKALJT2AayctQSweyMron0AK+k/BbB7GyukfQArSQBZCO0DWFn/LoDdm1gx7QNYaf8awO4trKD2Aaw0AaRV+wBW3voF2MCKah8A0KV9AECX9gEAXdoHAHRpHwDQpX0AQJf2AQBd2gcAdGkfANClfQBAl/YBC2xoMvYdRzYZ+471Tca+Y9Zk7Ds2NBn1jrE/ZUqGJmPfIYACOJvDHQI4cUOTse8QQAGczeEOAZy4ocnYdwigAM7mcIcATtzQZOw7BFAAZ3O4QwAnbmgy9h0CKICzOdwhgBM3NBn7DgEUwNkc7hDAiRuajH2HAArgbA53CODEDU3GvkMABXA2hzsEcOKGJmPfIYACOJvDHQI4cUOTse8QQAGczeEOAZy4ocnYdwigAM7mcIcATtzQZOw7BFAAZ3O4QwAnbmgy9h0CKICzOdwhgBM3NBn7DgEUwNkc7hDAiRuajH2HAArgbA53CODEDU3GvkMABXA2hzsEcOKGJmPfIYACOJvDHQI4cUOTse8QQAGczeEOAZy4ocnYdwigAM7mcIcATtzQZOw7BFAAZ3O4QwAnbmgy9h0CKICzOdwhgBM3NBn7DgEUwNkc7hDAiRuajH2HAArgbA53CODEDU3GvkMABXA2hzsEEGCZtQ8A6NI+AKBL+wCALu0DALq0DwDo0j4AoEv7AIAu7QMAurQPAOjSPgCgS/sAgC7tAwC6tA8A6NI+AKDLPwG8PYVZS9xMPAAAAABJRU5ErkJggg==" width="320" height="240" filter="url(#alpha)"/>
</svg>

この完全な例では、PNGのバイト列は保持されます。フィルターは保存された元ファイルの色を変えたり、パスに置き換えたりしません。埋め込みラスターの診断ガイドでは、外側のファイル名が .svg でもベクター形状とは限らない理由を説明しています。

段階的な切り替えと補間tableを区別する

両方の変換形式とも tableValues を使いますが、値の解釈が異なります。typeのリファレンスには利用できる変換関数が掲載され、tableValuesのリファレンスではルックアップリストを説明しています。

discrete では、各値が等しい幅の入力区間を占めます。2つの値 0 1 では、最初の区間が 0 ≤ A < 0.5、次の区間が 0.5 ≤ A ≤ 1 です。出力は2つの値の間で切り替わります。

table では、値が線形補間領域の端点になります。0 1 なら、補間によって各入力アルファを同じ値に戻します。これは恒等変換であり、測定したtableの列がフィルターなしの列と一致する理由です。

仕様の区間式では、次の選択肢も説明できます。

feFuncAの設定アルファの変換
discreteで0 10.5で明確に切り替える
discreteで0 0 0 10.75で明確に切り替える
tableで0 1恒等補間
tableで0 0 1 1明確な切り替えではなく、中間で徐々に変化する

スクリーンショットで検証したのは、2値のdiscreteとtableです。4値の行は仕様の対応を示しており、追加の図形を測定した結果ではありません。0と1だけのリストなら必ず二値のしきい値になると思い込まず、type を意図的に選んでください。

入力アルファと後段の不透明度を分ける

フィルターには実際の元データのアルファを入力します。この例では、そのアルファはPNGのピクセルに保存されています。ベクターでテストするなら、フィルターを適用する前の塗りのアルファや fill-opacity を使います。

Filter Effectsの合成モデルでは、不透明度より前にフィルターを適用します。したがって要素や周囲のグループに指定した全体の不透明度は、フィルターの後で描画結果を弱めることがあります。元データにしきい値処理をしてから低い不透明度で合成すると、再び半透明に見える場合があります。条件を制御したしきい値テストでは、後段の不透明度を混ぜないでください。

明確なしきい値処理は、元の半透明の移行部分も捨てます。薄いピクセルは消え、残る半透明ピクセルは完全に不透明になります。残したかった柔らかい光や細いエッジを除いてしまうこともあります。利用先のサイズと複数の背景で結果を確認してください。出力アルファが二値でも、最終的に表示されるエッジにサンプリングや合成の影響がないとは限りません。

半透明がデザインの一部なら、そのまま維持するか、明確な切り替えを強制せず緩やかな変換を使ってください。意図的な単色の可視性マスクについては、SVGのCSSマスクガイドで別の表示方法を扱っています。

不透明な白には別の診断が必要

白い部分が残るのは、アルファが完全に不透明だからです。この操作はピクセルが白く見えるかどうかではなく、アルファで選びます。完全に不透明な背景ピクセルは、この 0 1 のdiscrete変換では透明になりません。

不要な白背景が含まれている場合は、まず独立したSVGの形状なのか、ラスター画像の一部なのかを確認します。不要なベクター背景なら、形状を直接削除または編集してください。白がピクセルに焼き込まれたPNGなら、復元の前にラスター元画像を整えるか、適切な背景除去の方法を使います。背景透過SVGのガイドでは、それぞれの場合を説明しています。

色で背景を除く前に、被写体そのものの白い部分にも注意してください。このアルファフィルターは、どの白い領域が背景でどれが図形なのかを推測できず、元画像の統合時に失われた色情報も復元できません。

ベクター復元の前に透明なラスターを準備する

完成したデザインがラスターしかなく、SVGの形状が必要な場合は、PerfectVectorを利用できます。まず本当の透明度を持つPNGを準備し、PNGをSVGに変換します。コントラストのある背景でプレビューを比較し、シルエットと開口部を確認して、ダウンロードしたファイルに不要な背景の形状がないか調べてください。

このフィルターの例は表示上の実験です。フィルター付きSVGをベクター化に送るものではなく、新たなトレース結果を示すものでもありません。しきい値処理したラスターの見た目を維持する必要があるなら、ベクター復元を検討する前に、編集ソフトで実際のラスター納品用コピーを作り、検証してください。ブラウザープレビューに頼らず、そのコピーのアルファを確認します。

ベクターのマスターがあれば、そのまま使ってください。半透明が有用なデザイン情報を伝えているなら保持し、単純な記号なら保守しやすい場合は描き直します。画像ベクター化の概要では、ラスターの再構築と既存SVGの表示変更を区別しています。

よくある質問

discreteのtableValues 0 1は、どのアルファしきい値を使いますか? 入力アルファが0.5未満なら0、0.5以上なら1に変換します。検証した8ビットPNGの色見本では、バイト値127が透明に、128が不透明になります。

tableValues 0 1で透明度が変わらないのはなぜですか? typeがtableの場合、その値は0から1への線形補間を定義し、恒等変換になります。ここで示した2段階の変換にはtype discreteを使ってください。

白を除いたり、PNGをベクターパスに変えたりできますか? いいえ。完全に不透明な白は、このアルファしきい値を通過します。今回のSVG各版には同じPNGが1つのimage要素として残り、パスは0個です。背景の整備とベクターの再構築は別の作業です。

参考資料

  1. W3C — Filter Effects Level 1 — 既定の恒等変換、アルファを事前乗算していないチャンネルの変換、tableとdiscreteの区間式を定義しています。
  2. MDN — feComponentTransfer要素 — フィルタープリミティブによるチャンネルの値の変換を説明しています。
  3. MDN — feFuncA要素 — アルファチャンネルの変換関数を示しています。
  4. MDN — type属性 — component-transfer関数の種類と属性が使われる文脈を一覧にしています。
  5. MDN — tableValues属性 — tableとdiscreteの変換で使うルックアップ値を説明しています。

ラスターのデザインからベクター形状が必要ですか? 透明なPNGを準備して変換し、プレビューのシルエットと穴を確認して、ダウンロードしたSVGを色付きの背景で検証してください。

ブログのその他の記事

編集しやすい
よりきれいなSVGから始めましょう