Load bitmap into canvas and draw over it
Asked Answered
V

4

1

I like to make an app, something like a little paint, I have to get a bitmap, draw it on a canvas and next, draw over it (with figer)... So, I actually have this code:

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Environment;
import android.util.Log;
import android.graphics.Bitmap;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class DrawView extends View implements OnTouchListener {

    private Canvas mCanvas;
    private Path mPath;
    public Paint mPaint;
    private ArrayList<Path> paths = new ArrayList<Path>();
    private boolean start = true;

    public DrawView(Context context) {
    super(context);
    setFocusable(true);
    setFocusableInTouchMode(true);
    this.setOnTouchListener((OnTouchListener) this);
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(Color.BLACK);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(4);
    mPaint.setDither(true);
    mPaint.setFilterBitmap(true);
    mCanvas = new Canvas();
    mPath = new Path();
    paths.add(mPath);
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onDraw(Canvas canvas) {

    for (Path p : paths) {
        canvas.drawPath(p, mPaint);

    }
    if (start) {
        Bitmap bmp = BitmapFactory.decodeResource(getResources(),
                R.drawable.v01);
        canvas.drawBitmap(bmp, 0, 0, mPaint);
        start = false;
    }
}

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 = new Path();
    paths.add(mPath);
}

public boolean onTouch(View arg0, 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;
}
}

With this code I can draw over the canvas, and get the bitmap by first way... But, if I touch over, the bitmap dissapears, that's cause on each onTouch event I draw again based on the path... How can I do what I like?, I mean, get the Bitmap, and draw over it...

Varitype answered 7/6, 2013 at 17:24 Comment(4)
call canvas.setBitmap(bmp) instead of drawBitmap for your first call and move it above your draw path callsLoudhailer
you can set the background of your custom view. that will be the background and you can draw on that. its not good to draw your bitmap everytime since calling invalidate will refresh the drawAq
DrawView dv ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); dv = new DrawView(this); setContentView(dv); dv.setBackgroundResource(R.drawable.afor);//setbackground }Aq
@Raughnandan thanks, it works fine, but I want to load the bmp as a template, such I can erase or change the color if I want...Varitype
V
0

Solved,I used this code to can load an image and draw over it...

DrawView.java

package com.example.com.dibuja;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class DrawView extends View implements OnTouchListener {
private Canvas mCanvas;
private Path mPath;
public Paint mPaint;
private ArrayList<Path> paths = new ArrayList<Path>();
Bitmap bmp;

public DrawView(Context context) {
    super(context);
    setFocusable(true);
    setFocusableInTouchMode(true);

    this.setOnTouchListener(this);
    bmp = BitmapFactory.decodeResource(getResources(), R.drawable.v01);
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(Color.BLUE);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(6);
    mCanvas = new Canvas();
    mPath = new Path();
    paths.add(mPath);

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(bmp, 0, 0, mPaint);
    for (Path p : paths) {
        canvas.drawPath(p, mPaint);
    }
}

private float mX, mY;
private static final float TOUCH_TOLERANCE = 0;
Draw dw = new Draw();

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 = new Path();
    paths.add(mPath);
}

@Override
public boolean onTouch(View arg0, 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;
}
}
Varitype answered 23/7, 2013 at 17:22 Comment(0)
C
0

Should work if you move canvas.drawBitmap() outside of the if statement. Keep the decoding there, but move the actual drawing out of it.

Confident answered 7/6, 2013 at 17:37 Comment(1)
Yeah it works, but reduce the performance, cause the app will have to draw bitmap on each onTouch Event... And, cause is a little paint, The onTouch event will be each 4 pixels... So it makes the app really slow...Varitype
L
0

I'm not really sure what's your issue here. you have to redraw the bitmap every time you run onDraw, or there will be nothing there. Have you actually noticed any performance loss there?

What you don't have to do is to decode the resource on every invalidate.

Declare your bmp as a global variable

Bitmap bmp;

Store the bitmap on your constructor:

DrawView(Context context){
  ...
  bmp = BitmapFactory.decodeResource(getResources(),
                    R.drawable.v01);
  }

and remove the if on your draw method. You don't want the if there. You MUST redraw the bitmap every time you call invalidate. But this should not cause any performance issues.

canvas.drawBitmap(bmp, 0, 0, mPaint);
Lightheaded answered 11/6, 2013 at 16:19 Comment(3)
I think that i don´t explain as well.. I have to use the bmp as a template, so if I change the color of the mPaint, the image doesnt change her color, so, i would like manipulate the image, erase a line... Something like a little paint...Varitype
Your approach will get you a finger paint, where you set the bitmap in the background and draw lines over it. If you want to manipulate the bitmap itself you'll need a different approach.Lightheaded
LOike which apporach, could you giveme an idea??Varitype
R
0

This will make your view really slow, but if you remove the if(start) statement, then your bitmap won't dissapear.

A slightly better way to do it would be to take the canvas.drawBitmap() outside the if(start) method, but that will still be slow because the bitmap is being draw each time you touch the screen.


In effect this is happening because each time onDraw() is called you are passed a blank bitmap. This means that you have to redraw everything each time onDraw is called, but because you are only setting the bitmap the first time, when on draw is called again the bitmap is not added again and so dissapears.

Roddy answered 11/6, 2013 at 19:26 Comment(0)
V
0

Solved,I used this code to can load an image and draw over it...

DrawView.java

package com.example.com.dibuja;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class DrawView extends View implements OnTouchListener {
private Canvas mCanvas;
private Path mPath;
public Paint mPaint;
private ArrayList<Path> paths = new ArrayList<Path>();
Bitmap bmp;

public DrawView(Context context) {
    super(context);
    setFocusable(true);
    setFocusableInTouchMode(true);

    this.setOnTouchListener(this);
    bmp = BitmapFactory.decodeResource(getResources(), R.drawable.v01);
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(Color.BLUE);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(6);
    mCanvas = new Canvas();
    mPath = new Path();
    paths.add(mPath);

}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
}

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(bmp, 0, 0, mPaint);
    for (Path p : paths) {
        canvas.drawPath(p, mPaint);
    }
}

private float mX, mY;
private static final float TOUCH_TOLERANCE = 0;
Draw dw = new Draw();

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 = new Path();
    paths.add(mPath);
}

@Override
public boolean onTouch(View arg0, 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;
}
}
Varitype answered 23/7, 2013 at 17:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.