Android capture signature using Canvas and save in png format

Signature capture has a lot of uses in enterprise applications such as proof of delivery, inspection forms, sales order agreement, etc. Here is sample program that asks for the name of the person and its signature. The program uses a canvas view to get the signature and then save it as .png Image.

Android capture signature using Canvas
Android capture signature using Canvas
Please Note: Initially when I wrote the signature capture program it was saving data to the External Storage but then I changed that to the Internal Storage for security. In the example you will see references to External storage that I didn't remove when I posted this example so please ignore that. Comments from the readers made me realize that some people need help with storing data to Internal and External Storage, click below for sample code ...
Android Internal and External storage example

In case you want signature capture for a WEB app or a Hybrid app then no further, click below for sample code ...
Capture signature using HTML5 canvas - Use for iPad, iPhone, Android Tablets and Phones

Source for CaptureSignatureActivity.java

package com.as400samplecode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class CaptureSignatureActivity extends Activity {

    public static final int SIGNATURE_ACTIVITY = 1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button getSignature = (Button) findViewById(R.id.signature);
        getSignature.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                Intent intent = new Intent(CaptureSignatureActivity.this, CaptureSignature.class); 
                startActivityForResult(intent,SIGNATURE_ACTIVITY);
            }
        });
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        switch(requestCode) {
        case SIGNATURE_ACTIVITY: 
            if (resultCode == RESULT_OK) {

                Bundle bundle = data.getExtras();
                String status  = bundle.getString("status");
                if(status.equalsIgnoreCase("done")){
                    Toast toast = Toast.makeText(this, "Signature capture successful!", Toast.LENGTH_SHORT);
                    toast.setGravity(Gravity.TOP, 105, 50);
                    toast.show();
                }
            }
            break;
        }

    }  

}

Source for CaptureSignature.java

package com.as400samplecode;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Calendar;

import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore.Images;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;

public class CaptureSignature extends Activity { 

    LinearLayout mContent;
    signature mSignature;
    Button mClear, mGetSign, mCancel;
    public static String tempDir;
    public int count = 1;
    public String current = null;
    private Bitmap mBitmap;
    View mView;
    File mypath;

