Kandha
Kandha

Reputation: 3689

digital signature in android

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

Answers (5)

Gene Bo
Gene Bo

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

Pep Santacruz
Pep Santacruz

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

Harshal Benake
Harshal Benake

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

stealthjong
stealthjong

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

Vicky Kapadia
Vicky Kapadia

Reputation: 6083

This can be done with the help of Gestureoverlay. This is demonstrated in the APIDemos. The following link must be helpful:

digital Signature

Upvotes: 0

Related Questions