2013-06-21 22 views
5

Ho due bitmap. Ecco Bitmap 1:Android: mascheramento di una bitmap utilizzando un'altra bitmap

Bitmap 1: Background

E qui è Bitmap 2:

Bitmap 2: frame

Quello che i risultati finali sono le seguenti:

Bitmap Final

Gradirei un codice , tuttavia, apprezzerei di più un riferimento a una documentazione o tutorial. Mi piacerebbe capire il codice completamente e ho cercato su developer.android.com per così tanto tempo senza fortuna. Grazie.

+0

Questo può essere fatto, e sono sicuro che qualcuno entrerà con qualche intuizione. Ma posso chiederti perché non usi solo una singola bitmap o .png del risultato finale che vuoi? –

+1

@JadeByfield forse quelli sono input e output dinamici, nel qual caso, beh, non puoi farlo – fge

+0

@fge Ahh, buon punto :) –

risposta

1

Oltre 3 anni e nessuna risposta? Posso aggiustarlo.

Come indicato nei commenti, Bitmap 2 è trasparente attorno ai bordi e al centro (solo il contorno è lì) quindi il primo passo è riempire il centro con il bianco. Sono disponibili numerosi algoritmi di riempimento flood. Ho usato https://stackoverflow.com/a/8925653/852795 perché era facile, anche se ce ne sono altri che sono sicuramente più veloci. Questo è necessario in quanto consente il passaggio successivo.

Il secondo passaggio consiste nel combinare il bitmap pieno 2 con Bitmap 1 utilizzando Porter/Duff Composting. PorterDuff.Mode.SRC_ATOP dipingerà efficacemente Bitmap 1 nell'area ora bianca di Bitmap 2 lasciando l'area esterna al contorno trasparente.

Ecco il codice:

package test.testapplication; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Point; 
import android.graphics.PorterDuff; 
import android.graphics.PorterDuffXfermode; 
import android.os.Bundle; 
import android.support.v7.app.AppCompatActivity; 
import android.view.View; 
import android.graphics.Bitmap.Config; 

import java.util.LinkedList; 
import java.util.Queue; 

public class MainActivity extends AppCompatActivity { 

    Bitmap mask, background, filledMask, overlay; 
    Canvas c; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     mask = BitmapFactory.decodeResource(getResources(), R.drawable.mask); 
     background = BitmapFactory.decodeResource(getResources(), R.drawable.background); 

     // get the mask, copy it to filledMask and then flood from the center with CYAN 
     filledMask = Bitmap.createBitmap(mask.getWidth(), mask.getHeight(), Config.ARGB_8888); 
     c = new Canvas(filledMask); 
     c.drawBitmap(mask, 0, 0, new Paint()); 
     Point center = new Point(filledMask.getWidth()/2, filledMask.getHeight()/2); 
     floodFill(filledMask, center, Color.TRANSPARENT, Color.WHITE); 


     // create new overlay Bitmap, draw the filledMask and then add the background using PorterDuff 
     overlay = Bitmap.createBitmap(filledMask.getWidth(), filledMask.getHeight(), Config.ARGB_8888); 
     c = new Canvas(overlay); 
     Paint p = new Paint(); 
     p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); 
     c.drawBitmap(filledMask, 0, 0, new Paint()); 
     c.drawBitmap(background, 0, 0, p); 

     DrawView drawView = new DrawView(this); 
     // set background to light blue in order to see transparent areas 
     drawView.setBackgroundColor(0xffd2d7fe); 
     setContentView(drawView); 
     drawView.requestFocus(); 
    } 

    public class DrawView extends View { 
     Paint p = new Paint(); 
     int top = 0; 

     public DrawView(Context context) { 
      super(context); 
     } 

     protected void onDraw(Canvas canvas) { 
      super.onDraw(canvas); 
      canvas.drawBitmap(mask, 0, 0, p); 
      top += mask.getHeight(); 

      canvas.drawBitmap(filledMask, 0, top, p); 
      top += filledMask.getHeight(); 

      canvas.drawBitmap(background, 0, top, p); 
      top += background.getHeight(); 

      canvas.drawBitmap(overlay, 0, top, p); 
     } 
    } 

    // method from https://stackoverflow.com/a/8925653/852795 
    public void floodFill(Bitmap bmp, Point pt, int targetColor, int replacementColor) { 

     Queue<Point> q = new LinkedList<>(); 
     q.add(pt); 
     while (q.size() > 0) { 
      Point n = q.poll(); 
      if (bmp.getPixel(n.x, n.y) != targetColor) continue; 

      Point w = n, e = new Point(n.x + 1, n.y); 
      while ((w.x > 0) && (bmp.getPixel(w.x, w.y) == targetColor)) { 
       bmp.setPixel(w.x, w.y, replacementColor); 
       if ((w.y > 0) && (bmp.getPixel(w.x, w.y - 1) == targetColor)) q.add(new Point(w.x, w.y - 1)); 
       if ((w.y < bmp.getHeight() - 1) && (bmp.getPixel(w.x, w.y + 1) == targetColor)) q.add(new Point(w.x, w.y + 1)); 
       w.x--; 
      } 
      while ((e.x < bmp.getWidth() - 1) && (bmp.getPixel(e.x, e.y) == targetColor)) { 
       bmp.setPixel(e.x, e.y, replacementColor); 

       if ((e.y > 0) && (bmp.getPixel(e.x, e.y - 1) == targetColor)) q.add(new Point(e.x, e.y - 1)); 
       if ((e.y < bmp.getHeight() - 1) && (bmp.getPixel(e.x, e.y + 1) == targetColor)) q.add(new Point(e.x, e.y + 1)); 
       e.x++; 
      } 
     } 
    } 
} 

Quando eseguito, l'uscita (dopo l'aggiunta di una tinta blu luce al fondo, al fine di 'vedere' le aree trasparenti delle immagini) dovrebbe essere simile a questo, con le immagini, rispettivamente, essendo bitmap 2, bitmap 2 riempito, bitmap 1 e infine la combinazione di bitmap 2 riempita e bitmap 1:

enter image description here

sembra che ci sia un po 'confusione' proprio all'interno del contorno , ma probabilmente è così un artefatto del riempimento di piena, o forse l'originale Bitmap 2. Giocare con entrambi potrebbe chiarirlo.

Problemi correlati