    private String uniqueId;
    private EditText yourName;

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.signature);
       
        tempDir = Environment.getExternalStorageDirectory() + "/" + getResources().getString(R.string.external_dir) + "/";
        ContextWrapper cw = new ContextWrapper(getApplicationContext());
        File directory = cw.getDir(getResources().getString(R.string.external_dir), Context.MODE_PRIVATE);

        prepareDirectory();
        uniqueId = getTodaysDate() + "_" + getCurrentTime() + "_" + Math.random();
        current = uniqueId + ".png";
        mypath= new File(directory,current);


        mContent = (LinearLayout) findViewById(R.id.linearLayout);
        mSignature = new signature(this, null);
        mSignature.setBackgroundColor(Color.WHITE);
        mContent.addView(mSignature, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
        mClear = (Button)findViewById(R.id.clear);
        mGetSign = (Button)findViewById(R.id.getsign);
        mGetSign.setEnabled(false);
        mCancel = (Button)findViewById(R.id.cancel);
        mView = mContent;

        yourName = (EditText) findViewById(R.id.yourName);

        mClear.setOnClickListener(new OnClickListener() 
        {        
            public void onClick(View v) 
            {
                Log.v("log_tag", "Panel Cleared");
                mSignature.clear();
                mGetSign.setEnabled(false);
            }
        });

        mGetSign.setOnClickListener(new OnClickListener() 
        {        
            public void onClick(View v) 
            {
                Log.v("log_tag", "Panel Saved");
                boolean error = captureSignature();
                if(!error){
                    mView.setDrawingCacheEnabled(true);
                    mSignature.save(mView);
                    Bundle b = new Bundle();
                    b.putString("status", "done");
                    Intent intent = new Intent();
                    intent.putExtras(b);
                    setResult(RESULT_OK,intent);   
                    finish();
                }
            }
        });

        mCancel.setOnClickListener(new OnClickListener() 
        {        
            public void onClick(View v) 
            {
                Log.v("log_tag", "Panel Canceled");
                Bundle b = new Bundle();
                b.putString("status", "cancel");
                Intent intent = new Intent();
                intent.putExtras(b);
                setResult(RESULT_OK,intent);  
                finish();
            }
        });

    }

    @Override
    protected void onDestroy() {
        Log.w("GetSignature", "onDestory");
        super.onDestroy();
    }

    private boolean captureSignature() {

        boolean error = false;
        String errorMessage = "";


        if(yourName.getText().toString().equalsIgnoreCase("")){
            errorMessage = errorMessage + "Please enter your Name\n";
            error = true;
        }   

        if(error){
            Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
            toast.setGravity(Gravity.TOP, 105, 50);
            toast.show();
        }

        return error;
    }

    private String getTodaysDate() { 

        final Calendar c = Calendar.getInstance();
        int todaysDate =     (c.get(Calendar.YEAR) * 10000) + 
        ((c.get(Calendar.MONTH) + 1) * 100) + 
        (c.get(Calendar.DAY_OF_MONTH));
        Log.w("DATE:",String.valueOf(todaysDate));
        return(String.valueOf(todaysDate));

    }

    private String getCurrentTime() {

        final Calendar c = Calendar.getInstance();
        int currentTime =     (c.get(Calendar.HOUR_OF_DAY) * 10000) + 
        (c.get(Calendar.MINUTE) * 100) + 
        (c.get(Calendar.SECOND));
        Log.w("TIME:",String.valueOf(currentTime));
        return(String.valueOf(currentTime));

    }


    private boolean prepareDirectory() 
    {
        try 
        {
            if (makedirs()) 
            {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) 
        {
            e.printStackTrace();
            Toast.makeText(this, "Could not initiate File System.. Is Sdcard mounted properly?", 1000).show();
            return false;
        }
    }

    private boolean makedirs() 
    {
        File tempdir = new File(tempDir);
        if (!tempdir.exists())
            tempdir.mkdirs();

        if (tempdir.isDirectory()) 
        {
            File[] files = tempdir.listFiles();
            for (File file : files) 
            {
                if (!file.delete()) 
                {
                    System.out.println("Failed to delete " + file);
                }
            }
        }
        return (tempdir.isDirectory());
    }

    public class signature extends View 
    {
        private static final float STROKE_WIDTH = 5f;
        private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
        private Paint paint = new Paint();
        private Path path = new Path();

        private float lastTouchX;
        private float lastTouchY;
        private final RectF dirtyRect = new RectF();

        public signature(Context context, AttributeSet attrs) 
        {
            super(context, attrs);
            paint.setAntiAlias(true);
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeJoin(Paint.Join.ROUND);
            paint.setStrokeWidth(STROKE_WIDTH);
        }

        public void save(View v) 
        {
            Log.v("log_tag", "Width: " + v.getWidth());
            Log.v("log_tag", "Height: " + v.getHeight());
            if(mBitmap == null)
            {
                mBitmap =  Bitmap.createBitmap (mContent.getWidth(), mContent.getHeight(), Bitmap.Config.RGB_565);;
            }
            Canvas canvas = new Canvas(mBitmap);
            try 
            {
                FileOutputStream mFileOutStream = new FileOutputStream(mypath);

                v.draw(canvas); 
                mBitmap.compress(Bitmap.CompressFormat.PNG, 90, mFileOutStream); 
                mFileOutStream.flush();
                mFileOutStream.close();
                String url = Images.Media.insertImage(getContentResolver(), mBitmap, "title", null);
                Log.v("log_tag","url: " + url);
                //In case you want to delete the file
                //boolean deleted = mypath.delete();
                //Log.v("log_tag","deleted: " + mypath.toString() + deleted);
                //If you want to convert the image to string use base64 converter

            }
            catch(Exception e) 
            { 
                Log.v("log_tag", e.toString()); 
            } 
        }

        public void clear() 
        {
            path.reset();
            invalidate();
        }

        @Override
        protected void onDraw(Canvas canvas) 
        {
            canvas.drawPath(path, paint);
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) 
        {
            float eventX = event.getX();
            float eventY = event.getY();
            mGetSign.setEnabled(true);

            switch (event.getAction()) 
            {
            case MotionEvent.ACTION_DOWN:
                path.moveTo(eventX, eventY);
                lastTouchX = eventX;
                lastTouchY = eventY;
                return true;

            case MotionEvent.ACTION_MOVE:

            case MotionEvent.ACTION_UP:

                resetDirtyRect(eventX, eventY);
                int historySize = event.getHistorySize();
                for (int i = 0; i < historySize; i++) 
                {
                    float historicalX = event.getHistoricalX(i);
                    float historicalY = event.getHistoricalY(i);
                    expandDirtyRect(historicalX, historicalY);
                    path.lineTo(historicalX, historicalY);
                }
                path.lineTo(eventX, eventY);
                break;

            default:
                debug("Ignored touch event: " + event.toString());
                return false;
            }

            invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH),
                    (int) (dirtyRect.top - HALF_STROKE_WIDTH),
                    (int) (dirtyRect.right + HALF_STROKE_WIDTH),
                    (int) (dirtyRect.bottom + HALF_STROKE_WIDTH));

            lastTouchX = eventX;
            lastTouchY = eventY;

            return true;
        }

        private void debug(String string){
        }

        private void expandDirtyRect(float historicalX, float historicalY) 
        {
            if (historicalX < dirtyRect.left) 
            {
                dirtyRect.left = historicalX;
            } 
            else if (historicalX > dirtyRect.right) 
            {
                dirtyRect.right = historicalX;
            }

            if (historicalY < dirtyRect.top) 
            {
                dirtyRect.top = historicalY;
            } 
            else if (historicalY > dirtyRect.bottom) 
            {
                dirtyRect.bottom = historicalY;
            }
        }

        private void resetDirtyRect(float eventX, float eventY) 
        {
            dirtyRect.left = Math.min(lastTouchX, eventX);
            dirtyRect.right = Math.max(lastTouchX, eventX);
            dirtyRect.top = Math.min(lastTouchY, eventY);
            dirtyRect.bottom = Math.max(lastTouchY, eventY);
        }
    }
}

Source for main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/hello"
        android:textSize="25sp" android:paddingBottom="20dp"
        android:textStyle="bold" />
    <Button android:text="Get My Signature" android:id="@+id/signature"
        android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>

