Android でのドローアブル/ビットマップのマスク
質問
現在、白黒のビットマップを使用して、Android 上の別のビットマップまたは Drawable のアルファ チャネルをマスクする方法を探しています。これを行うための最良の方法は何なのか、興味があります。確かにこれを行う方法についていくつかのアイデアがありますが、それらは最適ではありません。
画像に新しいマスクを頻繁に適用できる必要があります (白黒のビットマップは数秒ごとに変わります)。
これを達成する方法についてのフィードバックをいただければ幸いです。
解決
私それが働いてしまった、それはとてもこのようなもの。
// we first same the layer, rectF is the area of interest we plan on drawing
// this will create an offscreen bitmap
canvas.saveLayer(rectF, null, Canvas.MATRIX_SAVE_FLAG
| Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG);
// draw our unmasked stuff
super.draw(canvas);
// We same a layer again but this time we pass a paint object to mask
// the above layer
maskPaint = new Paint()
maskPaint.setColor(0xFFFFFFFF);
maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
canvas.saveLayer(rectF, maskPaint,
Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
| Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG);
// we draw the mask which is black and white. In my case
// I have a path, and I use a blurPaint which blurs the mask slightly
// You can do anti aliasing or whatever you which. Just black & white
canvas.drawPath(path, blurPaint);
// We restore twice, this merges the results upward
// as each saveLayer() allocates a new drawing bitmap
canvas.restore();
canvas.restore();
他のヒント
私のソリューションは、近い@ over_optimisticのソリューションに1つ少ないsaveLayer()の呼び出しです。私はDrawableのパスの代わりにマスクを使用、私の場合には、それはディスクだった。
私はフィールドとして、これらの変数を宣言した(それはonDrawメソッドのメモリ外を割り当てることをお勧めです):
private Paint maskingPaint = new Paint();
private Drawable mask = <insert your drawable here>
次に、onDraw()のどこかの外部、セットアップオブジェクト
// Xfermode won't work if hardware accelerated
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
// Using destination shape as a mask
// For a good explanation of PorterDuff transfer modes : http://ssp.impulsetrain.com/porterduff.html
maskingPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
maskingPaint.setAntiAlias(true);
// Position the mask
mask.setBounds(<insert your mask bounds here>);
最後に、onDraw()メソッドは、マスクを適用
@Override
protected synchronized void onDraw(Canvas canvas)
{
// Draw the mask first, making it the PorterDuff destination
mask.draw(canvas);
// Save the layer with the masking paint, that will be applied on restore()
// Using CLIP_TO_LAYER_SAVE_FLAG to avoid any overflow of the masked image outside the mask bounds.
Rect bounds = mask.getBounds();
canvas.saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, maskingPaint,
Canvas.CLIP_TO_LAYER_SAVE_FLAG);
// Draw the shape offscreen, making it the PorterDuff source
super.onDraw(canvas);
// Apply the source to the destination, using SRC_IN transfer mode
canvas.restore();
}
の転送モードをより良く理解するために、私は http://ssp.impulsetrain.com/呼ばのporterduff.html。 このページには、読んでかなり面白いです。その後、同じ種類のコードでは、単純なマスクよりもはるかにacheiveすることができるでしょう!
私はマスク可能なレイアウトを作りました。 それはあなたがxporterduffmodeとマスクをspecifiyすることができますでframeLayoutです。 あなたがここでそれを見つけることができます: https://github.com/christophesmet/android_maskable_layoutする
あなたが何を目指しているのかは完全にはわかりませんが、次のことを組み合わせたものだと思います。 BitmapDrawable
そして LayerDrawable
機能するかもしれません。BitmapDrawable を使用すると、ビットマップを Drawable として使用できるようになり、LayerDrawable を使用してマスクを別の Drawable の上に重ねることができます。
PorterDuffXfermodeは、Paintオブジェクトに適用され、キャンバスに一緒に2つのビットマップをブレンドするために使用することができました。これは私がそれを必要とする正確にどのように動作します。