I want to scribble on image with finger(on image not on white background) and I am using this code to draw on image.
it draw on image but when when i release the touch the draw disappear.
i think the problem is in crating canvas.
And also
The image that i load in large so only a portion of image is displayed. So how can i stretch and fit the full image in screen for drawing on it.
public class MyView extends View {
private ImageView image;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
private float mX, mY;
private final float TOUCH_TOLERANCE = 4;
public MyView(Context c,View v) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(0XFF000000);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(3);
image=(ImageView) v.findViewById(R.id.my_image);
}
#Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Scribbling on white background
// mBitmap=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
// mCanvas =new Canvas(mBitmap);
// Scribbling on image
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.batman);
mBitmap= Bitmap.createBitmap( mBitmap.getWidth() ,mBitmap.getHeight(), mBitmap.getConfig());
mCanvas =new Canvas(mBitmap.copy(Bitmap.Config.ARGB_8888, true));
}
#Override
public void onDraw(Canvas c) {
// c.drawBitmap(DrawingActivity.mBitmap, 0, 0, null);
c.drawBitmap(mBitmap, 0, 0,mBitmapPaint);
c.drawPath(mPath, mPaint);
}
#Override
public boolean onTouchEvent(MotionEvent e) {
float x=e.getX();
float y=e.getY();
switch(e.getAction()){
case MotionEvent.ACTION_DOWN:
touchStart(x,y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchMove(x,y);
this.invalidate();
break;
case MotionEvent.ACTION_UP:
touchUp(x,y);
invalidate();
}
return true;
}
private void touchUp(float x, float y) {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
}
private void touchMove(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 touchStart(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX=x;
mY=y;
}
}
please help
Related
Undo button need to remove paths from drawing. when i need to click again it needs to remove lastpath. It is not to clear all the draw, clear one by one from the last drawn path.Here i am drawing on canvas using path.
class DrawingView extends View {
Paint mPaint;
//MaskFilter mEmboss;
//MaskFilter mBlur;
Bitmap mBitmap;
Canvas mCanvas;
Path mPath;
float x,y;
Paint mBitmapPaint;
public DrawingView(Context context) {
super(context);
// TODO Auto-generated constructor stub
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(20);
mPath = new Path();
mBitmapPaint = new Paint();
/*mBitmapPaint.setColor(Color.RED);*/
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w==0)
{
w=1080;
}
if (mBitmap==null)
{
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
}
else
{
h= mBitmap.getHeight();
w=mBitmap.getWidth();
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
}
if (mCanvas==null)
{
mCanvas = new Canvas(mBitmap);
}
else
{
mCanvas=null;
mCanvas = new Canvas(mBitmap);
}
}
#Override
public void draw(Canvas canvas) {
// TODO Auto-generated method stub
super.draw(canvas);
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);
//mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
// kill this so we don't double draw
mPath.reset();
// mPath= new Path();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
x = event.getX();
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;
}
}
For a little project I have to write an Android application for drawing a line on the screen with fingers. At the moment I use this piece of code
ยด
public class MainActivity extends Activity {
DrawingView dv ;
private Paint mPaint;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dv = new DrawingView(this);
setContentView(dv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#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) {
super.onDraw(canvas);
canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath( mPath, mPaint);
canvas.drawPath( circlePath, circlePaint);
}
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;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// 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;
}
}
}
With this I'm able to draw a line on my screen but I have no Idea how convert the painted line to a bitmap. I think I understand it wrong but I think "mBitmap" is only an empty Bitmap and the "picture" is saved in "mCanvas".
So is there any way to convert the painted line in a Bitmap?
You need not create mBitmap or mCanvas for this. You could simply call View.getDrawingCache() to get the contents of the View. More info here.
But if you are planning to draw in your own bitmap, then you need to have a mBitmap and mCanvas. Follow the steps below to accomplish this:
Move the below lines into the constructor, since you want the bitmap and canvas creation only once.
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
In your onDraw() method, use the mCanvas to draw and not the canvas. Finally draw the mBitmap on to the view's canvas. Something like below:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// This will use the mCanvas and draw the `path` in the mBitmap.
mCanvas.drawPath( mPath, mPaint);
mCanvas.drawPath( circlePath, circlePaint);
// Now once everything is drawn on mBitmap, we will draw the contents of this mBitmap onto the underlying bitmap of the View via `canvas`.
canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
}
Always remember, every view will have an underlying bitmap (shared across). The canvas that you get in the onDraw() will help you draw stuff in the underlying bitmap. If you want to draw in your own bitmap, then you need to create a bitmap and a canvas, and draw using the canvas you created and not the one provided to you in the onDraw().
how can draw straight line using single finger or pan tool movement in android ?? when we draw one line through finger scratches, which is draw some zigzag. my exact Q? is that how to automatic straight ??
Hey ,i am using both quadTo() & lineTo() method but not exact straight line, plz improve that ANS.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dv = new DrawingView(this);
setContentView(dv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(4);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#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) {
super.onDraw(canvas);
canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath( mPath, mPaint);
canvas.drawPath( circlePath, circlePaint);
}
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;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// 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;
}
}
}
That's a BIG question, dude! If I were you, I'd start with a code sample like this. That will get you finger drawing non-straight lines on the Canvas. After that you, could start thinking about how to adapt this code to your purposes. Note that there are methods for touch_down and touch_up. You could experiment with redrawing a subset of the canvas each time touch_up is called, replacing whatever has been drawn since the last touch_down with a simple line (using canvas.lineTo()) that links the x/y on touch_down with the x/y on touch_up.
I need to implement a grayscale colorpicker that I need to put on the screen alongside the drawing canvas, so that when the user clicks on the grayscale colorpicker he selects a shade of gray.
Please see this example:
Solution found.
To those who might be interested:
public class ColorPickerView extends View {
private OnCustomEventListener mListener;
private Paint mPaint;
private Paint mPaint1;
private Paint mPaint2;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
public int color;
public ColorPickerView(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(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
LinearGradient grad = new LinearGradient(0, 0, canvas.getWidth(), 0, Color.WHITE, Color.BLACK, TileMode.CLAMP);
/* Draw your gradient to the top of your bitmap. */
Paint p = new Paint();
p.setStyle(Style.FILL);
p.setShader(grad);
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), p);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setColor(0xFF00B8F5);
paint.setLinearText(true);
paint.setTextSize(60);
canvas.drawText("SELECT COLOUR", mBitmap.getWidth()/4-40, mBitmap.getHeight()/3*2+5, paint);
}
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;
color= (int) (x/mBitmap.getWidth()*255);
if(mListener!=null) mListener.onEvent();
}
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();
}
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;
}
public interface OnCustomEventListener{
public void onEvent();
}
public void setCustomEventListener(OnCustomEventListener eventListener) {
mListener=eventListener;
}
}
In my Paint App I have implemented UNDO function and it's working fine. But if a change the paint brush color (or) paint brush stroke then all my previous drawn paths changing to the new paint color. The code is as follows:
public class CustomView extends View implements OnTouchListener {
public Canvas mCanvas;
private Path mPath;
public Paint mPaint, mBitmapPaint;
Bitmap mBitmap;
Canvas canvas;
public ArrayList<Path> paths = new ArrayList<Path>();
public ArrayList<Path> undonePaths = new ArrayList<Path>();
private Bitmap im;
public CustomView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
setOnTouchListener(this);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFFFFFF);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
mCanvas = new Canvas();
mPath = new Path();
im = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher);
DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
int w = metrics.widthPixels;
int h = metrics.heightPixels;
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
// mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
// mPath = new Path();
// canvas.drawPath(mPath, mPaint);
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
for (Path p : paths) {
canvas.drawPath(p, mPaint);
}
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
undonePaths.clear();
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
paths.add(mPath);
mPath = new Path();
}
public void onClickUndo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
} else {
}
// toast the user
}
public void onClickRedo() {
if (undonePaths.size() > 0) {
paths.add(undonePaths.remove(undonePaths.size() - 1));
invalidate();
} else {
}
// toast the user
}
#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;
}
}
This is an old question, but I wanted to leave an answer for anyone that comes here. The solution is to keep track of separate Paint instances for each stroke (there should be exactly 1 Paint object per Path object).
Change your touch_up method to reset the mPaint, in addition to resetting the mPath.
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
paths.add(mPath);
mPath = new Path();
mPaints.add(mPaint)
// Creates a new Paint reference, but keeps the previous state (color, width, etc.)
mPaint = new Paint(mPaint);
}
Then your onDraw method looks something like this.
for (int i = 0; i < mPaths.size(); i++) {
canvas.drawPath(mPaths.get(i), mPaints.get(i));
}