How to drawing a path with a bitmap?

Dominik picture Dominik · Aug 10, 2011 · Viewed 11.3k times · Source

I have a little drawing app and want to use "complex" shapes as brushes, i.e. a star. Drawing with a simple brush already works with this code:

remotePath.reset();
remotePath.moveTo(start_x, start_y);

float dx = Math.abs(end_x - start_x);
float dy = Math.abs(end_y - start_y);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
        remotePath.quadTo(start_x, start_y, (end_x + start_x) / 2, (end_y + start_y) / 2);
}

remotePath.lineTo(end_x, end_y);
// commit the path to our offscreen
mCanvas.drawPath(remotePath, remotePaint);
// kill this so we don't double draw
remotePath.reset();
invalidate();

I basically want the same functionality using this bitmap:

Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.brush_star);

My solution currently is using a list of points (coordinates) to draw the bitmap. The problem with that solution is that it only draws bitmaps at the given points resulting in having gaps between each drawn bitmap. I rather would like to get a smooth line while drawing like with a simple brush without any gaps in between.

Current code for the bitmap drawing:

        protected void onDraw(Canvas canvas) {

        // Make canvas white
        canvas.drawColor(Color.WHITE);

        // Paintable area
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

        canvas.drawPath(mPath, mPaint);

        for (Point point : points) {
            canvas.drawBitmap(complexBrush, point.x, point.y, p);
        }
    }

What's the best way to do so? Thanks for any help!

Answer

Kenumir picture Kenumir · Jul 31, 2012

I use this Point's class:

public class Point  implements Serializable {
float x, y;
float dx, dy;
}

Paint object:

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(5);
paint.setColor(Color.RED);
paint.setAntiAlias(true);

draw on canvas:

private void drawCanvas(Canvas canvas, List<Point> pts){
    if (pts.size() > 1){
        Path path = new Path();
        final int SMOOTH_VAL = 6;
        for(int i = pts.size() - 2; i < pts.size(); i++){
            if(i >= 0){
                Point point = pts.get(i);

                if(i == 0){
                    Point next = pts.get(i + 1);
                    point.dx = ((next.x - point.x) / SMOOTH_VAL);
                    point.dy = ((next.y - point.y) / SMOOTH_VAL);
                }
                else if(i == pts.size() - 1){
                    Point prev = pts.get(i - 1);
                    point.dx = ((point.x - prev.x) / SMOOTH_VAL);
                    point.dy = ((point.y - prev.y) / SMOOTH_VAL);
                }
                else{
                    Point next = pts.get(i + 1);
                    Point prev = pts.get(i - 1);
                    point.dx = ((next.x - prev.x) / SMOOTH_VAL);
                    point.dy = ((next.y - prev.y) / SMOOTH_VAL);
                }
            }
        }

        boolean first = true;
        for(int i = 0; i < pts.size(); i++){
            Point point = pts.get(i);
            if(first){
                first = false;
                path.moveTo(point.x, point.y);
            }
            else{
                Point prev = pts.get(i - 1);
                path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x - point.dx, point.y - point.dy, point.x, point.y);
            }
        }
        canvas.drawPath(path, paint);
    } else {
        if (pts.size() == 1) {
            Point point = pts.get(0);
            canvas.drawCircle(point.x, point.y, 2, paint);
        }
    }
}

Draw on bitmap canvas:

private void drawBitmap(Bitmap bmp, List<Point> pts) {
    Canvas c = new Canvas(bmp);
    drawCanvas(c, pts);
}