2013-06-21 15 views
5

Mam dwie bitmapy. Oto bitmapy 1:Android - Maskowanie bitmapy za pomocą innej mapy bitowej

Bitmap 1: Background

A oto bitmapy 2:

Bitmap 2: frame

Co ostateczne wyniki będą:

Bitmap Final

Byłbym wdzięczny kod jednak bardziej doceniam odwołanie do dokumentacji lub samouczka. Chciałbym zrozumieć kod całkowicie i od dawna szukałem na developer.android.com bez powodzenia. Dzięki.

+0

To można zrobić, i jestem pewien, że ktoś wpadnie z pewnym wglądem. Ale czy mogę zapytać, dlaczego nie używasz pojedynczej bitmapy lub .png końcowego wyniku, który chcesz? –

+1

@JadeByfield może to są dynamiczne wejścia i wyjścia, w takim przypadku, cóż, nie możesz tego zrobić – fge

+0

@fge Ahh, dobry punkt :) –

Odpowiedz

1

Ponad 3 lata i brak odpowiedzi? Mogę to naprawić.

Jak stwierdzono w komentarzach, mapa bitowa 2 jest przezroczysta wokół krawędzi i na środku (tylko kontur jest tam), więc pierwszym krokiem jest wypełnienie środka bielą. Dostępnych jest wiele algorytmów wypełniania powodziowego. Użyłem https://stackoverflow.com/a/8925653/852795, ponieważ było to łatwe, chociaż są inne, które z pewnością są szybsze. Jest to konieczne, ponieważ umożliwia następny krok.

Drugi etap polega na połączeniu wypełnionej bitmapy 2 z bitmapą 1 przy użyciu Porter/Duff Composting. PorterDuff.Mode.SRC_ATOP będzie skutecznie malować mapę bitową 1 w białym obszarze bitmapy 2, pozostawiając obszar poza konturem przezroczysty.

Oto kod:

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++; 
      } 
     } 
    } 
} 

Po uruchomieniu wyjście (po dodaniu jasnoniebieski odcień tła, aby „zobaczyć” przezroczystych obszarów obrazów) powinien wyglądać tak, ze obrazy, odpowiednio, jako bitmapy 2, bitmapy 2 wypełnione bitmapy 1 i ostatecznie kombinacja bitowa 2 napełnione i bitmapy 1:

enter image description here

nie wydaje się być nieco „rozmycie” tylko wewnątrz konturu , ale to pewnie artefakt wypełnienia powodziowego, a może oryginalna mapa bitowa 2. Zabawa z obydwoma może to wyjaśnić.

Powiązane problemy