2010-08-12 23 views
14

Próbuję usunąć części mapy bitowej w mojej aplikacji Android, używając Porter-Duff Xfermodes.Wymazywanie części bitmapowych przy użyciu trybu PorterDuff

Mam zielone tło, na które nałożona jest niebieska bitmapa. Kiedy dotknę ekranu, ma powstać "dziura" w nakładającej się mapie bitowej, dzięki czemu widoczne jest zielone tło. Zamiast dziury mój obecny kod tworzy czarną kropkę.

Poniżej znajduje się mój kod. Jakieś pomysły, co tu robię źle?

/** Called when the activity is first created. */ 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
      WindowManager.LayoutParams.FLAG_FULLSCREEN); 
    setContentView(new DrawView(this)); 
} 

public class DrawView extends View implements OnTouchListener { 

    private int x = 0; 
    private int y = 0; 

    Bitmap bitmap; 
    Canvas bitmapCanvas; 

    private final Paint paint = new Paint(); 
    private final Paint eraserPaint = new Paint(); 

    public DrawView(Context context) { 
     super(context); 
     setFocusable(true); 
     setFocusableInTouchMode(true); 

     this.setOnTouchListener(this); 

     // Set background 
     this.setBackgroundColor(Color.GREEN); 

     // Set bitmap 
     bitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.RGB_565); 
     bitmapCanvas = new Canvas(); 
     bitmapCanvas.setBitmap(bitmap); 
     bitmapCanvas.drawColor(Color.BLUE); 

     // Set eraser paint properties 
     eraserPaint.setAlpha(0); 
     eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); 
     eraserPaint.setAntiAlias(true); 
    } 

    @Override 
    public void onDraw(Canvas canvas) { 
     bitmapCanvas.drawColor(Color.BLUE); 
     bitmapCanvas.drawCircle(x, y, 10, eraserPaint); 

     canvas.drawBitmap(bitmap, 0, 0, paint); 
    } 

    public boolean onTouch(View view, MotionEvent event) { 
     x = (int) event.getX(); 
     y = (int) event.getY(); 

     invalidate(); 
     return true; 
    } 

} 

Odpowiedz

6

Pierwsza myśl, nie jestem pewien, czy ustawienie alpha 0 na farby erase obiektu jest dobrym pomysłem. To może uczynić całą sprawę nieskuteczną.

Należy również zawsze używać Bitmap.Config.ARGB_8888, jeśli masz do czynienia z alfami.

Jeśli masz problemy z plikami PorterDuff, sugeruję uproszczenie Twojego podejścia TYLKO do robienia tego (tymczasowo). To pomoże ci zawęzić część, która nie działa. Skomentuj wszystko, co dotyczy aktualizacji dotyku i widoku.

Następnie można wyróżnić, która część rysunku nie działa poprawnie. Skonfiguruj konstruktora tak:

DrawView() 
{ 
    /* Create the background green bitmap */ 
    ... 

    /* Create foreground transparent bitmap */ 
    ... 

    /* Draw a blue circle on the foreground bitmap */ 
    ... 

    /* Apply the foreground to the background bitmap 
     using a PorterDuff method */ 
    ... 
} 

onDraw() 
{ 
    /* Simply draw the background bitmap */ 
    ... 
} 

Jeśli wszystko skonfigurować tak, powinieneś być w stanie powiedzieć, w jaki sposób metoda PD wpływa zieloną bitmapy i zmienić ten stan rzeczy odpowiednio.

+0

Bardzo dziękuję Josh! Utworzenie Bitmapy za pomocą Bitmap.Config.ARGB_8888 zamiast Bitmap.Config.RGB_565 rozwiązało problem. Odnośnie efektów: planuję zastosować alfa ścieżki farby do mojej nowej mapy bitowej jako kolejny krok. Jakie podejście sugerowałbyś zamiast używania Porter-Duff w zakresie wydajności rysowania? – Philipp

+0

1. Gdy otrzymujesz zdarzenia dotyku w onTouch, od czasu do czasu użyj drawPath, aby narysować czarną ścieżkę do przezroczystego obrazu. To jest twoja mapa bitowa z gumką. Jeśli jeszcze tego nie robisz, aplikacja FingerPaint w demonstracjach API ma przykładowy kod. 2. W onDraw, zastosuj swoją mapę bitową gumki do ORYGINALNEJ niebieskiej bitmapy za pomocą odpowiedniej metody PorterDuff. W ten sposób wycinamy całość w niebieskiej mapie bitowej w kształcie tego, co wymazaliśmy (czarna ścieżka). 3. Wciąż w onDraw, umieść zieloną bitmapę na ekranie, a następnie nowo wyciętą niebieską bitmapę. – Josh

+0

Należy pamiętać, że powyższe może być kosztowne w każdym cyklu rysowania - spójrz na obszary obcinania, aby ograniczyć aktualizowany obszar do tylko tego, co użytkownik zmienił w mapie bitowej gumki. – Josh

9

kod tutaj działa ... może pomóc ktoś

public class ImageDemo extends Activity { 

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

