Paint app. 2 Paint types, SolidLine and Airbrush, Airbrush draws to mCanvas, can only see Solid line when it's selected

StackOverflow https://stackoverflow.com/questions/22643616

  •  21-06-2023
  •  | 
  •  

Question

The default is SolidLine, I can start drawing, switch to Airbrush, and everything looks fine. If I switch back to SolidLine, the Airbrush draws disappear, but the previous SolidLine draws remain. If I then switch back to Airbrush, the previous Airbrush draw reappear, and the previous SolidLine draws remain. In the function touch_up(event), in (line_type == SOLID_LINE), if I comment out

//mCanvas.drawPath(mPath, mPaint);

then When I select Airbrush the SolidLine draws disappear, and reapear when I select back to SolidLine, while as usual Airbrush draw disappear. So it seems clear to me that I need to get my Airbrush draws onto the onDraw Canvas, but I've not been able to get that to work, trying a variety of things focussing on trying to draw the Bitmap mSourceBM used to initialize mCanvas, onto the onDraw Canvas canvas.

Any ideas would be greatly appreciated!

My onDraw function

    @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if(line_type == SOLID_LINE){
        for (Pair<Path, Paint> p : paths) {
            canvas.drawPath(p.first, p.second);
        }
        canvas.drawPath(mPath, mPaint);
    }else if(line_type == AIRBRUSH){
        Log.d(DTAG, "onDraw: AIRBRUSH: no call");
        canvas.drawBitmap(mSourceBM, 0,0, null);
    }
}

My init function, for context

    private void init(AttributeSet attrs, int defStyle) {
    if(line_type == SOLID_LINE){
        setSolidLine(); // various paint settings
    }else if(line_type == AIRBRUSH){
        setAirbrush(); // other paint settings
    }
}

Here's the drawSpalsh function that is fired multiple times in touch_move, and once in touch up. It draws a paint with a radial gradient, and a radius of have half the Paint Stroke width at point (x,y). invalidate() is called in onTouchEvent after each touch_move(x,y), touch_start(x,y), and touch_up(event) call.

    private void drawSplash(int x, int y)
{   
    mBrush.setBounds(x - strokeRadius, y - strokeRadius, x + strokeRadius, y + strokeRadius);
    mBrush.draw(mCanvas);
    //mPaint = mBrush.getPaint();
    //mCanvas.drawBitmap(mSourceBM, x, y, mPaint);

    //mCanvas.drawPaint(mPaint);
}

touch_start, called from onTouchEvent

    private void touch_start(float x, float y) {
    if(line_type == SOLID_LINE){
        undonePaths.clear();// we clear the undonePaths because we are drawing
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }else if(line_type == AIRBRUSH){
        mPreviousX = x;
        mPreviousY = y;
        Log.d(DTAG, "touch_start");
    }
}

touch_move called from onTouchEvent

private void touch_move(float x, float y) {
    if(line_type == SOLID_LINE){
        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;
        }
        // displayMemoryUsage("touch_move SOLID");
    }else if(line_type == AIRBRUSH){
        float mX = x;
        float mY = y;

        // get vector from previous to current position
        float xdist = mX - mPreviousX;
        float ydist = mY - 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.
        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);
        }
        //Log.d(DTAG, "touch_move: AIRBRUSH xdist, ydist: "+xdist+" "+ydist);
        // update the previous position
        mPreviousX = mX;
        mPreviousY = mY;
        //displayMemoryUsage("touch_move AIR");
        //Log.d(DTAG, "touch_move AIR: previous x y "+mX+" "+mY);
    }
}

touch_up called from onTouchEvent

    private void touch_up(MotionEvent event) {
    if(line_type == SOLID_LINE){
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        Paint newPaint = new Paint(mPaint);
        paths.add(new Pair<Path, Paint>(mPath, newPaint));
        mPath = new Path();
    }else if(line_type == AIRBRUSH){
        drawSplash((int) event.getX(), (int)event.getY());
    }
}

the Activity sets the Bitmap. Actually I don't use the BitmapDrawable. Just the Bitmap to initialize the Airbrush canvas mCanvas.

    /**
 * Sets the Canvas Bitmap we intend to modify
 */
public boolean setCanvasBitmapDrawable(BitmapDrawable bitmapdrawable, Bitmap sourceBM, int left_bound, int top_bound) {
    // supply bounds as parameters
    mSourceBM = sourceBM;
    // mSourceBM = convertToMutable(this, mSourceBM);

    bmDrawable = bitmapdrawable;
    mCanvas = new Canvas(mSourceBM);
    //bmDrawable.setBounds(left_bound, top_bound, bitmapdrawable.getIntrinsicWidth()+left_bound, bitmapdrawable.getIntrinsicHeight()+top_bound);

    invalidate();
    return true;
}
Was it helpful?

Solution

   @Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

        for (Pair<Path, Paint> p : paths) {
            canvas.drawPath(p.first, p.second);
        }
        canvas.drawPath(mPath, mPaint);

        Log.d(DTAG, "onDraw: AIRBRUSH: no call");
        canvas.drawBitmap(mSourceBM, 0,0, null);
    }

the ifs in the above statement make it draw only one or the other. take them out of ondraw, the if statements in your ontouch will suffice to show which type your using, and it should work fine

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top