CSS または JavaScript におけるブレンドモード対応

過去記事から分離、追記、一部変更。

参考「[ImageMagick で PSD のレイヤー情報を JSON 形式で取り出す & 関連情報 - Qiita](https://qiita.com/kerupani129/items/47242abaadf72723c976)」

本記事で使用した ImageMagick のバージョンは 6.8.9 です。

# 1. ブレンドモード対応

## 1.1. 早見表

ブレンドモードの表記の対応は以下の表のようになっています。

記載する内容は以下の通り:

- ブレンドモード名
    - ImageMagick, Compose
    - Photoshop
    - Photoshop, Blend Mode Key
    - JavaScript, PSD.js
- CSS または JavaScript から利用するためのブレンドモード名
    - CSS
    - JavaScript, Canvas
    - JavaScript, PixiJS

表中で注意が必要な項目は以下のように表記しています:

- <strong><font color="red">赤字</font></strong>は動作が間違っているもの
- <strong><font color="blue">青字</font></strong>は諸事情により使用できないもの
- **太字**は名前や動作に注意が必要なもの

※理由はそれぞれ後述。

|ブレンドモード|IM, Compose|Photoshop|キー|JS, PSD.js|
|---|---|---|---|---|
|-|None|-|-|-|
|通過 (フォルダ)|**<font color="red">Over</font>**|Pass Through|pass|passthru|
|通常|Over|Normal|norm|normal|
|乗算|Multiply|Multiply|mul&nbsp;|multiply|
|覆い焼き (リニア)<br>加算<br>Add|LinearDodge|Linear Dodge<br>Add|lddg|linear_dodge|
|加算 (発光)<br>Add (Glow)|**<font color="red">LinearDodge</font>**|-|-|-|
|減算|**<font color="red">Over</font>**|Subtract|**f**sub|subtract|
|除算|**<font color="red">Over</font>**|Divide|**f**div|divide|
|オーバーレイ|Overlay|Overlay|**over**|overlay|
|スクリーン|Screen|Screen|scrn|screen|
|比較 (明)|Lighten|Lighten|lite|lighten|
|比較 (暗)|Darken|Darken|dark|darken|
|差の絶対値|Difference|Difference|diff|difference|
|除外|Exclusion|Exclusion|**smud**|exclusion|
|覆い焼き|ColorDodge|Color Dodge|**div&nbsp;**|color_dodge|
|焼き込み|ColorBurn|Color Burn|**idiv**|color_burn|
|ソフトライト|SoftLight|Soft Light|sLit|soft_light|
|ハードライト|HardLight|Hard Light|hLit|hard_light|
|色相|Hue|Hue|hue&nbsp;|hue|
|彩度|Saturate|Saturation|sat&nbsp;|saturation|
|カラー|Colorize|Color|colr|color|
|輝度|Luminize|Luminosity|lum&nbsp;|luminosity|

|ブレンドモード|Photoshop|CSS|JS, Cnavas|JS, PixiJS|
|---|---|---|---|---|
|通過 (フォルダ)|Pass Through|-|-|-|
|通常|Normal|normal|source-over|NORMAL<br>SRC_OVER|
|乗算|Multiply|multiply|multiply|MULTIPLY|
|覆い焼き (リニア)<br>加算<br>Add|Linear Dodge<br>Add|-|-|**<font color="red">ADD</font>**|
|加算 (発光)<br>Add (Glow)|-|-|**lighter**|**ADD**|
|減算|Subtract|-|-|**<font color="blue">SUBTRACT</font>**|
|除算|Divide|-|-|-|
|オーバーレイ|Overlay|overlay|overlay|OVERLAY|
|スクリーン|Screen|screen|screen|SCREEN|
|比較 (明)|Lighten|lighten|lighten|LIGHTEN|
|比較 (暗)|Darken|darken|darken|DARKEN|
|差の絶対値|Difference|difference|difference|DIFFERENCE|
|除外|Exclusion|exclusion|exclusion|EXCLUSION|
|覆い焼き|Color Dodge|color-dodge|color-dodge|COLOR_DODGE|
|焼き込み|Color Burn|color-burn|color-burn|COLOR_BURN|
|ソフトライト|Soft Light|soft-light|soft-light|SOFT_LIGHT|
|ハードライト|Hard Light|hard-light|hard-light|HARD_LIGHT|
|色相|Hue|hue|hue|HUE|
|彩度|Saturation|saturation|saturation|SATURATION|
|カラー|Color|color|color|COLOR|
|輝度|Luminosity|luminosity|luminosity|LUMINOSITY|

※全てのブレンドモードを掲載しているわけではありません。
※ PixiJS は **Canvas レンダラの強制**が前提です (後述) 。
※ ImageMagick の Compose の `None` は PixiJS の `NONE` と別物です (後述) 。

参考「[Layer and Mask Information Section - Adobe Photoshop File Formats Specification](https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_75067)」
参考「[psd.js/blend_mode.coffee at master · meltingice/psd.js · GitHub](https://github.com/meltingice/psd.js/blob/master/lib/psd/blend_mode.coffee)」
参考「[&lt;blend-mode&gt; - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/blend-mode)」
参考「[CanvasRenderingContext2D.globalCompositeOperation - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation)」
参考「[PIXI.BLEND_MODES - PIXI - PixiJS API Documentation](https://pixijs.download/dev/docs/PIXI.html#BLEND_MODES)」

※ `Over` (`overlay` でない) や `source-over` 等は厳密にはブレンドの指定ではありません (別記事参照) 。

参考「[アルファ値を含むブレンドモードの画像合成の計算式 - Qiita](https://qiita.com/kerupani129/items/4bf75d9f44a5b926df58)」

## 1.2. PSD.js と Canvas API での ブレンドモード対応

「Photoshop の Blend Mode Key」「PSD.js で得られる値」「Canvas API の `globalCompositeOperation` に指定する値」の対応は、JavaScript 配列で表すと以下の通りです。

```js
const PSD_BLEND_MODES = [
	['pass', 'passthru', null],
	['norm', 'normal', 'source-over'],
	['mul ', 'multiply', 'multiply'],
	['lddg', 'linear_dodge', 'lighter'], // メモ: 画像編集ソフトウェアにより合成方法が異なる
	['fsub', 'subtract', null],
	['fdiv', 'divide', null],
	['over', 'overlay', 'overlay'],
	['scrn', 'screen', 'screen'],
	['lite', 'lighten', 'lighten'],
	['dark', 'darken', 'darken'],
	['diff', 'difference', 'difference'],
	['smud', 'exclusion', 'exclusion'],
	['div ', 'color_dodge', 'color-dodge'],
	['idiv', 'color_burn', 'color-burn'],
	['sLit', 'soft_light', 'soft-light'],
	['hLit', 'hard_light', 'hard-light'],
	['hue ', 'hue', 'hue'],
	['sat ', 'saturation', 'saturation'],
	['colr', 'color', 'color'],
	['lum ', 'luminosity', 'luminosity'],
	['diss', 'dissolve', null],
	['lbrn', 'linear_burn', null],
	['vLit', 'vivid_light', null],
	['lLit', 'linear_light', null],
	['pLit', 'pin_light', null],
	['hMix', 'hard_mix', null],
	['dkCl', 'darker_color', null],
	['lgCl', 'lighter_color', null],
];
```

メンテナンス性を考えると上記のコードが良いと思いますが、実際に使用する場合は `Map` に変換すると処理速度的に良いと思います。

```js
const CANVAS_BLEND_MODES = new Map(PSD_BLEND_MODES.map(([, name, op]) => [name, op]));

const getCanvasBlendMode = name => CANVAS_BLEND_MODES.get(name) ?? null;
```

# 2. ImageMagick の Compose における表記の注意点

- `None` の場合、レイヤーが**非表示**であることが分かるが、表示したときのブレンドモードを**取得できない**。
- PSD の仕様的には「減算」合成も「除算」合成も対応しているが、ImageMagick では「通常」扱い (バージョンによって変更される可能性あり) 。
- 「通過」フォルダは「通常」フォルダ扱い。
- `LinearDodge` は本来、単なる「加算」合成をさすが、ソフトウェアによっては「加算 (発光)」合成として使用される。

# 3. CSS または JavaScript から利用する際の注意点

## 3.1. CSS で指定する場合

- 2021/12/28 現在、「加算」「加算 (発光)」「減算」「除算」合成は非対応。

参考「[&lt;blend-mode&gt; - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/blend-mode)」
## 3.2. Canvas API で描画する場合

- 2021/02/22 現在、「減算」合成と「除算」合成は非対応。
- `lighter` は説明文だけ見ると「加算」合成と間違えやすいが、仕様の数式を見ると「**加算 (発光)**」合成。

参考「[「加算合成」と「加算 (発光) 合成」の違い - Qiita](https://qiita.com/kerupani129/items/215b1f973672452f2d2f)」

参考「[9.1.13. Lighter - Compositing and Blending Level 1](https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus)」

## 3.3. PixiJS で描画する場合

- 2021/02/22 現在の PixiJS のバージョンでは、**Canvas レンダラを強制**しないとほとんどのブレンドモードを使用できないため、注意。
- 2021/02/22 現在の PixiJS のバージョンでは、Canvas レンダラ使用時に `ADD` で `lighter` を代わりに使用する実装になっているため、「加算」合成でなく「**加算 (発光)**」合成になる。
- 2021/02/22 現在、Canvas API で `SUBTRACT` 非対応のため、Canvas レンダラでは `SUBTRACT` **使用不可**。
- `PIXI.BLEND_MODES.NONE` は一部のクラス (`State` など) のオブジェクトを非表示にするために使用される値で、通常のスプライト等に使用するものではないため、Compose の `None` と意味が異なる。

結局 Canvas で操作するのとやっていることが変わらないため、PixiJS を使用しなくてもいいかもしれません。

参考「[PIXI.Application - PixiJS API Documentation](https://pixijs.download/dev/docs/PIXI.Application.html)」(※ `options.forceCanvas: true` で Canvas レンダラを強制)
参考「[pixi.js/mapCanvasBlendModesToPixi.ts at dev · pixijs/pixi.js · GitHub](https://github.com/pixijs/pixi.js/blob/dev/packages/canvas/canvas-renderer/src/utils/mapCanvasBlendModesToPixi.ts)」
参考「[pixi.js/mapWebGLBlendModesToPixi.ts at dev · pixijs/pixi.js · GitHub](https://github.com/pixijs/pixi.js/blob/dev/packages/core/src/state/utils/mapWebGLBlendModesToPixi.ts)」
参考「[pixi.js/State.ts at dev · pixijs/pixi.js · GitHub](https://github.com/pixijs/pixi.js/blob/dev/packages/core/src/state/State.ts)」
参考「[pixi.js/Sprite.ts at dev · pixijs/pixi.js · GitHub](https://github.com/pixijs/pixi.js/blob/dev/packages/sprite/src/Sprite.ts)」

# 4. その他のブレンドモード

本記事で扱わなかった Photoshop や PSD のブレンドモードとして、以下のようなものがあります。

|ブレンドモード|Photoshop|キー|JS, PSD.js|
|-|-|-|-|
|ディザ合成|Dissolve|diss|dissolve|
|焼き込み (リニア)|Linear burn|lbrn|linear_burn|
|ビビッドライト|Vivid Light|vLit|vivid_light|
|リニアライト|Linear Light|lLit|linear_light|
|ピンライト|Pin Light|pLit|pin_light|
|ハードミックス|Hard Mix|hMix|hard_mix|
|カラー比較 (暗)|Darker Color|dkCl|darker_color|
|カラー比較 (明)|Lighter Color|lgCl|lighter_color|

参考「[Layer and Mask Information Section - Adobe Photoshop File Formats Specification](https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_75067)」
参考「[psd.js/blend_mode.coffee at master · meltingice/psd.js · GitHub](https://github.com/meltingice/psd.js/blob/master/lib/psd/blend_mode.coffee)」