Source for signature.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/linearLayout1"
    android:layout_width="600dp" android:layout_height="400dp"
    android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android">
    <LinearLayout android:layout_height="wrap_content"
        android:id="@+id/linearLayout2" android:layout_width="match_parent">
        <Button android:layout_height="50dp" android:layout_weight=".30"
            android:text="Cancel" android:layout_width="0dp" android:id="@+id/cancel" />
        <Button android:layout_height="50dp" android:layout_weight=".35"
            android:text="Clear" android:layout_width="0dp" android:id="@+id/clear" />
        <Button android:layout_height="50dp" android:layout_weight=".35"
            android:text="Save" android:layout_width="0dp" android:id="@+id/getsign" />
    </LinearLayout>
    <TableLayout android:layout_height="wrap_content"
        android:id="@+id/tableLayout1" android:layout_width="match_parent">
        <TableRow android:id="@+id/tableRow1" android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView android:layout_height="wrap_content" android:id="@+id/textView2"
                android:text="Your Name" android:textAppearance="?android:attr/textAppearanceMedium"
                android:layout_width="wrap_content" android:paddingLeft="10sp"
                android:layout_gravity="right" />
            <EditText android:layout_height="wrap_content" android:id="@+id/yourName"
                android:layout_weight="1" android:layout_width="match_parent"
                android:maxLength="30">
                <requestFocus />
            </EditText>
        </TableRow>
        <TableRow android:id="@+id/tableRow3" android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView android:layout_height="wrap_content" android:id="@+id/textView2"
                android:text="" android:maxLength="30"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:layout_width="wrap_content" />
            <TextView android:layout_height="wrap_content" android:id="@+id/textView2"
                android:text="Please Sign below ..." android:maxLength="30"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:layout_width="wrap_content" />
        </TableRow>
    </TableLayout>
    <LinearLayout android:layout_height="match_parent"
        android:id="@+id/linearLayout" android:layout_width="match_parent" />
</LinearLayout>

Source for AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.as400samplecode" android:versionCode="1"
    android:versionName="1.0">
    <uses-sdk android:minSdkVersion="13" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   
    <application android:icon="@drawable/icon" android:label="@string/app_name"
        android:theme="@android:style/Theme.Holo.Light">
        <activity android:name=".CaptureSignatureActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".CaptureSignature" android:label="Signature Confirmation"
            android:theme="@android:style/Theme.Holo.Light.Dialog" />
    </application>
</manifest>

Source for strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, CaptureSignatureActivity!</string>
    <string name="app_name">CaptureSignature</string>
    <string name="external_dir">GetSignature</string>
</resources>

Android capture signature using Canvas

Steps to Run the application on an Android Phone with Version 2.3.3 API level 10


1) Change your project build Target to Android 2.3.3


2) CaptureSignature manifest file Androidmanifest.xml with version and Theme changes as Holo theme is not available in API level 10.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.as400samplecode" android:versionCode="1"
    android:versionName="1.0">
    <uses-sdk android:minSdkVersion="10" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   
    <application android:icon="@drawable/icon" android:label="@string/app_name"
        android:theme="@android:style/Theme.Light">
        <activity android:name=".CaptureSignatureActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".CaptureSignature" android:label="Signature Confirmation"
            android:theme="@android:style/Theme.Dialog" />
    </application>
</manifest>

3) Change the signature.xml file with new layout width and height
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/linearLayout1"
    android:layout_width="400dp" android:layout_height="300dp"
    .......


Signature capture in Android Phone with Version 2.3.3 API level 10
Signature capture in Android Phone with Version 2.3.3 API level 10

How to display the saved signature from base64 String

 //convert the string to byte array
 byte[] imageAsBytes = Base64.decode(myStringImage.getBytes());
 //get reference to the image view where you want to display the image
 ImageView image = (ImageView)this.findViewById(R.id.ImageView);
 //set the image by decoding the byte array to bitmap
 image.setImageBitmap(
  BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
 );

