Android capture signature using canvas example will guide you today.
This example will guide you how to get and save human digital signature in android studio.
After drawing and making the digital signature, we will also save it in the png format.
Final Signature
After all above coding writings, we will get the output as the below video
You can develop digital signature example with two methods.
- Using third party libraries on github
- And using Canvas Class
We will use second method in this tutorial.
What is Digital Signature
It is mandatory to have some signing documents for several transactions, contracts and business solutions.
In this fast era, getting physical signature on every paper and send that paper to other place or office is little lengthy process.
Digital signature helps us here to simplify this process. User just need to give it’s signature on android device screen instead of real paper. That’s all.
We can save this digital signature as an image and can send it anywhere across the globe.
Now follow all the below steps to create digital signature using canvas in android.
Step 1. Manifest Changes
For storing the image in android device, we need storage permissions.
Write down below two lines in the AndroidManifest.xml file
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- Note : If your app is targeting sdk version greater than 22 then you have to ask for runtime permissions in android.
- I am targeting sdk version 22, So I have not asked for runtime permissions here.
Step 2. Main Updates
We need to add some source code in the main files to achieve our final goal.
Copy the following source code in activity_main.xml file
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:id="@+id/canvasLL" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#fff" android:orientation="vertical" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:layout_marginTop="20dp" android:layout_marginLeft="10dp" android:orientation="horizontal"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnclear" android:text="Clear"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnsave" android:text="Save"/> </LinearLayout> </LinearLayout>
- I have taken one LinearLayout which will work as a signature pad. User will have to write his signature on this pad.
- LinearLayout with id canvasLL will be our signature pad in the above code.
- I have also taken two buttons : Clear and Save
- When the user will click the Clear button, compiler will erase the existing writing from the signature pad.
- Save button will save the signature in png format when the user will click it.
Write down the following code in MainActivity.java file.
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; 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.graphics.RectF; import android.os.Environment; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; public class MainActivity extends AppCompatActivity { private Button btnClear, btnSave; private File file; private LinearLayout canvasLL; private View view; private signature mSignature; private Bitmap bitmap; // Creating Separate Directory for saving Generated Images String DIRECTORY = Environment.getExternalStorageDirectory().getPath() + "/Signature/"; String pic_name = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String StoredPath = DIRECTORY + pic_name + ".png"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); canvasLL = (LinearLayout) findViewById(R.id.canvasLL); mSignature = new signature(getApplicationContext(), null); mSignature.setBackgroundColor(Color.WHITE); // Dynamically generating Layout through java code canvasLL.addView(mSignature, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); btnClear = (Button) findViewById(R.id.btnclear); btnSave = (Button) findViewById(R.id.btnsave); view = canvasLL; btnClear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mSignature.clear(); } }); btnSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { view.setDrawingCacheEnabled(true); mSignature.save(view,StoredPath); Toast.makeText(getApplicationContext(), "Successfully Saved", Toast.LENGTH_SHORT).show(); } }); // Method to create Directory, if the Directory doesn't exists file = new File(DIRECTORY); if (!file.exists()) { file.mkdir(); } } 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, String StoredPath) { Log.v("log_tag", "Width: " + v.getWidth()); Log.v("log_tag", "Height: " + v.getHeight()); if (bitmap == null) { bitmap = Bitmap.createBitmap(canvasLL.getWidth(), canvasLL.getHeight(), Bitmap.Config.RGB_565); } Canvas canvas = new Canvas(bitmap); try { // Output the file FileOutputStream mFileOutStream = new FileOutputStream(StoredPath); v.draw(canvas); // Convert the output file to Image such as .png bitmap.compress(Bitmap.CompressFormat.PNG, 90, mFileOutStream); mFileOutStream.flush(); mFileOutStream.close(); } 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(); 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) { Log.v("log_tag", 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); } } }
Understandings
Look at the below source code
String DIRECTORY = Environment.getExternalStorageDirectory().getPath() + "/Signature/"; String pic_name = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String StoredPath = DIRECTORY + pic_name + ".png";
- First line will define the String variable DIRECTORY. It is defining a path where we need to create a folder.
- We will use this variable to create a folder named “Signature” in the external storage.
- Second line is defining the pic_name String variable. This variable holds the date format in string variable.
- Third line is defining the StoragePath named String variable. It will completely create a name of the image.
Consider the below code
canvasLL.addView(mSignature, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
- Above line will add view to the signature pad (LinearLayout).
- Here mSignature is the object of the signature class. We have defined this signature class in the Main Activity itself as written in the above MainActivity.java file.
Following code defines the click event of the Clear button.
btnClear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mSignature.clear(); } });
- When the user clicks the Clear button, compiler will clear the surface of the signature pad and erase the existing writings.
Look at the below code
btnSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { view.setDrawingCacheEnabled(true); mSignature.save(view,StoredPath); Toast.makeText(getApplicationContext(), "Successfully Saved", Toast.LENGTH_SHORT).show(); } });
- Compiler will execute the above code when the user will click the save button.
- It will save the image with the png format in the path defined by the “StoredPath” variable.
clear() and save() method
signature class have two methods clear() and save().
- clear() method will erase the wrtitings of the signature pad.
- save() method will save the image in the external storage->Signature directory.
Using canvas class is little complex method as it has very long and deep coding lines.
Customization in this method is a big pain ass you know.
You can use third party library to simplify this process.
Read how to make digital signature in android with library to have simple code.
Download Source Code for Android Capture Signature Using Canvas Example
[sociallocker]Download Source Code for Signature View Example[/sociallocker]