Let us see Kotlin Digital Signature View Capture Human Signature Android Example.
This tutorial will teach you how to capture digital signature in kotlin android.
In many cases we need to capture human digital signature, so this example will simplify this feature in kotlin programmatically.
There is not any built in signatureview who can hold the human or digital signature in android system.
We will use one external library to create signature pad on which human can draw his digital signature.
After capturing the digital signature, we will save the digital signature in the android device.
System will convert the digital signature into the jpeg image and then it will save it in android device.
First of all, see the following video for last output of this example.
Step 1. Signature Dependency
After creating a new project in the android studio, open your build.gradle(Module:app) file.
Inside this build.gradle(Module:app) file, add the following two lines
implementation 'com.kyanogen.signatureview:signature-view:1.0' implementation 'com.karumi:dexter:5.0.0'
First line is for the signature-view library from github.
This external library will help us to make signature pad on the screen.
Second line will give us the access to the Dexter library and it’s source code.
It will help us to ask for runtime permissions in the easiest way.
Step 2. Manifest Adding
Now go to your AndroidManifest.xml file. You should add the below lines in this file.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Above lines will add two permissions in the manifest file.
Step 3. Drawing Signature
Now we are going to write important code of snippet.
Open your activity_main.xml file and add the below source line
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <com.kyanogen.signatureview.SignatureView xmlns:sign="http://schemas.android.com/apk/res-auto" android:id="@+id/signature_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" sign:penSize="5dp" sign:backgroundColor="#ffffff" sign:penColor="#000000" sign:enableSignature="true"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/clear" android:text="clear"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/save" android:text="save"/> </LinearLayout>
There is one Signature View and two buttons are there in the above code.
We have used external library to create the signature view.
This signature view will create the signature pad on the screen and user can draw the signature on this pad.
Now in your MainActivity.kt file, you should write down the below coding structure
import android.Manifest import android.graphics.Bitmap import android.media.MediaScannerConnection import android.os.Environment import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.util.Log import android.widget.Button import android.widget.Toast import com.karumi.dexter.Dexter import com.karumi.dexter.MultiplePermissionsReport import com.karumi.dexter.PermissionToken import com.karumi.dexter.listener.PermissionRequest import com.karumi.dexter.listener.multi.MultiplePermissionsListener import com.kyanogen.signatureview.SignatureView import java.io.ByteArrayOutputStream import java.io.File import java.io.FileOutputStream import java.io.IOException import java.util.Calendar class MainActivity : AppCompatActivity() { internal lateinit var bitmap: Bitmap internal lateinit var clear: Button internal lateinit var save: Button internal lateinit var signatureView: SignatureView internal lateinit var path: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) requestMultiplePermissions() signatureView = findViewById(R.id.signature_view) as SignatureView clear = findViewById(R.id.clear) as Button save = findViewById(R.id.save) as Button clear.setOnClickListener { signatureView.clearCanvas() } save.setOnClickListener { bitmap = signatureView.signatureBitmap path = saveImage(bitmap) } } fun saveImage(myBitmap: Bitmap): String { val bytes = ByteArrayOutputStream() myBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bytes) val wallpaperDirectory = File( Environment.getExternalStorageDirectory().toString() + IMAGE_DIRECTORY /*iDyme folder*/ ) // have the object build the directory structure, if needed. if (!wallpaperDirectory.exists()) { wallpaperDirectory.mkdirs() Log.d("hhhhh", wallpaperDirectory.toString()) } try { val f = File( wallpaperDirectory, Calendar.getInstance() .timeInMillis.toString() + ".jpg" ) f.createNewFile() val fo = FileOutputStream(f) fo.write(bytes.toByteArray()) MediaScannerConnection.scanFile( this@MainActivity, arrayOf(f.path), arrayOf("image/jpeg"), null ) fo.close() Log.d("TAG", "File Saved::--->" + f.absolutePath) Toast.makeText(applicationContext, "Signature Saved !!!", Toast.LENGTH_SHORT) .show() signatureView.clearCanvas() return f.absolutePath } catch (e1: IOException) { e1.printStackTrace() } return "" } private fun requestMultiplePermissions() { Dexter.withActivity(this) .withPermissions( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE ) .withListener(object : MultiplePermissionsListener { override fun onPermissionsChecked(report: MultiplePermissionsReport) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT) .show() } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied) { // show alert dialog navigating to Settings //openSettingsDialog() } } override fun onPermissionRationaleShouldBeShown( permissions: List<PermissionRequest>, token: PermissionToken ) { token.continuePermissionRequest() } }).withErrorListener { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() } .onSameThread() .check() } companion object { private val IMAGE_DIRECTORY = "/signdemo" } }
More Understanding
First of all, focus on the following code lines
internal lateinit var bitmap: Bitmap internal lateinit var clear: Button internal lateinit var save: Button internal lateinit var signatureView: SignatureView internal lateinit var path: String
First line is creating the object of the Bitmap class.
Second and third line is making the objects of the Button class.
Third one will give us the object of the SignatureView.
And finally, last will make one string variable and it’s name is path.
Now read the onCreate() method. Inside this, you can see a method requestMultiplePermissions() method.
Below are the source code lines for requestMultiplePermissions() method,
private fun requestMultiplePermissions() { Dexter.withActivity(this) .withPermissions( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE ) .withListener(object : MultiplePermissionsListener { override fun onPermissionsChecked(report: MultiplePermissionsReport) { // check if all permissions are granted if (report.areAllPermissionsGranted()) { Toast.makeText(applicationContext, "All permissions are granted by user!", Toast.LENGTH_SHORT) .show() } // check for permanent denial of any permission if (report.isAnyPermissionPermanentlyDenied) { // show alert dialog navigating to Settings //openSettingsDialog() } } override fun onPermissionRationaleShouldBeShown( permissions: List<PermissionRequest>, token: PermissionToken ) { token.continuePermissionRequest() } }).withErrorListener { Toast.makeText(applicationContext, "Some Error! ", Toast.LENGTH_SHORT).show() } .onSameThread() .check() }
Above method is helping us in the implementation of the runtime permissions.
For asking runtime permissions, we are using Dexter library.
You can see that I have added two permissions : WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE
This method shows the dialog to the user which ask for permissions and user will have options whether to grant or deny the permissions.
Now go through the following coding snippet
clear.setOnClickListener { signatureView.clearCanvas() }
Compiler will run the above line when the user clicks the clear button.
It will simply use clearCanvas() method to remove all the existing writings on the signature view.
Now focus on this coding lines
save.setOnClickListener { bitmap = signatureView.signatureBitmap path = saveImage(bitmap) }
When the user clicks the save button, compiler will go through the above lines.
Compiler will first give us the bitmap from signature view.
Then it will call the saveImage() method. Here, compiler will use the bitmap to pass it in the parameter of saveImage() method.
Below are the writings of the saveImage() method.
fun saveImage(myBitmap: Bitmap): String { val bytes = ByteArrayOutputStream() myBitmap.compress(Bitmap.CompressFormat.JPEG, 90, bytes) val wallpaperDirectory = File( Environment.getExternalStorageDirectory().toString() + IMAGE_DIRECTORY /*iDyme folder*/ ) // have the object build the directory structure, if needed. if (!wallpaperDirectory.exists()) { wallpaperDirectory.mkdirs() Log.d("hhhhh", wallpaperDirectory.toString()) } try { val f = File( wallpaperDirectory, Calendar.getInstance() .timeInMillis.toString() + ".jpg" ) f.createNewFile() val fo = FileOutputStream(f) fo.write(bytes.toByteArray()) MediaScannerConnection.scanFile( this@MainActivity, arrayOf(f.path), arrayOf("image/jpeg"), null ) fo.close() Log.d("TAG", "File Saved::--->" + f.absolutePath) Toast.makeText(applicationContext, "Signature Saved !!!", Toast.LENGTH_SHORT) .show() signatureView.clearCanvas() return f.absolutePath } catch (e1: IOException) { e1.printStackTrace() } return "" }
This method will get the bitmap inside it’s first parameter.
After this, compiler will check if there is any folder called “signdemo” inside the internal storage of the android device.
If “signdemo” folder is not already there in the internal storage, it will create one.
After this, compiler will convert the bitmap into the jpeg image.
Finally, compiler will save this jpeg image of the signature inside the “signdemo” folder.
After saving the image in the device, compiler will show one toast to say user regarding storage of image.
It will also remove all the current writings from the signature view after storing the image.