180 comments :

  1. Hi,
    Thanks for posting this code. Please give download link for full source code. Also is there anyway to run and test this on emulator.

    Thanks
    Sampath

    ReplyDelete
  2. This is the complete source code for the android signature application. You just need to copy and paste the code.

    Yes it does run on the emulator !

    ReplyDelete
    Replies
    1. Can u please provide a link to this project. I'm having issues with layout files when I copy the code. Thanks.

      Delete
    2. how do you pass to another intent

      Delete
  3. Hi,
    Thanks for this tutorial.But i have an issue.Unable to write something in the Gesture(@+id/linearLayout) clearly.It shows broken gesture.
    Pls help to avoid this.Thanks..

    ReplyDelete
  4. you are really great!! appreciate your work man!!!

    ReplyDelete
  5. It doesnt recognise external_dir. Any suggestions?

    ReplyDelete
  6. davemcavanagh,

    the external_dir is just a variable to be defined in the Strings.xml file. You can set it to any value where you would like to store this signature.

    ReplyDelete
  7. Thanks. Will this only work with minSdkVersion="13"? I have tried running it with 10 and I get an error
    E/AndroidRuntime(1248): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.as400samplecode/com.as400samplecode.CaptureSignatureActivity}: java.lang.ClassNotFoundException: com.as400samplecode.CaptureSignatureActivity in loader dalvik.system.PathClassLoader[/data/app/com.as400samplecode-2.apk]

    Any advice appreciated!

    ReplyDelete
  8. davemcavanagh,

    Yes, the application runs on Android Phone with API level 10. Please see my notes above, I have updated a few things.

    ReplyDelete
    Replies
    1. please give me your e-mail address...

      Delete
    2. yeapkai@hotmail.my
      Please send me source code

      Delete
  9. Thanks a million it works now! I have just one more question.

    I have declared external_dir in my strings file as a string name. Im sure this is wrong. How do I access my saved signature?

    Cheers

    ReplyDelete
    Replies
    1. will you please send me the project of this app on waqas_1231@hotmail.com... i copy the code but it is not working...

      Delete
    2. I had to fix a few errors in the code that Eclipse helpfully pointed out, but I can't get it to run either!

      Delete
  10. OK I have worked out that the signature is being stored in the external storage of my device. This is done by the use of

    getExternalStorageDirectory()

    Is there a way of accessing this external storage so that I can send the signature to an sqlite database?

    ReplyDelete
  11. Yes, all you have to do is just create a FileInputStream as shown below.

    FileInputStream mFileInputStream = new FileInputStream(mypath);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] b = new byte[1024];
    int bytesRead = 0;
    while ((bytesRead = mFileInputStream.read(b)) != -1) {
    bos.write(b, 0, bytesRead);
    }
    byte[] ba = bos.toByteArray();
    String ba1=Base64.encodeBytes(ba);

    -- OR --

    Base64.encodeFromFile(mypath.toString() //to convert directy from file to String.

    I am using the Base64 encoding here. Then you can send this string to Server as XML or JSON. For more information check this.

    Convert Image to String and String to Image using Base64 encoding

    ReplyDelete
  12. Hi,

    This is exactly what I need, but the problem that I am having is that I am getting some error saying, "external_dir cannot be resolved or is not a field" and the only suggestions are to create a string or rename it. I know this is something simple but I'm not sure what an easy fix would be, I assume it would be to declare this string, assign value, then use it where it is called in the code? Any help would be greatly appreciated, thanks!

    ReplyDelete
  13. I have added the Project explorer for the Signature Capture App and the Strings.xml file. Please see above for help with external_dir.

    ReplyDelete
  14. What license is this under?

    ReplyDelete
  15. Can I use it under Apache or MIT?

    ReplyDelete
  16. Please do as you wish and if you find a way to use this code in your project in any form and improve on it, it would be nice if you can share some of that with the readers of this blog.

    Good luck!

    ReplyDelete
  17. This is an outstanding tutorial, really great stuff. And thanks for sharing this with all.....

    ReplyDelete
  18. outstanding tutorial,Thnk you vry much.

    ReplyDelete
  19. I wanted to draw a line but this is the result.
    http://postimage.org/image/eq7j4baqt/

    any suggestions?

    ReplyDelete
  20. Milton,

    Can you please elaborate a little. What is the issue here? Is it regarding the image getting cut off? This application for signature capture is a canvas for your to draw anything and save as a png image.

    ReplyDelete
  21. Thank you for your code ! I launched appli in 2 minutes without any problems.

    ReplyDelete
  22. Hi! The problem is that by making a figure, lines are going down ... In the picture I uploaded, I just did a horizontal line but the result was another.

    ReplyDelete
  23. Milton,

    Not sure how that's happening. If you could provide the link to your source code may be I can find something.

    ReplyDelete
  24. Hey Nice work..Thanks a lott....My image is being saved plz can u help..How can I save an image with my own unique Image Name? Like u have given image in which yourName has the text:BetterThanZero and signature is It Works.So cn u plz help me in coding to save IT works with the Name BetterThanZero.
    Thanks and Regards

    ReplyDelete
  25. The following lines create the filename. Here I am creating a unique filename using current date and time. Change it according to your need ...


    uniqueId = getTodaysDate() + "_" + getCurrentTime() + "_" + Math.random();
    current = uniqueId + ".png";
    mypath= new File(directory,current);

    ReplyDelete
  26. Hi, thanks for your tutorial.
    I have test on my device(HTC 2.3.3), but in the 'GetSignature' folder, there is empty file. The signature didn't save. Why this happen.
    My project run as android 2.2 API 8.

    ReplyDelete
  27. ok, thanks, I have change 'mypath'

    ReplyDelete
    Replies
    1. I have the same issue. Can u tell us what path you have.

      Delete
  28. Super Thanks!!!

    ReplyDelete
  29. Hi, im new to android.
    I try to copy the code provided above into the eclipse but it keep showing me with the error R cannot resolved to a variable.
    Why is this happening? can help?

    ReplyDelete
  30. if you used ctrl-shift-o then eclipse might have added import android.R

    I removed this and the code worked.

    ReplyDelete
  31. Is there a way to set a background image?

    ReplyDelete
  32. You can set the background color
    mSignature.setBackgroundColor(Color.WHITE);

    ReplyDelete
  33. Hi,

    Great blog with excellent posts and code.

    I've used the following to convert my "signature" to Base64 but it's cutting the image before the end.

    FileInputStream mFileInputStream = new FileInputStream(mypath);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] b = new byte[1024];
    int bytesRead = 0;
    while ((bytesRead = mFileInputStream.read(b)) != -1) {
    bos.write(b, 0, bytesRead);
    }
    byte[] ba = bos.toByteArray();
    String ba1=Base64.encodeBytes(ba);

    Can you tell me why or how can I solve the problem?

    ReplyDelete
  34. It has nothing to do with base64 conversion. I vaguely remember it has to do with this line of code

    mBitmap = Bitmap.createBitmap (mContent.getWidth(), mContent.getHeight(), Bitmap.Config.RGB_565);;

    Try increasing the size here. It has to match the canvas size in the view for complete image.

    ReplyDelete
  35. I ran the code on emulator and it created a file in the folder:
    /data/data/com.example.signature/app_GetSignature/20120525_201312_0.10451272391892374.png rather than the folder /mnt/sdcard/GetSignature
    It also created the jpg image in the /mnt/sdcard/DCIM/Camera folder. Please advice.
    Thank you.

    ReplyDelete
  36. I love this application but my only problem is I need to store the file to /data/data/package_name/files. I do not have an sd card and will be testing it on a tablet which does not either. I have searched the internet and have found nothing that could help me speficially as to where and what I am supposed to put to store it in such a directory. Thanks!

    ReplyDelete
  37. This application saves the signature to the Android Internal Storage even though there are some references to the External Storage in the sample program. Some lines are redundant in there, hope it clears any further confusion for the readers...

    ReplyDelete
    Replies
    1. I appreciate your work,but how to save image.png file in mnt/sdcard/GetSignature ??

      Delete
  38. hi iam gettinga problem like this.:
    getsignature empty folder is creating
    in sdcard. signature is not saving(png image is not saving)in the folder
    in logcat its showing like this:
    06-11 12:23:38.085: W/WindowManager(74): Failure taking screenshot for (230x135) to layer 21010
    please help me
    Thanks

    ReplyDelete
  39. I ran the code on emulator and it created a file in the folder:
    /data/data/com.example.signature/app_GetSignature/20120525_201312_0.10451272391892374.png rather than the folder /mnt/sdcard/GetSignature
    It also created the jpg image in the /mnt/sdcard/DCIM/Camera folder. Please advice.
    Thank you.

    ReplyDelete
  40. /data/data/com.example.signature/app_GetSignature/20120525_201312_0.10451272391892374.png is alright. Not sure how it created a Jpeg in Camera Folder. The folder in /mnt/sdcard/GetSignature is also okay as I mentioned before that I started with External Storage and then converted to Internal Storage and left some of the code in there.

    ReplyDelete
  41. I used your script to save the signature to SQLite using Base64. Now I need some guidance to load/present/show (on a canvas) the saved signature?

    Your help will be appreciated

    Regards

    ReplyDelete
  42. Added a section for displaying a Base64 string back as image, basically the signature in this case.

    ReplyDelete
  43. Application is perfect but I got an error that "Failed to insert image" when application rich at line String url = Images.Media.insertImage.
    Please anyone give me suggestion.

    ReplyDelete
  44. this is very good app that i have to very helpful and others..

    ReplyDelete
  45. Thank you for all the work and excellent coverage on a pretty complex challenge. Great job!

    ReplyDelete
  46. I really found this blog very useful.I was able run the application. :)

    But i was not able to retrieve the image which is being saved using your code!What should i do?Can you just tell me what should i have to replace with "myStringImage"?

    ReplyDelete
  47. Good blog.If i set a background image for the signature part,then how can i 'save and retrieve'the image?background image+ the signature?

    ReplyDelete
  48. how to put dot while doing signature in this application? if any one knows the answer please help me.its urgent....

    ReplyDelete
    Replies
    1. case MotionEvent.ACTION_MOVE:

      case MotionEvent.ACTION_UP:
      if(lastTouchX==eventX && lastTouchY==eventY && event.getAction()==MotionEvent.ACTION_UP) {//caso del punto
      path.addCircle(eventX, eventY, 1, Direction.CW);
      }

      add this "if" on the code

      Delete
  49. Hi BetterthanZero.

    This isa excellent code. All is going well but I am not seeing captured signature in the folder. Folder is empty. What path should I mention in the code to see signature image in the phone. I have g2x phone

    ReplyDelete
    Replies
    1. This example saves the signature in the Internal Storage for the application. Please check this out Android Internal and External storage example - Store and Retrieve Data

      Delete
    2. Thank you so much !

      Delete
  50. When I am running this application... my R.java get deleted while cleaning and resource.ap_ file get deleted how to resolve this issues..

    ReplyDelete
  51. i am using android 2.2 , is it work for 2.2 ?

    ReplyDelete
    Replies
    1. it's working on 2.2 just i changed min sdk to 8

      Delete
  52. Hi,
    i dont want to store images in DCIM/Camera.
    How to restrict this ? please help me to solve this issue

    ReplyDelete
  53. Thanks a lot dear..............................................

    ReplyDelete
  54. I got an error that "Failed to insert image" when application rich at line String url = Images.Media.insertImage
    Please help me to solve this

    ReplyDelete
  55. I forgot to say that is log_tag url:null.

    ReplyDelete
    Replies
    1. Comment those 2 lines out. Its already writing to the file. That's for the image to show up in the media library and you will not be doing that for a signature.

      Delete
    2. Thank you so much!

      Delete
  56. can anyonw send me this project..@ sampath.muddineni@gmail.com

    ReplyDelete
  57. BetterThanZero,

    Great instructional code! It has already helped immeasurably. I have aquestion I was wondering if you could quickly answer:

    If the filename for a signature file is known, how you would you initially open the file and display the contents?

    Thank you!

    ReplyDelete
    Replies
    1. I forgot to mention that perhaps the code could either reside in the signature constructor or exist as a public method in the signature class.

      Delete
    2. You can display the signature in a ImageView.

      Bitmap image = BitmapFactory.decodeFile(path);
      imageView.setImageBitmap(image);

      Delete
    3. Thank you, but I was trying to display the saved bitmap in the canvas that is part of the signature. The user can "edit" the signature.

      Delete
  58. Hmm great tutorial! However I need help with something which is the part on the saving as the .png file with the specified filename (current). I ran the application but the signature does not get stored in the specified directory but instead was saved in the mnt/sdcard/DCIM/Camera folder. Anyone with the same problem?

    ReplyDelete
    Replies
    1. Yes, same problem here, I tried to make so many changes but it is still not working

      Delete
    2. change mypath decleration to this
      mypath= new File(tempDir,current);
      and it will store it to GetSignature Folder.

      Delete
  59. One flaw though,

    The users rest their hands on the tab while signing, haha. Any code to only make the three buttons, the name box and the sign area accepting touch input?

    Kind Regards, your code works great!! on slower devices, the signature comes out to be curves made of straight lines.

    ReplyDelete
  60. Hi,It is really a nice code. can u plz tell me how to paste my signature in any of the document like pdf,word etc

    ReplyDelete
  61. Nice article. I have one quick question. How to resize the signature view/image in desired width and length before storing in external storage?

    ReplyDelete
  62. This code worked first time and was exactly what i needed so thanks alot for sharing.

    The one thing im having problems with is I need 2 signatures and names to be taken. Ive attempted to do this but when i take the second signature it overwrites the first. Any ideas what im doing wrong.

    Cheers

    Si


    public class CaptureSignatureActivity extends Activity {

    public static final int SIGNATURE_ACTIVITY = 1;
    public static final int SIGNATURE_ACTIVITY1 = 2;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.startmenu);

    Button getSignature = (Button) findViewById(R.id.signature);
    Button getSignature2 = (Button) findViewById(R.id.signature2);



    getSignature.setOnClickListener(new View.OnClickListener() {
    public void onClick(View view) {
    Intent intent = new Intent(CaptureSignatureActivity.this, CaptureSignature.class);
    startActivityForResult(intent,SIGNATURE_ACTIVITY);
    }
    });

    getSignature2.setOnClickListener(new View.OnClickListener() {
    public void onClick(View view) {
    Intent intent = new Intent(CaptureSignatureActivity.this, CaptureSignature.class);
    startActivityForResult(intent,SIGNATURE_ACTIVITY1);
    }
    });

    }


    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
    switch(requestCode) {
    case SIGNATURE_ACTIVITY:
    if (resultCode == RESULT_OK) {
    final ImageView mImg;


    final TextView mname = (TextView) findViewById(R.id.srname);
    mname.setText(CaptureSignature.srnametostring);


    mImg = (ImageView) findViewById(R.id.sigview1);
    mImg.setImageBitmap(CaptureSignature.mBitmap);


    Bundle bundle = data.getExtras();
    String status = bundle.getString("status");
    if(status.equalsIgnoreCase("done")){
    Toast toast = Toast.makeText(this, "Signature capture successful!", Toast.LENGTH_SHORT);
    toast.setGravity(Gravity.TOP, 105, 50);
    toast.show();
    }
    }
    break;
    case SIGNATURE_ACTIVITY1:
    if (resultCode == RESULT_OK) {
    final ImageView mImg1;



    final TextView mname2 = (TextView) findViewById(R.id.srname2);
    mname2.setText(CaptureSignature.srnametostring);


    mImg1 = (ImageView) findViewById(R.id.sigview2);
    mImg1.setImageBitmap(CaptureSignature.mBitmap);


    Bundle bundle = data.getExtras();
    String status = bundle.getString("status");
    if(status.equalsIgnoreCase("done")){
    Toast toast = Toast.makeText(this, "Signature capture successful!", Toast.LENGTH_SHORT);
    toast.setGravity(Gravity.TOP, 105, 50);
    toast.show();
    }
    }
    break;
    }


    }
    }

    ReplyDelete
  63. Please can u help me how to save the file in mnt/sdcard/getDirectory???

    ReplyDelete
  64. Great job :) Thanks for sharing :)

    ReplyDelete
  65. Its really awesome thank you so much.i want send this image to web app of mine please help me to do

    ReplyDelete
  66. Awesome, dude. Works great. Thanks so much. I built something like this for iOS and was not really up to recreating it for Android, so you saved me a lot of time. One thing I did in iOS that I will probably retrofit to this when I get a chance is curve smoothing - makes the signatures look better. I think all I did was a continuous substitution of every few points in the path with a bezier curve.

    Thanks again.

    bh

    ReplyDelete
  67. i just need full code line by line explanation for capturesignature.java

    ReplyDelete
  68. hi i used all these codes.all are working goodly,but how to store captured signature and where to put the last para of code am confuse..........

    ReplyDelete
    Replies
    1. please say me how to convert the captured sign into bitmap image........

      Delete
    2. For purpose of Storing in SQLITE DB...........

      Delete
  69. This is BRILLIANT! Thank you!

    ReplyDelete
  70. Hai Thanks a lot this code helped me a lot I am very glad to see you Blog


    Have a nice day

    ReplyDelete
  71. HI i used this code and writing on the view works but when I convert the saved bitmap into an encoded string instead of saving to internal storage, the bitmap is all black. Any idea why?

    ReplyDelete
  72. awsome

    Your Blog saved my head, But can you tell me why images are being store in /sdcard/external_sd/DCIM
    thanks

    ReplyDelete
  73. Thanks a lot man its awsom... but please can you tel me why image object null when I wana to save it

    ReplyDelete
  74. It does not accept dot(.) also not work smoothly like short note application of android.
    Please help

    ReplyDelete
  75. I want to display the captured image in to ImageView in "CaptureSignatureActivity". If I use your code:
    //convert the string to byte array
    byte[] imageAsBytes = Base64.decode(myStringImage.getBytes());
    //get reference to the image view where you want to display the image
    ImageView image = (ImageView)this.findViewById(R.id.ImageView);
    //set the image by decoding the byte array to bitmap
    image.setImageBitmap(
    BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
    );
    what should I pass in "myStringImage"???

    ReplyDelete
  76. This works great as long as nobody touches outside the box. If you touch the screen outside it then you either can't write in the box or it drops back to the main screen. When you are trying to write you naturally lay your hand on the pad you are writing on, this causes the above actions. Is there anyway to ignore anything outside the signature box?

    ReplyDelete
  77. you can put the source code. thanks

    ReplyDelete
  78. love u plz put the source code in the one file so we can drag and drop that app

    ReplyDelete
  79. Thanks a lot.Ur code is working for me

    ReplyDelete
  80. thank you for the code. I'm having a problem with drawing on the mobile device. the resolution on the canvas seems poor. when drawing a diagonal line, the line is drawn as steps. On the simulator it's fine.

    any ideas guys? thanks a lot

    ReplyDelete
  81. Thanku for the code.Code is saving image in phone and i want to delete the image from phone.In the code there are some code but it is not working..// In case you want to delete the file
    //boolean deleted = mypath.delete();

    ReplyDelete
  82. can u plz post the code to display the captured signature..plzzzzzzzzzzzzzzzzzzzzz

    ReplyDelete
  83. ur code is awesome..but plz provide the code to display that captures signature and where should we write that display function..help plzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

    ReplyDelete
  84. Hi thanks for the code this is a great piece. I have only a couple of problems hopefully you can provide the answers. I have used Base64 library to encode the captured image but when I load this in a windows application the string is not recognized as a valid Base64 string! Do you have any idea why this is happening? Also I would lie to reduced the output size of the image from the current size to about a third. I have tried Bitmap.createScaledBitmap(mBitmap, x, y, true); but I loose aspect ratio. I am fairly new to java so please help.

    ReplyDelete
    Replies
    1. Hi, Thanks for responding, I have used your Base64 method as shown above:

      String encoded = Base64.encodeFromFile(mypath.toString());
      But I get this error when I attempt to use the Base64 string as an image source:

      The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.

      Do you have any idea why I should get this?

      Delete
  85. Thanks a lot.Your code is working for me

    ReplyDelete
  86. I am getting this error: java.lang.IllegalStateException: Unable to create new file: /storage/sdcard0/DCIM/Camera/1394096244886.jpg

    Please help

    ReplyDelete
  87. This works nicely. I had to add an OnTouchListener on the Signature view, to prevent the (in my case) parent scroll view from catching scroll events. On ACTION_DOWN simply call getParent().requestDisallowInterceptTouchEvent(true) and on ACTION_UP call with argument false.

    ReplyDelete
  88. Nice...thank u....

    ReplyDelete
  89. Hi please tell me can i run this code in 4.2 please let me know if so

    ReplyDelete
  90. A great tutorial. Thank you very much and appreciate your effort.
    I have a simple question though. How can I save two signature images at the same location?

    ReplyDelete
  91. Interesting to make an app with signature

    Thanks

    ReplyDelete
  92. Please help!!! When I attempt to draw, it only draws within an area of say 3 millimeters. Any ideas?

    ReplyDelete
    Replies
    1. I figured it out. I was using it inside a scroll view which i don't think it is good idea.

      Delete
  93. This comment has been removed by the author.

    ReplyDelete
  94. I have a error in this "external_dir" plz help me ...

    (R.string.external_dir)

    this is the full line
    File directory = cw.getDir(getResources().getString(R.string.external_dir), Context.MODE_PRIVATE);

    ReplyDelete
  95. will you please send me the project of this app on waqas_1231@hotmail.com... i copy the code but it is not working... I am working on 4.4 level

    ReplyDelete
  96. have a error while running project on emaulaoter, aapt.exe has stoped and then a new window occurs that you have errors in your project... do any one send me working condition project please ....

    ReplyDelete
  97. hallo,
    i got redline on this code:
    signature mSignature;

    signature cannot be resolved to a type


    is signature a layout file ?

    ReplyDelete
  98. This comment has been removed by the author.

    ReplyDelete
  99. thanks man ,for this code and for people "who get errors or any application stopped" pls try debugging it :) coz by doing that i learnt many new codes and many new tings :) once again thanks man :D for this awesome cod

    ReplyDelete
  100. Thankyou so much for such a great tutorial... It hepls me a lot... But i am unable to get the image on emulator as well as on my phone. Can anyone tell me please that where this image is stored?

    ReplyDelete
  101. Can you able to add the project zip file?please

    ReplyDelete
  102. Thank you very much :)

    ReplyDelete
  103. Excellent post. I must say that you have provided a great amount of information about digital signatures in this article. You have also posted the steps to create digital signature which helped me to successfully design my own signature. Thanks a lot.

    digital signature FAQ

    ReplyDelete
  104. hi, may u post block diagram of the algorithm?)

    ReplyDelete
  105. hi, it worked perfectly,thanks for sharing your code with us.

    ReplyDelete
  106. Hi i have some trouble in my codes! In this code,

    prepareDirectory();
    uniqueId = getTodaysDate() + "_" + getCurrentTime();
    current = uniqueId + ".png";
    mypath= new File(directory,current);

    I should get my unique ID as today's date + time and it should be in png file. But the unique id that i got is 1420628634664 and the picture is saved as JPEQ file

    ReplyDelete
    Replies
    1. iam also getting same issue.if u get solution plz share

      Delete
  107. Thank you for this wonderful and useful code. Made my day. :)

    ReplyDelete
  108. Bro thanx for the code but can u give some idea on how to match 2 signatures?

    ReplyDelete
  109. i want to save signature in data base...HOW? URGENT REQ.....

    ReplyDelete
  110. can u send me this code on aniketverma.chandi@gmail.com

    ReplyDelete
  111. This code works very well. Thank you.
    FWIW I changed the signature.xml to use RelativeLayout. This works better on a phone.

    ReplyDelete
  112. bhai aetli comment na karo page lode thava ma var lage 6

    ReplyDelete
  113. .mnkln
    Dxvc
    zx
    xzv

    x
    vxv
    xc
    v
    v
    cx
    v

    zzczcz
    z
    zx

    z
    zx

    czx
    z

    z

    z
    z
    zx

    xz
    zx
    zx
    z

    zx
    z
    zx
    x
    x
    zx
    z
    z
    cz
    xz
    zcx

    z
    z
    zx
    zxc

    zxxz

    xzcx
    xz
    zxzxzx

    zx
    xz
    xz

    xz
    xz
    zx
    xz
    v
    vxcvxcxvxxc
    x
    xv
    cxv
    vv
    vv

    vvxxv
    xc
    xv

    ReplyDelete
  114. Thanks for such a useful post. Works brilliantly.

    ReplyDelete
  115. Hi,
    Thanks for posting this code. Please give download link for full source code.
    Pleaseeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

    ReplyDelete
  116. Hi,

    The post is very useful. thanks.
    I would appreciate if you can also help me in -
    rather than whole bitmap, if signature is draw on middle part than can we save only judging signature part and not whole bitmap??
    In brief, Can we save only portion of the bitmap where thr is signature, and not all bitmap?

    ReplyDelete
  117. Hi,

    Thanks for the useful post.
    Is this post your too?: https://www.codeofaninja.com/2014/08/android-signature-capture-tutorial-and-source-code.html
    The code for signature view is the same.

    ReplyDelete
  118. Hello and Greetings,

    First of all, thanks a lot for this code, it helped me a lot and i have succesfully integregated it on my application (i'm an android noob), but i have a question, is it normal that the result image file, shows buttons and edittexts beside the signature?

    Thanks in advance

    ReplyDelete
  119. This is a great post and the code works well.
    But before going on to attempt to use the image elsewhere - I am first trying to confirm the image capture was good by displaying it in an ImageView.
    But what I have tried to use only displays a totally BLACK image, not showing the signature at all.

    The code I am using is as follows:
    // Get Pathed File ( NOTE - I confirmed as good with ImgFile.exists() )
    File ImgFile = new File(getApplicationContext().getFilesDir().getPath(), ImgFileName);

    FileInputStream mFileInputStream;
    mFileInputStream = null;
    try {
    mFileInputStream = new FileInputStream(ImgFile);
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] b = new byte[1024];
    int bytesRead = 0;
    try {
    while ((bytesRead = mFileInputStream.read(b)) != -1) {
    bos.write(b, 0, bytesRead);
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    byte[] ba = bos.toByteArray();
    Bitmap bm = BitmapFactory.decodeByteArray(ba, 0, ba.length);
    ImgView.setImageBitmap(bm);

    NOTE - I did not save as Base64, so I am not attempting to do a Base64.decode

    What am I doing wrong?

    Thanks

    ReplyDelete
  120. sir i dont understand whos string is convert in base64




    ReplyDelete
  121. It is very helpful for me but signature stored in DCIM not stored in speficied folder.
    plz help me to save in given particular folder.

    ReplyDelete
  122. This comment has been removed by the author.

    ReplyDelete
  123. Can you please let me know, can we do the same with Web based Application than Apps?

    ReplyDelete
  124. I've added many edittext's above signature. Added scrollview to go up and down, but the signature gets hidden or it does not appear on screen. Any clue.

    ReplyDelete
  125. I am using your code but I have problem. The created signature's image is not shown in Gallery immediately but when I do restart my mobile then the signature's image is shown. What I am doing wrong ? What is The Solution ?

    ReplyDelete
  126. my code is copied as same above . i have API level 17 for this.But while building this project i am facing several problems.kindly provide me solution for that.

    ReplyDelete
  127. The Code is awesome but you miss one thing if user want to insert dot(.) after sign its not working in your code.

    ReplyDelete
  128. I want to add signature in my app as well as use dot(.) in signature. how to insert dot (.) ?

    ReplyDelete
  129. Hi,
    Very Good article.
    What would be the best way to save the signature as a series of x,y points?
    Wayne

    ReplyDelete
  130. hey, how to delete the original image from storage ?
    where is the original path ?
    thanks

    ReplyDelete
  131. Android capture- stored programs, which are automatically executed or fired when some events occur in SQL. The programming students can execute now Triggers programs who are taking academic writing help from dissertation writers,database control (DML) proclamation which incorporates Embed, Erase, Overhaul and Read occasions which is composed for creating some determined section values naturally.

    ReplyDelete
  132. I have used the code for signature.

    but i am not able to save the signature as image.
    How i save the signed image ???

    please can someone help !!!!

    ReplyDelete
    Replies
    1. I found a library that you can use to save bitmap signatures to gallery in jpg or svg: https://github.com/gcacace/android-signaturepad

      Check the /SignaturePad-Example app for a more detailed code example of how to use the library.

      Delete
  133. can i save it , in transparent background in device storage

    ReplyDelete
  134. //convert the string to byte array
    byte[] imageAsBytes = Base64.decode(myStringImage.getBytes());
    //get reference to the image view where you want to display the image
    ImageView image = (ImageView)this.findViewById(R.id.ImageView);
    //set the image by decoding the byte array to bitmap
    image.setImageBitmap(
    BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
    );

    what is mymyStringImage in myStringImage.getBytes();???
    Please help me out

    ReplyDelete
  135. dot is not capturing. it only works to draw line

    ReplyDelete
  136. Good post. Information about android is really good. Software development company
    offers you best it services like android development.

    ReplyDelete
  137. it work perfect for me, emulator and samsung 8+

    ReplyDelete
  138. It is very helpful for me. Thank you to share with us.

    ReplyDelete
  139. I've added many edittext's above signature. Added scrollview to go up and down, but the signature gets hidden or it does not appear on screen. Any clue.
    thanks for sharing...
    GCLUB
    gclub casino
    goldenslot mobile
    gclub

    ReplyDelete
  140. Nice article with proper information. I would definitely try it!

    ReplyDelete
  141. I read some articles on this site and I think your blog is really interesting and has great information. Thank you for your sharing.
    html color

    ReplyDelete