Android digital signature

I want to create a digital signature application in android. It must capture the user's signature and save it as an image. If anyone knows, please let me know.

+9
android
source share
5 answers

Try creating 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 XML: <com.example.myapp.gui.views.SignatureView .../> To get a drawn signature, use this: Bitmap bmp = ((SignatureView)findViewById(R.id.signatureview)).getImage();

You can end up saving 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 in the root of your SD card as signature.jpeg. For part of the letter, make sure you have this permission in your manifest: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

+11
source share

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(); } }); } } 
+5
source share

This can be done using Gestureoverlay. This is demonstrated in APIDemos. The following link should be helpful:

digital signature

0
source share

For a jpg file with a white background:

 gestureView.setDrawingCacheBackgroundColor(Color.WHITE); 

and

 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); 

using the Harshal Benake solution .

0
source share

Thanks to Harhal’s answer , there is a way to get a bitmap without access to the file system.

Yes, the gestureView.buildDrawingCache() API is out of date, but at the moment this is a more acceptable solution in my case ... than asking users for permission to save to support the entire application for this only function.

  // .. continuing from Harhal 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, gestureView stuck for me on the first bitmap loaded. Therefore, it seems that just reloading the same fragment is the easiest way to do it all over again.

Below is the pseudo-code for this, since each seems to have its own control over its fragment stack.

  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 } }); 
0
source share

All Articles