In this post, I will show you how to Create Digital Signature in Android.
Don't forget to add the following permission in your manifest file
Create color.xml and replace it with the following code
Create strings.xml and replace it with the following code
Create activity_toolbar.xml and replace it with the following code
Create activity_main.xml and replace it with the following code
Create dialog_signature.xml and replace it with the following code
Open MainActivity.java and replace it with the following code
Download From Github
Post your doubts and comments in the comments section.
Project Structure:
Create a new Project in Eclipse/Android Studio with the required Specifications.Codes:
AndroidManifest.xmlDon't forget to add the following permission in your manifest file
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
color.xmlCreate color.xml and replace it with the following code
<resources>
<color name="ColorPrimaryDark">#3367d6</color>
<color name="ColorPrimary">#4285f4</color>
</resources>
strings.xmlCreate strings.xml and replace it with the following code
<resources>
<string name="app_name">Digital Signature</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="hint_sign">Get Signature</string>
<string name="dialog_title">SIGN HERE</string>
<string name="hint_cancel">Cancel</string>
<string name="hint_clear">Clear</string>
<string name="hint_save">Save</string>
</resources>
activity_toolbar.xmlCreate activity_toolbar.xml and replace it with the following code
<RelativeLayout 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:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="@string/app_name">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/AppTheme"
app:popupTheme="@style/AppTheme" />
</RelativeLayout>
activity_main.xmlCreate activity_main.xml and replace it with the following code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@android:color/white">
<include layout="@layout/activity_toolbar" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:gravity="center">
<Button
android:id="@+id/signature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hint_sign"
android:padding="5dp"
android:background="@color/ColorPrimary" />
</LinearLayout>
</LinearLayout>
dialog_signature.xmlCreate dialog_signature.xml and replace it with the following code
<?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:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="400dp"
android:orientation="vertical"
android:background="@android:color/white">
<TextView
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/ColorPrimaryDark"
android:text="@string/dialog_title"
android:textColor="@android:color/white"
android:padding="5dp"
android:gravity="center"/>
<LinearLayout
android:id="@+id/linearLayout2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="3"
android:background="@android:color/white">
<Button
android:id="@+id/cancel"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="@string/hint_cancel"
tools:ignore="ButtonStyle"
android:textColor="@android:color/white"
android:background="@color/ColorPrimary" />
<Button
android:id="@+id/clear"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="@string/hint_clear"
tools:ignore="ButtonStyle"
android:textColor="@android:color/white"
android:background="@color/ColorPrimary" />
<Button
android:id="@+id/getsign"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="@string/hint_save"
tools:ignore="ButtonStyle"
android:textColor="@android:color/white"
android:background="@color/ColorPrimary" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:orientation="vertical" />
</LinearLayout>
MainActivity.javaOpen MainActivity.java and replace it with the following code
package com.example.digitalsignature;
import android.app.Dialog;
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.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
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 {
Toolbar toolbar;
Button btn_get_sign, mClear, mGetSign, mCancel;
File file;
Dialog dialog;
LinearLayout mContent;
View view;
signature mSignature;
Bitmap bitmap;
// Creating Separate Directory for saving Generated Images
String DIRECTORY = Environment.getExternalStorageDirectory().getPath() + "/DigitSign/";
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);
// Setting ToolBar as ActionBar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Button to open signature panel
btn_get_sign = (Button) findViewById(R.id.signature);
// Method to create Directory, if the Directory doesn't exists
file = new File(DIRECTORY);
if (!file.exists()) {
file.mkdir();
}
// Dialog Function
dialog = new Dialog(MainActivity.this);
// Removing the features of Normal Dialogs
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog_signature);
dialog.setCancelable(true);
btn_get_sign.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Function call for Digital Signature
dialog_action();
}
});
}
// Function for Digital Signature
public void dialog_action() {
mContent = (LinearLayout) dialog.findViewById(R.id.linearLayout);
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) dialog.findViewById(R.id.clear);
mGetSign = (Button) dialog.findViewById(R.id.getsign);
mGetSign.setEnabled(false);
mCancel = (Button) dialog.findViewById(R.id.cancel);
view = mContent;
mClear.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.v("tag", "Panel Cleared");
mSignature.clear();
mGetSign.setEnabled(false);
}
});
mGetSign.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.v("tag", "Panel Saved");
view.setDrawingCacheEnabled(true);
mSignature.save(view, StoredPath);
dialog.dismiss();
Toast.makeText(getApplicationContext(), "Successfully Saved", Toast.LENGTH_SHORT).show();
// Calling the same class
recreate();
}
});
mCancel.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.v("tag", "Panel Cancelled");
dialog.dismiss();
// Calling the same class
recreate();
}
});
dialog.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("tag", "Width: " + v.getWidth());
Log.v("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);
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();
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) {
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);
}
}
}
Screen Shots
Download Full Source Code
You can download the full source from the following Github link. If you Like this tutorial, Please star it in Github.Post your doubts and comments in the comments section.
Good job bro. Very helpful.
ReplyDeletesuper bro..............
ReplyDeleteThank You Bro..Very Helpful Perfectly working
ReplyDeleteThanks Bro for your support and keep on visiting
DeleteBro there´s a problem with the save function, the first time it works ok and save the sign in the specified folder, but from the second time the function doesn't create the file, what could be the problem, thanks for the tuto, it help me a lot! :)
ReplyDeleteHow may I attach the saved file to an e-mail?
ReplyDeleteYou can attach the saved file by using Email Intent as in the following
Delete"Uri path = Uri.parse("file://" + filepath);
Intent emailIntent = new Intent(Intent.ACTION_SEND);
// set the type to 'email'
emailIntent .setType("image/*");
String to[] = {"myemail@gmail.com"};
emailIntent .putExtra(Intent.EXTRA_EMAIL, to);
// the attachment
emailIntent .putExtra(Intent.EXTRA_STREAM, path);
// the mail subject
emailIntent .putExtra(Intent.EXTRA_SUBJECT, "Subject");
startActivity(Intent.createChooser(emailIntent , "Send email..."));"
Thanks for your support and Keep on Visiting
Good Job. Work perfectly for me
ReplyDeleteThanks Bro
DeleteWell done ....bro.
ReplyDeleteBut how can I add the the image file to volley http request to be send to a server.
Will appreciate any help.
Convert your Image into Base64 string and pass it using volley
DeleteBitmap bm = BitmapFactory.decodeFile("/path/to/image.jpg");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); //bm is the bitmap object
byte[] byteArrayImage = baos.toByteArray();
String encodedImage = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);
Refer this Link:http://stackoverflow.com/questions/4830711/how-to-convert-a-image-into-base64-string
This Tutorial is very Useful..Thanks for uploading.
ReplyDeleteNow I want to display the image what i have captured..can you please help me out?
Thanks for your support Swapna. You can display the captured image by setting the saved image path in ImageView as in the following
DeleteImageView preview = (ImageView) findViewById(R.id.preview);
preview.setImageURI(Uri.parse(filePath));
pay with their phones in stores and speed through checkout in Android apps. apk download
ReplyDeletei cant GET image on sd card on specified folder
ReplyDeleteAre you got any exception related to your app?
DeleteMaybe Permission Problem, if you used Android M.
Check that and comment me if the error will not be solved.
I was facing file not found exception in your project while using M.
ReplyDeleteSolution: Add the askForPermission(Manifest.permission.READ_EXTERNAL_STORAGE,READ_EXST);
private void askForPermission(String permission, Integer requestCode) {
if (ContextCompat.checkSelfPermission(MainActivity.this, permission) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permission)) {
//This is called if user has denied the permission before
//In this case I am just asking the permission again
ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, requestCode);
} else {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, requestCode);
}
} else {
createDirectory();
// Toast.makeText(this, "" + permission + " is already granted.", Toast.LENGTH_SHORT).show();
}
}
handle it
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.v("onRequestpermission", requestCode + "//");
if (ActivityCompat.checkSelfPermission(this, permissions[0]) == PackageManager.PERMISSION_GRANTED) {
switch (requestCode) {
//Location
case 4:
createDirectory();
}
} else {
Log.v("Permission Denied", requestCode + "else//");
}
}
Though the code for file and directory is not required but for reference i am putting it.
private File createFile(String url){
String filename = String.valueOf(url.hashCode());
// String filename = URLEncoder.encode(url);
File f = new File(DIRECTORY, filename);
if(f.exists()) {
return f;
}
else {
try {
f.createNewFile();
} catch (IOException e){
Log.v("File IOException", e.getMessage());
}
}
return f;
}
// Method to create Directory, if the Directory doesn't exists
private void createDirectory(){
file = new File(DIRECTORY);
if (!file.exists()) {
file.mkdirs();
}
}
Happy Coding :)
few more lines of code in save method.
Delete// it will check the file is created or not.
createDirectory();
createFile(StoredPath);
FileOutputStream mFileOutStream = new FileOutputStream(StoredPath);
can you show how can i save it to an online database?
ReplyDeleteBro, Refer this blog post to upload image to online server
Deletehttps://androidmads.blogspot.in/2016/06/upload-file-to-server-using-retrofit-in.html
Dude i have a little problem it says that "Result of 'File.mkdir()' is ignored" will you help me how to resolve this problem
DeleteBro, it's just a warning. 'File.mkdir()' returns boolean value. you can assign it to any boolean variable and print it with Logcat Like below
ReplyDeleteLog.v("isDirectoryCreated",String.valueof(File.mkdir())).
But it not an error.
HELLO GUYS I WANT TO ASK A QUESTION AND IF SOMEBODY CAN HELP..... I HAVE FIXED MY OWN APPLICATION AND I HAVE ADDED IN A SIGNATURE CANVAS IT WORKS ALL PERFECT, THE BITMAP IS SAVED PERFECT AT MY DATABASE BUT I HAVE A PROBLEM WHEN MY APPLICATION IS AT A BIG RESOLUTION PHONE LIKE GALAXY NOTE 4 (1440 x 2560 pixels (~518 ppi pixel density)) MY SIGNATURE BITMAP IS BEEN SAVED PERFECT BUT ITS VERY BIG AND HALF OF THE BITMAP IS GONE TO THE RIGHT HAW CAN I PUT MY BITMAP TO BE SAVED ALWAYS FOR EXAMPLE 1000X400 PIXELS OR 260 DPI AND NOT HAVING ANY PROBLEM OF WHAT PHONE USES MY APP PIXELS OR DENSITY?????IF SOMEBODY CAN HELP IT WILL MEAN A LOT FOR ME !!
ReplyDeletei am totally beginner in android studio. and trying this code. but i cant run the app. i didn't know what happen like i said i am totally new with this and trying this out for self learning purpose. i run it on avd and its prompt a message that "unfortunately the app stop".How can i fix it? owh..and how im going to set it into default activity, maybe i attach the wrong one i guess.
ReplyDeleteGreat job
ReplyDeleteHow to convert this file to Base64?
ReplyDeleteHi,
DeleteYou can use the following snippets to convert Image to Base64 and Vice-Versa.
// Image to Base64
Bitmap bm = BitmapFactory.decodeFile("/path/to/image.jpg");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); //bm is the bitmap object
byte[] b = baos.toByteArray();
String encodedImage = Base64.encodeToString(byteArrayImage, Base64.DEFAULT)
// Base64 to Image
byte[] decodedString = Base64.decode(encodedImage, Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
Hi.. Can you please help me, sir ? I have an email app. I want to send the last sign I created with a text.. but when I select the email app to send the image it's dosen't appear. What can I do ?
ReplyDeleteHey Bro,
DeleteUse the following snippet to attach Image
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_EMAIL, new String[] {"email@example.com"});
intent.putExtra(Intent.EXTRA_SUBJECT, "subject here");
intent.putExtra(Intent.EXTRA_TEXT, "body text");
File root = Environment.getExternalStorageDirectory();
File file = new File(root, xmlFilename);
if (!file.exists() || !file.canRead()) {
Toast.makeText(this, "Attachment Error", Toast.LENGTH_SHORT).show();
finish();
return;
}
Uri uri = Uri.parse("file://" + file);
intent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(intent, "Send email..."));
hi
ReplyDeleteapplication is working fine if i change the tools.context:.main instead of @strings/app_name.
http://schemas.android.com/tools"">
and can you please help me in terms of path where this signature is getting saved.
Thanks in advance.
Super Tutorial it is very Useful..Thanks for uploading.
ReplyDeleteNow I want to display the image what i have captured..can you please help me out?
Hi, after reading this amazing paragraph i am also glad to share my
ReplyDeletefamiliarity here with friends.
Hi,this tutorial is working,But issue are raise for me,issue are when i first time sign clear function is worked,then exit the dialog. Second time i open signature dialog,I signed in layout but clear function is not worked,this is my problem please help me..?
ReplyDeletecreate and generate your custom e-signatures live using our online signature maker tool. Create your own personal signature which you can use on Websites, Blogs, E-mails, Forums, Word Docs, PDFs, etc. Choose your own signature font and style to create and generate a perfect digital signature.
ReplyDeletehttps://www.signaturemaker.in/en/online-signature-maker/
nice tutorials to Create a Digital Signature Application in Android. thank you very much
ReplyDeleteBro Thanku for sharing this awesome post with android begineers
ReplyDeleteBro I wanted to get entered file name by user in edittext and save this png with that entered file name
how can I implement this
Bro your help will be appreciated
I'm dazzled, I should state. In all respects infrequently do I run over a blog that is both useful and engaging, and let me let you know, you ve hit the nail on the head. Your blog is significant.. Fred @ LeReviewist
ReplyDeleteWhere to find saved signatures in Phone?
ReplyDeleteThanks for the post and great tips..even I also think that hard work is the most important aspect of getting success..
ReplyDeleteapp development company in mumbai
// // Function for Digital Signature
ReplyDeletemContent.addView( mSignature, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT );
It brings this error below
"error: no suitable method found for addView(dialog_signature,int,int)
mContent.addView( mSignature, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT );"
Please Help!!!!!
Particular interviews furnish firsthand message on mart size, industry trends, ontogeny trends, capitalist landscape and outlook, etc. agen asuransi allianz
ReplyDeleteSome casinos automatically credit your account with a birthday bonus, so keep in mind to log in and verify. It’s value noting that while no deposit bonuses are sometimes provided as part of of} a on-line casino registration bonus 카지노사이트 package deal, they’re not at all times reserved model spanking new|for model new} gamers. You may find that the casino additionally presents you a deposit bonus if you add extra funds too.
ReplyDeletesd
ReplyDeleteAffiliate marketing allows businesses to partner with affiliates who promote their products in exchange for a commission.
ReplyDeleteDigital Marketing Agency
Erzurum
ReplyDeleteistanbul
Ağrı
Malatya
Trabzon
VUR