Photoshopのような画像合成はフロントエンドでどこまで可能か
モダンブラウザに限定すれば実装は容易
Photoshopには描画モードという機能があり、例えば「乗算」「オーバーレイ」「スクリーン」などの描画モードを用いることでデザインの表現を大きく広げることが可能になります。
これまで描画モードを利用した表現はブラウザで再現することはできなかったため、たとえば描画モードの設定値に若干の修正を加えた時は毎回画像を切り出し直さなければならず、手間がかかっていました。
なぜかというとPhotoshopでの描画モードはいわゆる画像合成そのものであり、これまでのブラウザの技術はそれを実現するほどの水準に達していませんでした。
しかし現在ではブラウザの技術が大幅に進化し、画像合成がCSSまたはJavascriptで行うことができるようになりました。
mix-blend-mode
先に結論から申し上げますと、モダンブラウザに至ってはCSSのみで合成が可能です。
しかも非常に実装は容易です。
CSS3で登場したmix-bled-modeというプロパティを用いることで、Photoshopに用意されている描画モードの多くをカバーできます。
以下は、モノクロ画像と7色のグラデーションを、描画モード「スクリーン」で合成したデモです。
ソースをご覧いただければ、たった一行の指定で合成を実現できることが分かります。
See the Pen Composition Demo - 01 by Shin Imae (@shinimae) on CodePen.
より詳しく知りたい方や、他のブレンドモードのデモをご覧になりたい方は、以下をご参照ください。
記述も簡潔で、実装の垣根がぐんと下がっていますが、残念ながら冒頭で申し上げた通りIE/Edgeはこのプロパティに未対応です。
以下が各ブラウザに置けるmix-blend-modeの対応状況一覧ですが、Edgeですら対応はままならない状況です。
Can I use... Support tables for HTML5, CSS3, etc
ではIE/Edgeでは合成が無理なのかというと決してそんなことはなく、Canvasを利用するのが最も近道になります
globalCompositOperation
Canvas APIには二つの要素を重ねて描画した際に、その重なり方を制御できるglobalCompositOperationというプロパティが存在します。
こちらは非常に使い勝手がよく、要素を重ねる際にこのプロパティに重なり方を指定する任意の値を代入するだけで、合成をしてくれます。
以下はglobalCompositOperationを用いてスクリーン合成を行なったデモです。
Canvasのスケーリングこそ行なっていますが全体的には比較的シンプルなコードで実装できていることが分ります。
See the Pen Composition Demo - 02 by Shin Imae (@shinimae) on CodePen.
globalCompositOperationのリファレンスを以下にご紹介しますが、こちらを参照いただくとmix-blend-modeと同様の合成方法がAPI側ですでに用意されていることが分ります。
しかし残念なことに、このうちいくつかはIE/Edgeは未対応です。
今回実例に用いたスクリーン合成もその一つですので、上記のデモをIE/Edgeでご覧いただくと合成できずにグラデーションで塗りつぶされてしまいます。
また振り出しに戻ってしまいました。
ビットマップ演算
IEも含めた全ての環境で同様の表示を実現するには、globalCompositOperationが内部的に行なっているビットマップ演算を行うしかありません。
1ピクセルごとの色の情報を取得し、それを操作して新しくイメージデータを生成します。 まさしくPhotoshopの内部で行われていることをそのまま実装する形になります。
ややとっつきにくさがあるかもしれませんが、いくつかのポピュラーな合成アルゴリズムについて下記で解説されています。
合成と聞くととても複雑なことをしているかのようですが、実際のところは二つの色情報を四則演算しているに過ぎず、その実態はとてもシンプルです。 乗算や加算をはじめ(列挙されていませんが)グレースケールやネガポジ反転などは、今回取り上げているスクリーン合成に比べると非常に初歩的なアルゴリズムとなっています。
話を戻して、スクリーン合成のアルゴリズムについても上記で解説がされているため、それを参考に合成した結果が以下になります。
See the Pen Composition Demo - 03 by Shin Imae (@shinimae) on CodePen.
mix-blend-mode対応の判別
@supportsルールが使えるならばとても楽なのですが、例のごとくIE/Edgeが対応していないため、Javascriptにて対応状況を判別する必要があります。
if (typeof window.getComputedStyle(document.body).mixBlendMode !== 'undefined') { // supported. }else{ // not supported. }
出典はこちら。
おわりに
最終的にCanvasによるビットマップ演算という結論に達しましたが、とりわけモバイルブラウザを念頭に入れると、このCanvasを用いたレンダリングがとても高負荷なものであることは言うまでもありません。
前セクションで紹介したmix-blend-modeを利用した実装であればある程度のの負荷にも耐えうるものの、IEを対象に含めると先述したような(決しては容易とは言い難い)ビットマップ演算が必要不可欠なものになることは忘れてはいけません。
ページロード時に一度だけ合成を行う場合はこれで十二分に対応ができますが、例えばグラデーションの開始位置が徐々に変わるなど、合成具合が連続的に変化する場合(つまりms単位でCanvasで合成を繰り返さなければいけない場合)は、環境によってはCanvasの最適化を行なってもなお致命的にパフォーマンスが落ちることがあるので、注意が必要です。
フロントエンドでの画像合成をどこまで実現するか、その対応範囲を制作前に規定する作業はまだしばらく必要になりそうです