Kotlin Digital Signature View Capture Human Signature Android

listview section header kotlin, kotlin pick video from gallery or capture from camera, kotlin custom spinner with image, pull to refresh listview android, swipe to refresh recyclerview android, expandablelistview in kotlin, Kotlin Horizontal Progressbar Android, kotlin image slider from url, Kotlin GIF Animated Splash Screen, Kotlin RecyclerView Sectioned Header, kotlin indeterminate circular progressbar, android dexter kotlin, kotlin digital signature view, kotlin alertdialog with edittext, elasticsearch windows, android dexter kotlin

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.

Download Code From Github

Download Source Code