2010-08-12 19 views
14

我嘗試使用Porter-Duff Xfermodes擦除Android應用程序中的位圖部分。使用PorterDuff模式擦除位圖部件

我有一個藍色的位圖疊加的綠色背景。當我觸摸屏幕時,應該創建覆蓋位圖中的「洞」,使綠色背景可見。而不是一個洞,我現在的代碼產生一個黑點。

以下是我的代碼。任何想法,我在這裏做錯了什麼?

/** 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; 
    } 

} 

回答

6

首先想到的是,我不確定是否將erase設置爲0在擦除paint對象上是個好主意。這可能會使整個事情失效。

另外,如果您正在處理alpha,則應始終使用Bitmap.Config.ARGB_8888。

如果您在使用PorterDuff時遇到問題,我會建議簡化您的方法,只做(臨時)。這將幫助您縮小不工作的部分。評論與觸摸和查看更新有關的所有內容。

然後,您可以指出繪圖的哪部分工作不正確。設置你的構造是這樣的:

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 */ 
    ... 
} 

如果你做一些事情,這樣,你應該能夠告訴你如何PD方法影響綠色的位圖,並相應地改變的東西。

+0

非常感謝喬希!使用Bitmap.Config.ARGB_8888而不是Bitmap.Config.RGB_565創建位圖解決了這個問題。 關於效果:我計劃將繪製路徑的alpha作爲下一步應用到我的前景位圖。你會建議採用什麼方法,而不是使用Porter-Duff關於繪圖性能? – Philipp 2010-08-13 09:18:04

+0

1.當您在onTouch中獲得觸摸事件時,不時使用drawPath爲透明圖像繪製黑色路徑。這是你的橡皮擦位圖。如果你還沒有這樣做,API演示中的FingerPaint應用程序有一些很好的示例代碼。 2.在onDraw中,使用適當的PorterDuff方法將您的橡皮擦位圖應用於原始藍色位圖。這會將藍色位圖中的整體切割爲您已擦除的內容(黑色路徑)。 3.仍然在onDraw中,將綠色位圖放在屏幕上,然後是新剪下的藍色位圖。 – Josh 2010-08-13 14:57:57

+0

請注意,上述操作可能會在每個繪製週期中花費很高 - 查看裁剪區域以將您正在更新的區域限制爲僅在用戶在橡皮擦位圖中更改的區域。 – Josh 2010-08-13 14:58:58

9

這裏是工作代碼...可以幫助別人

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

謝謝我發現這個很有幫助,你可以像這樣轉換位圖,儘管我們用硬編碼的大小。 'bitmap = bm.copy(Config.ARGB_8888,true);' – schwiz 2011-08-05 21:13:51

+0

謝謝我也發現這真的很有幫助。去年早些時候我正在尋找這個解決方案。 – Sourabh 2014-02-18 12:39:37

+0

請注意,如果您只想在圖像中繪製一個洞,您應該將背景色設置爲Color.TRANSPARENT而不是Color.GREEN。我有很多時間將所有半個示例中的代碼拼湊在一起,非常感謝您發佈一個完整的示例:) – adavea 2014-09-08 19:34:51

0

這裏是您的解決方案的另一個進步...... 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