canvas.getImageData・putImageDataを利用したレイヤー効果

canvasに画像を貼り付ける際に、様々な画像加工エフェクトを付けられたら幅が広がるのでは、と思って少し調べた所、こちらのスクリプトで同様のことがされておりましたので、参考にさせて頂きました。

フォトレタッチやドローイングツールのレイヤー効果でお馴染みの加算・乗算やスクリーンなど、原理を再現してcanvas上で利用できるようにしています。

ざっくりとした仕組み

画像オブジェクトのデータの値をそのまま弄ることは出来ませんので、
いったんcanvas上に展開した画像データをgetImageDataメソッドで配列として取得し、
RGBA値を操作してputImageDataメソッドでcanvasに戻す、といった手順になります。

iconDecotterでは、afterのcanvasに直接フレーム画像をdrawImageメソッドで貼っていましたが、レイヤー効果をかけるために別のcanvasを用意し、一旦そこに貼りつけたものを合成してafterに貼り付けるように変更しました。ただ、これは非常に処理的に重いため、レイヤー効果の指定が無い場合は今まで通りにし、効果の指定がある時のみ作業canvasからの処理を経由するように分岐させました。
ちなみに作業用canvasは、スタイルシートをdisplay:noneに指定して非表示にしておけば、裏側のデータの操作用には問題なく使用できます。

変更点について

前述のスクリプトにおいて乗算のレイヤー効果を付ける場合、合成画像に透過部分がある場合について、いわゆるPhotoshop等で乗算指定した時とは結果が違ってしまうようでした。
canvasの透過部分は、デフォルトではRGB値が0でアルファ値0なので、RGBの演算としては黒扱いです。そうなると、乗算の場合単純に計算しただけでは、透明部分が全て黒になります。初めから透明部分を黒として扱うものであればそれで正しいのですが、だいたいのフォトレタッチツールにおいて、透過部分はそのまま下レイヤーの状態が維持されるので、そうなるように調整しました。

ブレンド関数に、上レイヤー側のcanvasの透明度も渡すようにし、透明度に応じて上レイヤーの影響を変化させるようにしています。

"Multiple2": function(a,b,ba){return a*(1-ba/255)+(a*b/255)*(ba/255);}

こうすると、上レイヤー側に透過部分があっても、そこが黒くならずに下レイヤーの状態を再現します。

コメント

タイトルとURLをコピーしました