     setContentView(new Panel(this)); 
    } 

    class Panel extends View { 

     private Bitmap mBitmap; 
     private Canvas mCanvas; 
     private Path mPath; 
     private Paint mPaint; 

     Bitmap bitmap; 
     Canvas pcanvas; 

     int x = 0; 
     int y =0; 
     int r =0; 

     public Panel(Context context) { 
      super(context); 

      Log.v("Panel", ">>>>>>"); 

      setFocusable(true); 
      setBackgroundColor(Color.GREEN); 

      // setting paint 
      mPaint = new Paint(); 
      mPaint.setAlpha(0); 
      mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); 
      mPaint.setAntiAlias(true); 

      // getting image from resources 
      Resources r = this.getContext().getResources(); 

      Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.mickey); 

      // converting image bitmap into mutable bitmap 
      bitmap = bm.createBitmap(295, 260, Config.ARGB_8888); 
      pcanvas = new Canvas(); 
      pcanvas.setBitmap(bitmap); // drawXY will result on that Bitmap 
      pcanvas.drawBitmap(bm, 0, 0, null);   
     } 

     @Override 
     protected void onDraw(Canvas canvas) { 
      // draw a circle that is erasing bitmap    
      pcanvas.drawCircle(x, y, r, mPaint); 

      canvas.drawBitmap(bitmap, 0, 0,null); 

      super.onDraw(canvas); 
     }  

     @Override 
     public boolean onTouchEvent(MotionEvent event) {   
      // set parameter to draw circle on touch event 
      x = (int) event.getX(); 
      y = (int) event.getY(); 

      r =20; 
      // At last invalidate canvas 
      invalidate(); 
      return true; 
     } 
    } 
} 
+1

dziękuję Uważam, że to pomocne, ale możesz przekonwertować bitmapę tak jak z naszym twardym kodowaniem rozmiaru. 'bitmap = bm.copy (Config.ARGB_8888, true);' – schwiz

+0

Dziękuję Również uważam to za bardzo pomocne. Szukałem tego rozwiązania na początku zeszłego roku. – Sourabh

+0

Pamiętaj, że jeśli chcesz po prostu narysować dziurę w obrazie, po prostu ustaw kolor tła na Kolor.TRANSPARENT zamiast Kolor.ZIELONY. Dużo czasu spędziłem na komponowaniu kodu z wszystkich pół-przykładów, dzięki za opublikowanie pełnego przykładu :) – adavea

0

Oto kolejny awans do rozwiązania ... See Demo example

public class MainActivity extends Activity { 

    Bitmap bp; 
    Canvas bitmapCanvas; 
    DrawView drawImg; 
    LinearLayout ln1; 

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

     setContentView(R.layout.activity_main); 
     ln1 = (LinearLayout) findViewById(R.id.ln1); 
     drawImg = new DrawView(this); 
     ln1.addView(drawImg); 

    } 



    public class DrawView extends View implements View.OnTouchListener { 

     private int x = 0; 
     private int y = 0; 

     Bitmap bitmap; 
     Path circlePath; 
     Paint circlePaint; 

     private final Paint paint = new Paint(); 
     private final Paint eraserPaint = new Paint(); 


     public DrawView(Context context){ 
      super(context); 
      setFocusable(true); 
      setFocusableInTouchMode(true); 
      this.setOnTouchListener(this); 

      // Set background 
      this.setBackgroundColor(Color.CYAN); 
      bp = BitmapFactory.decodeResource(getResources(), R.drawable.bg); 

      // Set bitmap 
      bitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888); 
      bitmapCanvas = new Canvas(); 
      bitmapCanvas.setBitmap(bitmap); 
      bitmapCanvas.drawColor(Color.TRANSPARENT); 
      bitmapCanvas.drawBitmap(bp, 0, 0, null); 

      circlePath = new Path(); 
      circlePaint = new Paint(); 
      circlePaint.setAntiAlias(true); 
      circlePaint.setColor(Color.BLUE); 
      circlePaint.setStyle(Paint.Style.STROKE); 
      circlePaint.setStrokeJoin(Paint.Join.MITER); 
      circlePaint.setStrokeWidth(4f); 

      // Set eraser paint properties 
      eraserPaint.setAlpha(0); 
      eraserPaint.setStrokeJoin(Paint.Join.ROUND); 
      eraserPaint.setStrokeCap(Paint.Cap.ROUND); 
      eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 
      eraserPaint.setAntiAlias(true); 

     } 

     @Override 
     public void onDraw(Canvas canvas) { 

      canvas.drawBitmap(bitmap, 0, 0, paint); 
      bitmapCanvas.drawCircle(x, y, 30, eraserPaint); 

      canvas.drawPath(circlePath, circlePaint); 
     } 

     public boolean onTouch(View view, MotionEvent event) { 
      x = (int) event.getX(); 
      y = (int) event.getY(); 

      bitmapCanvas.drawCircle(x, y, 30, eraserPaint); 

      circlePath.reset(); 
      circlePath.addCircle(x, y, 30, Path.Direction.CW); 

      int ac=event.getAction(); 
      switch(ac){ 
       case MotionEvent.ACTION_UP: 
        Toast.makeText(MainActivity.this, String.valueOf(x), Toast.LENGTH_SHORT).show(); 
        circlePath.reset(); 
        break; 
      } 
      invalidate(); 
      return true; 
     } 
    } 
} 

read more

Powiązane problemy