Reputation: 11
I would like to create a brush effect, which when the user drags his/her finger on the screen, the brush only changes the alpha of the image/bitmap below. For example, if the brush opacity is set to 50%, then applying brush should
That is, the brush should only affect the alpha transparency not the color. I am starting with the following code:
public class DrawingView extends View {
//drawing path
private Path drawPath;
//drawing and canvas paint
private Paint drawPaint, canvasPaint;
//initial color
private int paintColor = 0xFFFF0000, paintAlpha = 255;
//canvas
private Canvas drawCanvas;
//canvas bitmap
private Bitmap canvasBitmap;
//constructor
public DrawingView(Context context, AttributeSet attrs){
super(context, attrs);
setupDrawing();
}
//prepare drawing
private void setupDrawing(){
drawPath = new Path();
drawPaint = new Paint();
drawPaint.setColor(paintColor);
drawPaint.setAntiAlias(true);
drawPaint.setStrokeWidth(50);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
canvasPaint = new Paint(Paint.DITHER_FLAG);
}
//view assigned size
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
drawCanvas = new Canvas(canvasBitmap);
}
//draw view
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawPath(drawPath, drawPaint);
}
//respond to touch interaction
@Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
//respond to down, move and up events
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
drawPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
drawPath.lineTo(touchX, touchY);
drawCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
default:
return false;
}
//redraw
invalidate();
return true;
}
//return current alpha
public int getPaintAlpha(){
return Math.round((float)paintAlpha/255*100);
}
//set alpha
public void setPaintAlpha(int newAlpha){
paintAlpha=Math.round((float)newAlpha/100*255);
drawPaint.setColor(paintColor);
drawPaint.setAlpha(paintAlpha);
}
}
As you have noticed, this brush needs to have a fill color. That is what want to avoid. I need a brush with transparency, but not color.
If there is another method to achieve the object, that is fine.
Upvotes: 0
Views: 1323
Reputation: 30985
Setting an absolute alpha value is likely going to involve some pixel-twiddling in the bitmap.
The closest Porter-Duff mode for what you want is DST_OUT, which will act like an eraser.
Try this code and see if it comes close:
drawPaint.setColor(Color.BLACK); // the color doesn't really matter
drawPaint.setAlpha(255 - alpha); // inverse of the alpha result you want
drawPaint.setXferMode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
What this is going to do is make the image pixels lighter and lighter every time you draw over the same spot, which probably isn't what you want. In which case you would have to get more complicated and draw the color+alpha paths onto a separate bitmap, then draw that bitmap over your image bitmap using PorterDuff.Mode.DST_OUT
.
It's unfortunate that you can't simply implement a custom ColorFilter
that will do exactly what you want. All those graphics operations happen in native space and Google doesn't want us mere mortals messing with that stuff.
Upvotes: 0