Pergunta

Atualmente estou à procura de uma maneira de usar um bitmap em preto e branco para mascarar o canal alfa de outro bitmap ou Drawable no Android.Estou curioso para saber qual a melhor maneira de fazer isso é.Eu certamente tenho um par de idéias de como fazer isso, mas eles não são o ideal.

Eu preciso ser capaz de aplicar uma nova máscara para a imagem a cada tantas vezes (o bitmap preto e branco vai mudar a cada poucos segundos).

Qualquer feedback sobre como conseguir isso seria muito apreciada.

Foi útil?

Solução

Eu consegui funcionar, então é algo assim

    // 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();

Outras dicas

A minha solução é fechar a @over_optimistic solução, menos um saveLayer() chamada.Eu uso um Drawable máscara em vez de um caminho, no meu caso, foi um disco.

Declarei essas variáveis conforme campos (é uma boa prática para alocar memória fora do método onDraw):

private Paint maskingPaint = new Paint();
private Drawable mask = <insert your drawable here>

Então, em algum lugar fora de onDraw(), o programa de configuração a objetos:

// 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>);

Então, finalmente, o onDraw() método aplica-se a 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 uma melhor compreensão dos modos de transferência, I a que se refere http://ssp.impulsetrain.com/porterduff.html.Essa página é muito interessante para ler.Depois, com o mesmo tipo de código que você vai ser capaz de conseguir muito mais do que uma simples máscara!

Eu fiz um layout mascarável. É um Framelayout, onde você pode especificar o XporterDuffMode e a máscara. Você pode encontrá-lo aqui: https://github.com/christophesmet/android_maskable_layout

Não estou totalmente claro sobre o que você está buscando, mas acredito que uma combinação de BitmapDrawable e LayerDrawable pode funcionar. O BitmapDrawable permitirá que você use seus bitmaps como desenhos e, em seguida, você pode usar o LayererDrawable para colocar a máscara em cima de outro desenhado.

Usando o exemplo Xfermodes na demonstração da API, pude usar um porterDuffxfermode aplicado a um objeto de tinta para misturar dois bitmaps em uma tela. Isso funciona exatamente como eu preciso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top