2010-04-12 18 views
17

Attualmente sto cercando un modo per utilizzare una bitmap in bianco e nero per mascherare il canale alfa di un'altra bitmap o Drawable su Android. Sono curioso di sapere qual è il modo migliore per farlo. Ho certamente un paio di idee su come farlo, ma non sono ottimali.Masking a Drawable/Bitmap su Android

Devo essere in grado di applicare una nuova maschera all'immagine ogni tanto (la bitmap in bianco e nero cambierà ogni pochi secondi).

Qualsiasi feedback su come ottenere ciò sarebbe molto apprezzato.

+0

Sto cercando di utilizzare le parti nere della maschera bitmap per impostare il canale alfa del pixel corrispondente sull'altra bitmap/Drawable su 0. –

risposta

3

ho ottenuto che funziona, quindi è qualcosa di simile

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

Se si esegue l'override del metodo onDraw, invece di 'super.draw (canvas)' ci dovrebbe essere 'super.onDraw (canvas)'. Altrimenti si finisce in loop infinito con errore StackOverflow. – Speedy

+0

Ho fatto la stessa cosa sopra nel 'onDraw' della mia vista personalizzata, ma sembra che' saveLayer' sia costoso e quindi invece di impostare un livello hardware per la mia vista ('View.setLayerType (LAYER_TYPE_HARDWARE, paint) '). Maggiori informazioni: http://stackoverflow.com/a/33483016/4747587 – Henry

2

Non sono del tutto chiaro su cosa stai andando, ma credo che una combinazione di BitmapDrawable e LayerDrawable possa funzionare. BitmapDrawable ti permetterà di usare i tuoi Bitmap come Drawable, e quindi puoi usare LayerDrawable per sovrapporre la maschera a un altro Drawable.

+0

Lo controllerò, grazie. –

1

Utilizzo dell'esempio Xfermodes nella demo API Sono stato in grado di utilizzare PorterDuffXfermode applicato a un oggetto Paint per unire due bitmap su un'area di disegno. Funziona esattamente come ne ho bisogno.

+12

Potresti aggiungere altri dettagli? – Casebash

5

La mia soluzione è vicina alla soluzione di @ over_optimistic, meno una chiamata saveLayer(). Io uso una maschera Drawable invece di un percorso, nel mio caso era un disco.

ho dichiarato queste variabili come campi (è buona pratica per allocare la memoria al di fuori del metodo OnDraw):

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

Poi, da qualche parte al di fuori di OnDraw(), impostazione degli oggetti:

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

infine, l'OnDraw() metodo applica la maschera:

@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(); 
} 

Per una migliore comprensione o Per le modalità di trasferimento, ho fatto riferimento a http://ssp.impulsetrain.com/porterduff.html. Questa pagina è piuttosto interessante da leggere. Dopodiché, con lo stesso tipo di codice sarai in grado di ottenere molto più di una semplice maschera!

+0

Soluzione perfetta. Gli altri sono un po 'troppo lunghi. – Jona

+0

IMO meglio della risposta accettata, preferisco disegnabile sul percorso –

Problemi correlati