Enmascarando un Disponibles / mapa de bits en Android
Pregunta
Actualmente estoy buscando una manera de utilizar un mapa de bits en blanco y negro para enmascarar el canal alfa de otro mapa de bits o Disponibles en Android. Soy curioso en cuanto a cuál es la mejor manera de hacer esto es. Ciertamente tengo un par de ideas sobre cómo hacer esto, pero ellos no son óptimas.
Tengo que ser capaz de aplicar una nueva máscara a la imagen de vez en cuando (el mapa de bits en blanco y negro va a cambiar cada pocos segundos).
Cualquier comentario sobre cómo lograr esto sería muy apreciado.
Solución
Lo tengo trabajo, así que es algo como esto
// 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();
Otros consejos
Mi solución está cerca de la solución de @ over_optimistic, menos uno saveLayer () llamada. Yo uso una máscara Disponibles en lugar de un camino, en mi caso se trataba de un disco.
I declaró estas variables como campos (que es buena práctica de asignar la memoria fuera del método onDraw):
private Paint maskingPaint = new Paint();
private Drawable mask = <insert your drawable here>
Entonces, en algún lugar fuera de onDraw (), los objetos de configuración:
// 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>);
Entonces, finalmente, el método onDraw () aplica la máscara:
@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();
}
Para una mejor comprensión de los modos de transferencia, que se refirió a http://ssp.impulsetrain.com/ porterduff.html . Esa página es bastante interesante para leer. Después de eso, con el mismo tipo de código podrás acheive mucho más que una simple máscara!
Hice un diseño enmascarable. Es un FrameLayout donde se puede specifiy la xporterduffmode y la máscara. Lo puedes encontrar aquí: https://github.com/christophesmet/android_maskable_layout
No estoy del todo claro en lo que vamos a ir, pero creo que una combinación de BitmapDrawable
y LayerDrawable
puede trabajar. BitmapDrawable le permitirá utilizar sus mapas de bits como dibujables, y luego se puede utilizar LayerDrawable a la capa de la máscara en la parte superior de otro Disponibles.
Usando el ejemplo Xfermodes en el API de demostración I fue capaz de utilizar un PorterDuffXfermode aplicar a un objeto de pintura a mezclarse dos mapas de bits en una lona. Esto funciona exactamente cómo lo necesito a.