Drawing on Canvas and save image
Solution 1
I saw really good code on android developers, but I can't find it anymore... It's output is bezier curves so it will be pretty smooth. Here is code that I edited:
public class MyDrawView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
public MyDrawView(Context c) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(3);
}
@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.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;
}
public void clear(){
mBitmap.eraseColor(Color.TRANSPARENT);
invalidate();
System.gc();
}}
then in onCreate of activity you want to use it in you just write something like this:
RelativeLayout parent = (RelativeLayout) findViewById(R.id.signImageParent);
myDrawView = new MyDrawView(this);
parent.addView(myDrawView);
This view is transparent and uses black paint to draw with your finger. So if you want see what you draw simply draw a white or gray bitmap on background of this view (you just add one line in the beginnig of onDraw), or you can use the background of the parent.
Then when you want to create an image from what you have drawn you just call
parent.setDrawingCacheEnabled(true);
Bitmap b = parent.getDrawingCache();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(getFileName());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
b.compress(CompressFormat.PNG, 95, fos);
It depends on what you want to have as output, you can use this code or instead of parent you can do this with myDrawView and you get just the image you have drawn without background (since we have our myDrawView background transparent).
Hope this will help. Feel free to leave feedback.
Solution 2
the drawing thing
Scribbler.java:
package org.yourpackage.scribble;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
public class Scribbler extends Activity {
DrawView drawView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawView = new DrawView(this);
drawView.setBackgroundColor(Color.WHITE);
setContentView(drawView);
drawView.requestFocus();
}
}
DrawView.java:
package org.yourpackage.scribble;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class DrawView extends View implements OnTouchListener {
List<Point> points = new ArrayList<Point>();
Paint paint = new Paint();
public DrawView(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
paint.setColor(Color.BLACK);
}
@Override
public void onDraw(Canvas canvas) {
for (Point point : points) {
canvas.drawCircle(point.x, point.y, 2, paint);
}
}
public boolean onTouch(View view, MotionEvent event) {
Point point = new Point();
point.x = event.getX();
point.y = event.getY();
points.add(point);
invalidate();
return true;
}
}
class Point {
float x, y;
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.yourpackage.scribble"
android:versionCode="1"
android:versionName="1.0">
<application>
<activity android:name=".Scribbler">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
..will give you something like that:
You may want to draw lines instead of pixels
the saving thing
To implement saving you can pass a Bitmap
into the Canvas
constructor, then use the compress
method of Bitmap
to create an OutputStream
which can be written to the SD card
EDIT to answer your comment:
Sure you can use XML to define your layout since DrawView
extends View you can use it in your layout xml file.
An example for the main.xml
layout file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:id="@+id/linearLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/gradient"
>
<Button android:text="Button" android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<org.yourpackage.scribble.DrawView android:id="@+id/drawView1" android:layout_width="wrap_content" android:layout_height="wrap_content"> </at.gru.android.drawdemo.DrawView>
</LinearLayout>
that gives you something like that:
You'll just need an additional contstructor public DrawView(Context context, AttributeSet attrSet)
Rahul Kalidindi
Solutions Architect and Dev Android iOS Mobile Apps Chatbots
Updated on January 26, 2022Comments
-
Rahul Kalidindi over 2 years
I am new to the Android Graphics class. I want to draw an image(actually a signature kind) using the touch events and want it to be saved on SDcard when I want to save it. I have scanned through the web for any such tutorials but I have not found any. Can anyone please tell me how to draw on canvas using the touch events and save it.
Any tutorials or sample code will be of great help.
-
Rahul Kalidindi over 12 yearsDo I need to create the buttons and labels from code if I want to insert any of the UI components? Can I use an XML Layout file for the UI components? Using the above example the drawing is not continuos. What should be done to achieve continuous drawing without breakages?
-
Rahul Kalidindi over 12 yearsThanks for the Edit Martin. One last thing. How can achieve smooth drawing without the breakages?
-
DonGru over 12 yearsuse the drawLine() method of the Canvas class instead of drawCircle - api doc
-
Rahul Kalidindi over 12 yearsThe same problem is occurring even when I use the drawLine() method... :-(
-
snapfractalpop about 12 years@RahulVarma, if you are using drawLine, you may need to adapt the code a bit. Drawing a line from a point to itself is like drawing a circle.. you'd want to draw a line from one point to the next. Depending on what you are trying to do, this can become complex (since you may not want lines between all consecutive points).
-
jigspatel over 11 yearsThanks for grate Answer. Realy help me.
-
Zahid H over 10 yearsI am using the same method for drawing on a canvas for letter practicing. How do I let the user draw lines in anyway they want? Also the background from using this example isn't showing up.
-
Zahid H over 10 yearsWhat if I have a TextView that I want to make it into a drawing board to allow free draw?
-
KarenAnne over 10 years@ZahidH You could try creating your own gradient. :)