Android Paint: how to get “airbrush” effect?

后端 未结 3 1515
梦如初夏
梦如初夏 2021-02-04 09:56

I am following the \"FingerPaint\" demo in the API Demos.

I would need to get an \"airbrush\" effect, in the sense that when I draw over the same spot it gets darker and

相关标签:
3条回答
  • 2021-02-04 10:04

    I made only few minor changes in your code.

     mPaint.setColor(Color.BLACK);// changed color to balck
     mPaint.setAlpha(0x80); // only change    
    

    Activity class

    public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.BLACK);
        mPaint.setAlpha(0x80); // only change
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(12);
    
    }
    
    private Paint mPaint;
    
    public class MyView extends View {
    
        private static final float MINP = 0.25f;
        private static final float MAXP = 0.75f;
    
        private Bitmap mBitmap;
        private Canvas mCanvas;
        private Path mPath;
        private Paint mBitmapPaint;
    
        public MyView(Context c) {
            super(c);
    
            mPath = new Path();
            mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawColor(0xFFAAAAAA);
    
            canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    
            canvas.drawPath(mPath, mPaint);
        }
    
        private float mX, mY;
        private static final float TOUCH_TOLERANCE = 4;
    
        private void touch_start(float x, float y) {
            mPath.reset();
            mPath.moveTo(x, y);
            mX = x;
            mY = y;
        }
    
        private void touch_move(float x, float y) {
            float dx = Math.abs(x - mX);
            float dy = Math.abs(y - mY);
            if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
                mX = x;
                mY = y;
            }
        }
    
        private void touch_up() {
            mPath.lineTo(mX, mY);
            // commit the path to our offscreen
            mCanvas.drawPath(mPath, mPaint);
            // kill this so we don't double draw
            mPath.reset();
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float x = event.getX();
            float y = event.getY();
    
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
            }
            return true;
        }
    }
    
    }
    

    snap shot

    enter image description here

    0 讨论(0)
  • 2021-02-04 10:21

    Found the solution. For those who might be interested:

    public class DrawView extends View {
    public Paint mPaint;
    private Paint mPaint1;
    private Paint mPaint2;
    
    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Path mPath;
    private Paint mBitmapPaint;
    
    public DrawView(Context context, AttributeSet attrs) {
        super( context,  attrs);
    
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        mPaint = new Paint();
        mPaint.setAlpha(0x80);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(0x44000000);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.BUTT);
        mPaint.setStrokeWidth(5);
    
    }
    
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(0xFF00B8F5);
    
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    }
    
    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;
    
    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
        //mCanvas.drawPoint(x, y, mPaint);
    
    }
    
    private void touch_move(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        Path npath=new Path();
        npath.moveTo(mX, mY);
        npath.lineTo( x ,y );
        mX=x;
        mY=y;
        mCanvas.drawPath(npath, mPaint);
        npath.reset();
        //Log.e("","sto disegando");
    }
    
    private void touch_up() {
    
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
    
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touch_start(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touch_move(event);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touch_up();
            invalidate();
            break;
        }
        return true;
    }
    }
    

    Edit: Attaching snap shot of my emulator (Raghunandan). I used your code no changes except increased the stroke width and it looks like below.

    Does not look good when you draw slowly.

    enter image description here

    Screen shot stroke width 12 if you draw a striaght line no problem. But when you draw zig zag you can see it does not look good

    enter image description here

    0 讨论(0)
  • 2021-02-04 10:26

    This approach is more of a simulation the way something like Photoshop would do it: Integrate along the path and draw individual paint splashes with an adjustable spacing inbetween.

    enter image description here

    public class DrawView extends View {
    public Paint mPaint;
    
    private Bitmap mBitmap;
    private Canvas mCanvas;
    
    private int strokeRadius;
    private ShapeDrawable mBrush;
    private Paint mBitmapPaint;
    
    private float mPreviousX, mPreviousY;
    
    public DrawView(Context context, AttributeSet attrs) {
        super( context,  attrs);
    
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    
        int strokeWidth = 20;
    
        strokeRadius = strokeWidth/2;
    
        Shape brushShape = new OvalShape();
    
        mBrush = new ShapeDrawable(brushShape);
    
        Paint paint = mBrush.getPaint();
    
        // radial gradient shader with a transparency falloff, if you don't want this,
        // just set a color on the paint and remove the setShader call
        Shader shader = new RadialGradient(strokeRadius, strokeRadius, strokeRadius,
                Color.argb(255, 0, 0, 0), Color.argb(0, 0, 0, 0), Shader.TileMode.CLAMP);
    
        paint.setShader(shader);
        paint.setAlpha(0x10);
    }
    
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(0xFF00B8F5);
    
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
    }
    
    private void touch_start(float x, float y) {
        mPreviousX = x;
        mPreviousY = y;
    }
    
    private void touch_move(MotionEvent event)
    {
        float x = event.getX();
        float y = event.getY();
    
        // get vector from previous to current position
        float xdist = x - mPreviousX;
        float ydist = y - mPreviousY;
    
        // get the length
        float segmentLength = (float) Math.sqrt(xdist * xdist + ydist * ydist);
    
        // derive a suitable step size from stroke width
        float stepSize = Math.max(strokeRadius / 10, 1f);
    
        // calculate the number of steps we need to take
        // NOTE: this draws a bunch of evenly spaced splashes from the start point
        // to JUST BEFORE the end point. The end point will be drawn by the start point of the
        // next stroke, or by the touch_up method. If we drew both the start and
        // end point there it would be doubled up
        int steps = Math.max(Math.round(segmentLength / stepSize), 2);
    
        for(int i = 0; i < steps; ++i)
        {
            int currentX = (int) (mPreviousX + xdist * i / steps);
            int currentY = (int) (mPreviousY + ydist * i / steps);
    
            drawSplash(currentX, currentY);
        }
    
        // update the previous position
        mPreviousX = x;
        mPreviousY = y;
    }
    
    private void touch_up(MotionEvent event) {
        drawSplash((int) event.getX(), (int)event.getY());
    }
    
    /**
     * draws the brush to the canvas, centered around x and y
     * @param x
     * @param y
     */
    private void drawSplash(int x, int y)
    {
        mBrush.setBounds(x - strokeRadius, y - strokeRadius, x + strokeRadius, y + strokeRadius);
    
        mBrush.draw(mCanvas);
    
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
    
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touch_start(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touch_move(event);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touch_up(event);
            invalidate();
            break;
        }
        return true;
    }
    }
    

    Edit: snap shot (Raghunandan). Result Testing with White Background and Black Color paint.

    enter image description here

    0 讨论(0)
提交回复
热议问题