Code to capture signature

Asked

Viewed 2,784 times

1

I need to know how to capture a signature made by a person on an Android screen to put into a document (virtually a digital signature).

2 answers

4

Your question is not very well defined, but I’ll try to help anyway.

There is nothing ready on "official" Android to do this, you need to assemble the pieces, or use a third party library not very well known. The idea is to create a canvas (screen space) where the user will draw freely with finger or Stylus. Then you will need to capture the formed image and then do what you want with it.

Recommended Option 1: Android Signature Pad

A great solution is the android-signaturepad library that can be found here: https://github.com/gcacace/android-signaturepad

It’s based on Square’s signature code and has a fantastic article showing the concept behind the idea: https://medium.com/square-corner-blog/smoother-signatures-be64515adb33#. aq576z753

Recommended Option 2: Signatureview

Another great option I found was the library Signatureview which can be found in:

https://github.com/zahid-ali-shah/SignatureView

It is a complete open source solution for what you want. The original answer with this solution can be seen here: https://stackoverflow.com/a/37314197/285678


There is another article, in English, that can be useful if you do not use the above option, because it implements exactly the joining of the pieces as I said at the beginning (although only record the generated image in a file, it is trivial to modify it to do what you want):

http://www.mysamplecode.com/2011/11/android-capture-signature-using-canvas.html

There is already an answer in Stack Overflow in English with an interesting implementation, which provides a View that you can use to capture signatures. The code is as follows::

public class CaptureSignatureView extends View {

    private Bitmap _Bitmap;
    private Canvas _Canvas;
    private Path _Path;
    private Paint _BitmapPaint;
    private Paint _paint;
    private float _mX;
    private float _mY;
    private float TouchTolerance = 4;
    private float LineThickness = 4;

    public CaptureSignatureView(Context context, AttributeSet attr) {
        super(context, attr);
        _Path = new Path();
        _BitmapPaint = new Paint(Paint.DITHER_FLAG);
        _paint = new Paint();
        _paint.setAntiAlias(true);
        _paint.setDither(true);
        _paint.setColor(Color.argb(255, 0, 0, 0));
        _paint.setStyle(Paint.Style.STROKE);
        _paint.setStrokeJoin(Paint.Join.ROUND);
        _paint.setStrokeCap(Paint.Cap.ROUND);
        _paint.setStrokeWidth(LineThickness);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        _Bitmap = Bitmap.createBitmap(w, (h > 0 ? h : ((View) this.getParent()).getHeight()), Bitmap.Config.ARGB_8888);
        _Canvas = new Canvas(_Bitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(_Bitmap, 0, 0, _BitmapPaint);
        canvas.drawPath(_Path, _paint);
    }

    private void TouchStart(float x, float y) {
        _Path.reset();
        _Path.moveTo(x, y);
        _mX = x;
        _mY = y;
    }

    private void TouchMove(float x, float y) {
        float dx = Math.abs(x - _mX);
        float dy = Math.abs(y - _mY);

        if (dx >= TouchTolerance || dy >= TouchTolerance) {
            _Path.quadTo(_mX, _mY, (x + _mX) / 2, (y + _mY) / 2);
            _mX = x;
            _mY = y;
        }
    }

    private void TouchUp() {
        if (!_Path.isEmpty()) {
            _Path.lineTo(_mX, _mY);
            _Canvas.drawPath(_Path, _paint);
        } else {
            _Canvas.drawPoint(_mX, _mY, _paint);
        }

        _Path.reset();
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        super.onTouchEvent(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);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                TouchUp();
                invalidate();
                break;
        }

        return true;
    }

    public void ClearCanvas() {
        _Canvas.drawColor(Color.WHITE);
        invalidate();
    }

    public byte[] getBytes() {
        Bitmap b = getBitmap();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        b.compress(Bitmap.CompressFormat.PNG, 100, baos);
        return baos.toByteArray();
    }

    public Bitmap getBitmap() {
        View v = (View) this.getParent();
        Bitmap b = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(b);
        v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
        v.draw(c);

        return b;
    }
}

To add this View to a Linearlayout you can do:

LinearLayout mContent = (LinearLayout) findViewById(R.id.linearLayout);
CaptureSignatureView mSig = new CaptureSignatureView(this, null);
mContent.addView(mSig, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);

To take an array of bytes with the signature data, or take a Bitmap directly from it use the code below:

byte[] signature = mSig.getBytes();
Bitmap signature = mSig.getBitmap();

You can then do whatever you want with these signature images. Then comes the less defined part of your question: what kind of document will you save this signature to? Just send it separately? Depending on your answer it can be quite difficult to implement this part.

1

Follow an example:

Drawview.java.

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;



public class DrawView extends View {

    Paint paint = new Paint();
    ArrayList<Line> lines = new ArrayList<Line>();
    Line currentLine;


    public DrawView(Context context, AttributeSet attrs) {
        super(context, attrs);

        paint.setAntiAlias(true);
        paint.setStrokeWidth(8f);
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
    }

    @Override
    protected void onDraw(Canvas canvas) {
            print(canvas);
    }

    /**
     * Desenha no canvas as linhas
     * @param canvas
     */
    private void print(final Canvas canvas){
        // Deesenha todas as linha já escritas
        for(final Line l : lines){
            int max = l.pointers.size()-1;
            for(int pt =0; pt < max; pt++ ) {
                Pointer pA = l.pointers.get(pt);
                Pointer pB = l.pointers.get(pt+1);
                canvas.drawLine(pA._x, pA._y, pB._x, pB._y, paint);
            }
        }
        // Desenha a linha corrente!
        if(currentLine != null){
            int max = currentLine.pointers.size()-1;
            for(int pt =0; pt < max; pt++ ) {
                Pointer pA = currentLine.pointers.get(pt);
                Pointer pB = currentLine.pointers.get(pt+1);
                canvas.drawLine(pA._x, pA._y, pB._x, pB._y, paint);
            }
        }
    }

    public Bitmap generateBitmap() {
        Bitmap b = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(b);
        print(c);
        return b;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Inicia uma nova linha
        if(event.getAction() == MotionEvent.ACTION_DOWN){
            currentLine = new Line();
            currentLine.addPointer(new Pointer(event.getX(), event.getY()));
            invalidate();
            return true;
        }else if(event.getAction() == MotionEvent.ACTION_MOVE) { // adiciona os pontos a linha
            currentLine.addPointer(new Pointer(event.getX(), event.getY()));
            invalidate();
            return true;
        }else if(event.getAction() == MotionEvent.ACTION_UP ){ // finaliza a linha
            lines.add(currentLine);
            currentLine = null;
            invalidate();
            return true;
        }else{
            return false;
        }
    }


    /**
     * Representa um ponto
     */
    class Pointer{
        float _x, _y;
        public Pointer(float _x, float _y){
            this._x = _x;
            this._y = _y;
        }
    }

    /**
     * Representa uma linha (formado por uma lista de pontos)
     */
    class Line {
        List<Pointer> pointers = new ArrayList<>();
        public void addPointer(final Pointer p){
            pointers.add(p);
        }
    }
}

XML:

<seu.pacote.DrawView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/assinatura"  />

Activity:

DrawView assinatura = DrawView.class.cast(findViewById(R.id.assinatura));

final Bitmap assinaturaBitmap = assinatura.generateBitmap();
  • 1

    Cool... it seems simple and it seems to work... then I’ll test.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.