Hello developers, In this tutorial we will learn about the how to capture digital Signature using android canvas and also save the signature in image format for further usage. Capturing the Digital Signature has multiple usages in the internet age. Digital signatures are used for authentication and integrity assurance of digital data. It is used as proof of any product delivery, to accept an agreement which is confidential, or on legal/contractual documents. The most important component we have used to capture the signature is android canvas.
Android Canvas is a graphic component which allows us to call the draw() method to draw or write anything on the screen.
Capturing Digital Signature in android.
To capture the Digital Signature using android canvas, we first create an XML file which contains the canvas on which we can register our signatures using our fingers or stylus. Then we convert that signature into an Image, create a directory in mobile storage and save the signature image in that directory on click of the save button. We can also show the image in another activity using the path of the directory.
Create Android Canvas Example App
- Go to File → New → New Project and enter your Application Name. Let’s say Android Canvas Example App
- Enter company domain, this is used to uniquely identify your App’s package worldwide.
- Choose project location and minimum SDK and on the next screen choose Simple Activity, since we would be adding most of the code ourselves. Then Click on Next.
- Choose an Activity Name. Make sure Generate Layout File check box is selected, Otherwise, we have to generate it ourselves. Then click on Finish. We have kept the Activity Name as BillDetailsActivity.java. This will be the default screen when the user opens the app for the first time.
Gradle will configure your android canvas example project in the android studio and resolve the dependencies, Once it is complete proceed to the next steps.
Add Layout to Android Canvas Project
- Now we will create layout for the BillDetailsActivity. In this layout we use the TableLayout to create a table like structure in which we show the details of the product we buy like its price, date, order number, buyer’s details etc. It also contains Checkbox for confirmation, ImageView for getting the image of signature and a button to go to the another activity where we capture the signature.
- Now we will create a table_borders.xml file in drawable folder which is used to make a border on every textview of the table rows which makes the table clear to see and attractive. To create a xml file in drawable folder, right click on the drawable folder which is present in res -> drawable. Click on New and then click on Drawable resource file. Then add the file name table_border.xml you can give name to file according to your choice and click ok and add the below code in this xml file.
- To capture the signature using android canvas we will create a new activity SignatureActivity in which we add android canvas component and get the signature on that canvas. To create the activity right click on package New ⇒ Activity ⇒ Empty Activity.
Now open the activity_signature.xml and add the below code which contains the three buttons for cancel, clear and save the signature. It also contains the LinearLayout on which we add the canvas which is used to write the signature using our fingers.
So, open activity_bill_details.xml file which is present in res -> layouts folder and add the below code.
activity_bill_details.xml
table_border.xml
activity_signature.xml
Capture Signature using canvas
Now open BillDetailsActivity.java class and add the below code. In this activity, we show the details of the product. We also add a checkbox and enable the button to go to another activity if the checkbox is checked. We also set the image of signature which we get from another activity using the image path of signature. It also contains the button by which we can go to other activity from where we get the signature of the customer.
BillDetailsActivity.java
package com.androidtutorialpoint.androidcanvasexample; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; public class BillDetailsActivity extends Activity { Button signatureButton; ImageView signImage; CheckBox checkBox; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bill_details); signatureButton = (Button) findViewById(R.id.getSign); signImage = (ImageView) findViewById(R.id.imageView1); signatureButton.setOnClickListener(onButtonClick); checkBox = (CheckBox) findViewById(R.id.checkbox); //disable button if checkbox is not checked else enable button checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if ( isChecked ) { signatureButton.setEnabled(true); } else{ signatureButton.setEnabled(false); } } }); //to get imagepath from SignatureActivity and set it on ImageView String image_path = getIntent().getStringExtra("imagePath"); Bitmap bitmap = BitmapFactory.decodeFile(image_path); signImage.setImageBitmap(bitmap); } Button.OnClickListener onButtonClick = new Button.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (checkBox.isChecked()){ Intent i = new Intent(BillDetailsActivity.this, SignatureActivity.class); startActivity(i); } else { signatureButton.setEnabled(false); } } }; }
Now open SignatureActivity.java class. In this activity first, we create the directory in our storage where all the images of user signature have been saved. We also add the canvas to the layout on which we are able to write our signature. It also contains three buttons i.e. cancel, clear and saves. In the onClick() of Cancel we move to the previous activity without signature. In the onClick() of Clear, we erase the data if the user is not able to write the signature properly. In the onClick() of Save, the signature is converted into an image file and save into the directory which we have created earlier and also we move to the previous activity on which the signature is shown as a proof.
So, open SignatureActivity.java class and add the below code.
SignatureActivity.xml
package com.androidtutorialpoint.androidcanvasexample; import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; 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.Build; import android.os.Bundle; import android.os.Environment; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; 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 SignatureActivity extends AppCompatActivity { Button mClear, mGetSign, mCancel; File file; LinearLayout mContent; View view; signature mSignature; Bitmap bitmap; // Creating Separate Directory for saving Generated Images String DIRECTORY = Environment.getExternalStorageDirectory().getPath() + "/UserSignature/"; 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_signature); mContent = (LinearLayout) findViewById(R.id.canvasLayout); mSignature = new signature(getApplicationContext(), null); mSignature.setBackgroundColor(Color.WHITE); // Dynamically generating Layout through java code mContent.addView(mSignature, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mClear = (Button) findViewById(R.id.clear); mGetSign = (Button) findViewById(R.id.getsign); mGetSign.setEnabled(false); mCancel = (Button) findViewById(R.id.cancel); view = mContent; mGetSign.setOnClickListener(onButtonClick); mClear.setOnClickListener(onButtonClick); mCancel.setOnClickListener(onButtonClick); // Method to create Directory, if the Directory doesn't exists file = new File(DIRECTORY); if (!file.exists()) { file.mkdir(); } } Button.OnClickListener onButtonClick = new Button.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (v == mClear) { Log.v("log_tag", "Panel Cleared"); mSignature.clear(); mGetSign.setEnabled(false); } else if (v == mGetSign) { Log.v("log_tag", "Panel Saved"); if (Build.VERSION.SDK_INT >= 23) { isStoragePermissionGranted(); } else { view.setDrawingCacheEnabled(true); mSignature.save(view, StoredPath); Toast.makeText(getApplicationContext(), "Successfully Saved", Toast.LENGTH_SHORT).show(); // Calling the same class recreate(); } } else if(v == mCancel){ Log.v("log_tag", "Panel Canceled"); // Calling the BillDetailsActivity Intent intent = new Intent(SignatureActivity.this, BillDetailsActivity.class); startActivity(intent); } } }; public boolean isStoragePermissionGranted() { if (Build.VERSION.SDK_INT >= 23) { if (getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { return true; } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); return false; } } else { return true; } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ view.setDrawingCacheEnabled(true); mSignature.save(view, StoredPath); Toast.makeText(getApplicationContext(), "Successfully Saved", Toast.LENGTH_SHORT).show(); // Calling the same class recreate(); } else { Toast.makeText(this, "The app was not allowed to write to your storage. Hence, it cannot function properly. Please consider granting it this permission", Toast.LENGTH_LONG).show(); } } 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(mContent.getWidth(), mContent.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); Intent intent = new Intent(SignatureActivity.this, BillDetailsActivity.class); intent.putExtra("imagePath", StoredPath); startActivity(intent); finish(); mFileOutStream.flush(); mFileOutStream.close(); } catch (Exception e) { Log.v("log_tag", e.toString()); } } public void clear() { path.reset(); invalidate(); mGetSign.setEnabled(false); } @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 dirtyRect.right) { dirtyRect.right = historicalX; } 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); } } }
Add Permission and resources
As we want to create a directory and store the images in that directory. So we have to add the permission to write into the external storage. So add the below line in AndroidManifest.xml
AndroidManifest.xml
As we know that hard coding of resources is not a good practice for coding so we will add some new colors in colors.xml and string values in strings.xml.
Add the following resources in the respective files present in the path res -> values
strings.xml
SignatureUsingCanvas Get Signature Sign Here Cancel Clear Save Bill Details Date 16 Mar 2017 Order Number 10798565 Buyer\'s Name Umesh Buyer\'s Address Pratap Nagar Contact Number 0000000000 Total Amount Rs 1500 I have Successfully Received the product Get Signature
colors.xml
#000000 #202324 #B8B9B1 #ffffff
We have used the following dimensions and styles in our android canvas example application.
dimens.xml
16dp 16dp 3px 5dp 15dip 10dp 150dp 80dp 20sp 0dp 50dp
styles.xml
Now run the Android Canvas Example app on an actual Android Device and you try to capture your signature and save it.
What’s Next ??
After this, We will be covering more interesting tutorials like creating a multilingual app in android.
Till then stay tuned for more tutorials.. and Don’t forget to subscribe our blog for latest android tutorials. Also do Like our Facebook Page or Add us on Twitter.
To download the full code for the Android Canvas Tutorial using the android studio, Click on the Download Now link below.
The post Android Canvas Tutorial – Capture Digital Signature and Save appeared first on Android Tutorial Point.