Reputation: 3689
I want to create Digital signature application in android. It should capture user signature and store it as an image. If anybody know please let me know.
Upvotes: 14
Views: 19418
Reputation: 12063
Thanks to Harhal's answer , here's a way to get the bitmap without accessing the filesystem.
Yes the gestureView.buildDrawingCache()
API is deprecated, but for the time being this is a more acceptable solution in my case .. than asking users for save permission to support the entire app for just this one feature.
// .. continuing from Harhal's code here:
donebutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
gestureView.buildDrawingCache();
bitmap = gestureView.getDrawingCache();
// set bitmap somewhere
// eg: mBinding.signature.setImageBitmap(bitmap);
}
catch (Exception e) {
e.printStackTrace();
}
// Activity Stuff ...
}
});
To reset the view, the gestureView
got stuck for me on the first bitmap it loaded. Therefore, it seems just reloading the same fragment is the simplest way to get everything reset cleanly.
Below is pseudo code for this, as everyone seems to manage their fragment stack differently.
clearButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// Reload this fragment
// 1. Pop current fragment (current instance) from fragment stack
// 2. Set this same fragment again
}
});
Upvotes: 0
Reputation: 487
For a jpg file with white background:
gestureView.setDrawingCacheBackgroundColor(Color.WHITE);
and
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
using Harshal Benake solution.
Upvotes: 0
Reputation: 2401
hope this code helps you:)
esign_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.gesture.GestureOverlayView
android:id="@+id/signaturePad"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5"
android:background="@android:color/white"
android:clickable="false"
android:eventsInterceptionEnabled="true"
android:fadeEnabled="false"
android:gestureColor="#0000ff"
android:gestureStrokeLengthThreshold="0.1"
android:gestureStrokeType="multiple"
android:longClickable="false"
android:orientation="vertical"
android:uncertainGestureColor="#000000"
android:splitMotionEvents="true"
android:fadeOffset="10000000">
</android.gesture.GestureOverlayView>
<RelativeLayout
android:id="@+id/rellay_esign_donebutton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
>
<Button
android:id="@+id/DoneButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Done" />
<Button
android:id="@+id/ClearButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Clear" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
Esignature.java
public class Esignature extends Activity {
GestureOverlayView gestureView;
String path;
File file;
Bitmap bitmap;
public boolean gestureTouch=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.esign_main);
Button donebutton = (Button) findViewById(R.id.DoneButton);
donebutton.setText("Done");
Button clearButton = (Button) findViewById(R.id.ClearButton);
clearButton.setText("Clear");
path=Environment.getExternalStorageDirectory()+"/signature.png";
file = new File(path);
file.delete();
gestureView = (GestureOverlayView) findViewById(R.id.signaturePad);
gestureView.setDrawingCacheEnabled(true);
gestureView.setAlwaysDrawnWithCacheEnabled(true);
gestureView.setHapticFeedbackEnabled(false);
gestureView.cancelLongPress();
gestureView.cancelClearAnimation();
gestureView.addOnGestureListener(new OnGestureListener() {
@Override
public void onGesture(GestureOverlayView arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
}
@Override
public void onGestureCancelled(GestureOverlayView arg0,
MotionEvent arg1) {
// TODO Auto-generated method stub
}
@Override
public void onGestureEnded(GestureOverlayView arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
}
@Override
public void onGestureStarted(GestureOverlayView arg0,
MotionEvent arg1) {
// TODO Auto-generated method stub
if (arg1.getAction()==MotionEvent.ACTION_MOVE){
gestureTouch=false;
}
else
{
gestureTouch=true;
}
}});
donebutton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
try {
bitmap = Bitmap.createBitmap(gestureView.getDrawingCache());
file.createNewFile();
FileOutputStream fos = new FileOutputStream(file);
fos = new FileOutputStream(file);
// compress to specified format (PNG), quality - which is
// ignored for PNG, and out stream
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
if(gestureTouch==false)
{
setResult(0);
finish();
}
else
{
setResult(1);
finish();
}
}
});
clearButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
gestureView.invalidate();
gestureView.clear(true);
gestureView.clearAnimation();
gestureView.cancelClearAnimation();
}
});
}
}
Upvotes: 7
Reputation: 11093
Try a custom view instead of gestures:
package com.example.myapp.gui.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* A simple view to capture a path traced onto the screen. Initially intended to be used to captures signatures.
*
* @author Andrew Crichton
* @version 0.1
*/
public class SignatureView extends View {
private Path mPath;
private Paint mPaint;
private Paint bgPaint = new Paint(Color.TRANSPARENT);
private Bitmap mBitmap;
private Canvas mCanvas;
private float curX, curY;
private static final int TOUCH_TOLERANCE = 4;
private static final int STROKE_WIDTH = 4;
public SignatureView(Context context) {
super(context);
init();
}
public SignatureView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SignatureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
setFocusable(true);
mPath = new Path();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(STROKE_WIDTH);
}
public void setSigColor(int color) {
mPaint.setColor(color);
}
public void setSigColor(int a, int red, int green, int blue) {
mPaint.setARGB(a, red, green, blue);
}
public boolean clearSignature() {
if (mBitmap != null)
createFakeMotionEvents();
if (mCanvas != null) {
mCanvas.drawColor(Color.BLACK);
mCanvas.drawPaint(bgPaint);
mPath.reset();
invalidate();
}
else {
return false;
}
return true;
}
public Bitmap getImage() {
return this.mBitmap;
}
public void setImage(Bitmap bitmap) {
this.mBitmap = bitmap;
this.invalidate();
}
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
int bitmapWidth = mBitmap != null ? mBitmap.getWidth() : 0;
int bitmapHeight = mBitmap != null ? mBitmap.getWidth() : 0;
if (bitmapWidth >= width && bitmapHeight >= height)
return;
if (bitmapWidth < width)
bitmapWidth = width;
if (bitmapHeight < height)
bitmapHeight = height;
Bitmap newBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
Canvas newCanvas = new Canvas();
newCanvas.setBitmap(newBitmap);
if (mBitmap != null)
newCanvas.drawBitmap(mBitmap, 0, 0, null);
mBitmap = newBitmap;
mCanvas = newCanvas;
}
private void createFakeMotionEvents() {
MotionEvent downEvent = MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis()+100, MotionEvent.ACTION_DOWN, 1f, 1f ,0);
MotionEvent upEvent = MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis()+100, MotionEvent.ACTION_UP, 1f, 1f ,0);
onTouchEvent(downEvent);
onTouchEvent(upEvent);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
canvas.drawPath(mPath, mPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchDown(x, y);
break;
case MotionEvent.ACTION_MOVE:
touchMove(x, y);
break;
case MotionEvent.ACTION_UP:
touchUp();
break;
}
invalidate();
return true;
}
/**----------------------------------------------------------
* Private methods
**---------------------------------------------------------*/
private void touchDown(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
curX = x;
curY = y;
}
private void touchMove(float x, float y) {
float dx = Math.abs(x - curX);
float dy = Math.abs(y - curY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(curX, curY, (x + curX)/2, (y + curY)/2);
curX = x;
curY = y;
}
}
private void touchUp() {
mPath.lineTo(curX, curY);
if (mCanvas == null) {
mCanvas = new Canvas();
mCanvas.setBitmap(mBitmap);
}
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
}
}
Then, use this class in your XML: <com.example.myapp.gui.views.SignatureView .../>
To get the drawn signature, use this: Bitmap bmp = ((SignatureView)findViewById(R.id.signatureview)).getImage();
You can eventually save the bitmap with this code:
public void saveBitmap(Bitmap bmp) {
try {
String root = Environment.getExternalStorageDirectory().getAbsolutePath() + "/";
String filepath = root + "signature.jpg";
FileOutputStream fos = new FileOutputStream(filepath);
bmp.compress(CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
}
catch(Exception e) {
Log.e("Could not save", e.getMessage());
e.printStackTrace();
}
}
which will save the signature on the root of your sd card as signature.jpeg. For the writing part, make sure to have that permission in your manifest: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Upvotes: 16
Reputation: 6083
This can be done with the help of Gestureoverlay. This is demonstrated in the APIDemos. The following link must be helpful:
Upvotes: 0