2013-02-10 20 views
29

Così ho provato il codice da qui: Creating an ImageView with a mask. Sto utilizzando le seguenti immagini come originale e la maschera:Android come applicare la maschera su ImageView?

enter image description hereenter image description here

Tuttavia, il risultato che ottengo è questo:

enter image description here

nota che lo sfondo della finestra non è nero, ma holo light (che sulla galaxy nexus ha l'aspetto di un grigio molto pallido, non completamente bianco). La seconda immagine è il risultato che ottengo quando un elemento è selezionato in una visualizzazione elenco.

Se invece creo un nuovo Bitmap utilizzando lo stesso algoritmo e poi passare alla visualizzazione dell'immagine, invece di rilevante OnDraw(), che disegna in modo corretto:

Canvas canvas = new Canvas(); 
Bitmap mainImage = //get original image 
Bitmap maskImage = //get mask image 
Bitmap result = Bitmap.createBitmap(mainImage.getWidth(), mainImage.getHeight(), Bitmap.Config.ARGB_8888); 

canvas.setBitmap(result); 
Paint paint = new Paint(); 
paint.setFilterBitmap(false); 

canvas.drawBitmap(mainImage, 0, 0, paint); 
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); 
canvas.drawBitmap(maskImage, 0, 0, paint); 
paint.setXfermode(null); 

imageView.setImageBitmap(result); 

ottengo il risultato atteso:

enter image description here

Nota la dissolvenza è stata applicata correttamente. Questo è più evidente quando viene effettuata una selezione.

Quindi cosa succede nel metodo onDraw di ImageView per creare questo sfondo nero invece di lasciare trasparire lo sfondo della finestra? La cosa interessante è che, se l'immagine originale in sé ha una certa trasparenza, che la trasparenza è rispettato, per esempio:

enter image description here

non riesco a capirlo da solo. Preferirei farlo su onDraw invece di pre-creare la bitmap perché funziona solo per bitmap come sorgente e maschera. Voglio essere in grado di farlo con altri drawable come gradienti e colori solidi, ma in quei casi la larghezza e l'altezza non sono impostate.

+1

Ecco un aggiornamento. Dopo aver letto http://stackoverflow.com/questions/3467334/erase-bitmap-parts-using-porterduff-mode, ho potuto riprodurre lo stesso comportamento del nero nell'esempio di lavoro se avessi impostato la configurazione di Bitmap su RGB_565 anziché su ARGB_8888. Potrei anche restringere il problema alla tela che viene passata sul metodo onDraw. Se utilizzo la tela onDraw, viene visualizzato il bordo nero.Dal momento che il canvas passato a onDraw non ha una bitmap associata, forse nativamente non supporta la trasparenza? Un'altra cosa che ho scoperto è che il bordo nero scompare mentre la vista elenco scorre. – AngraX

+1

Ok. Dopo aver letto questo http://stackoverflow.com/questions/5231260/android-shader-behave-different-in-ondrawcanvas-and-new-canvasbitmap sembra che il bug sia in realtà che sto rendendo trasparenti i pixel della tela della finestra se lo applico sulla tela passato a onDraw(). E dietro la finestra c'è uno sfondo nero. Sembra che non abbia altra scelta che usare una bitmap temporanea e renderizzare in essa, a meno che non riesca a trovare un'altra modalità DST che funzioni. – AngraX

+0

sto provando ad implementare una funzionalità simile in cui ho una visione di immagini con l'immagine e la seconda con maschera nera, al tocco dovrebbe mostrare la dietro immagine del cerchio come la tua presentazione, puoi aiutarmi qui? – ViVekH

risposta

25

Ho trovato la combinazione perfetta per creare il mascheramento senza bordo nero dopo aver ricercato tutti i post StackOverflow. Si adatta abbastanza bene al mio scopo.

Attualmente sto creando una vista trascinabile utilizzando un'immagine normale e un'immagine di mascheramento (una foto con trasparenza), quindi ho bisogno di sovrascrivere la funzione onDraw.

private Bitmap mImage = ...; 
private Bitmap mMask = ...; // png mask with transparency 
private int mPosX = 0; 
private int mPosY = 0; 

private final Paint maskPaint; 
private final Paint imagePaint; 

public CustomView (final Context context) { 
    maskPaint = new Paint(); 
    maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 

    imagePaint = new Paint(); 
    imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OVER)); 
} 

/* TODO 
if you have more constructors, make sure you initialize maskPaint and imagePaint 
Declaring these as final means that all your constructors have to initialize them. 
Failure to do so = your code won't compile. 
*/ 

@Override 
public void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 

    canvas.save();  
    canvas.drawBitmap(mMask, 0, 0, maskPaint); 
    canvas.drawBitmap(mImage, mPosX, mPosY, imagePaint); 
    canvas.restore(); 
} 
+1

Ehi. Ho appena controllato la logica dopo aver letto alcuni articoli sulle modalità xfer e credo che la tua soluzione funzioni abbastanza bene. Accettandolo come la risposta ufficiale. Per ulteriori dettagli sulle modalità xfer, vedere: http://www.piwai.info/transparent-jpegs-done-right/ e http://ssp.impulsetrain.com/2013-03-17_Porter_Duff_Compositing_and_Blend_Modes.html – AngraX

+0

Nel caso l'algoritmo sopra non ha funzionato, cambia il setXfermode di maskPaint a PorterDuff.Mode.DST_OUT. – morph85

+0

Ha funzionato con entrambe le modalità: CLEAR e DST_OUT. Interessante, dalla documentazione che ho letto sulle modalità xfer, CLEAR dovrebbe cancellare tutto, ma su Android funziona esattamente come un DST_OUT. A proposito, sto usando gli shader ora invece delle modalità xfer, quindi eseguo 1 passino di disegno in meno, facendo cadere il mio overdraw dai rossi ai verdi :). – AngraX

2

Rispondere alla mia domanda. Xfermode funzionava come previsto. La vernice stava rendendo il risultato della tela trasparente (che era la tela usata dall'attività della finestra). Poiché la tela stessa veniva impostata trasparente, la finestra mostrava cosa c'era dietro: lo sfondo nero.

Per farlo correttamente, è necessario creare una nuova bitmap per contenere il risultato della maschera alfa. Ho aggiornato il codice per tenere conto dei drawable di tutti i tipi.

0

presente codice si applichino:

mask_over = BitmapFactory.decodeResource(
      getResources(), mask_over1[0]); 
    icon = Bitmap.createScaledBitmap(icon, screenwidth, screenwidth, false); 
    mask_over = Bitmap.createScaledBitmap(mask_over, screenwidth, screenwidth, false); 
      back_img=createBitmap_ScriptIntrinsicBlur(Bitmap.createScaledBitmap(cropview.croppedImage, screenwidth, screenwidth, false),25.0f); 
    LinearLayout.LayoutParams layoutParams111 = new LinearLayout.LayoutParams(screenwidth, screenwidth); 
Problemi correlati