1

I am developing an Android Digital signature app in which user can sign and i have to save this file as image.i am using SurfaceView for drawing. DigitalSignatureActivity has two Buttons Save,Clear. 1.Save Button to save file as image 2.Clear Button to clear surface. But i am unable to clear the surface.i tried drawingSurface.setBackgroundColor(Color.BLACK); still previous sign is retained and canvas.drawColor(Color.BLACK); has no effect and i am able to save file but its not storing signature perfectly(Some contents are missing) please help. My code is: DigitalSignatureActivity.java

package com.pop.digitalsign;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Bundle;
import android.os.Environment;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class DigitalSignatureActivity extends Activity implements
        View.OnTouchListener {

    private DrawingSurface drawingSurface;
    private DrawingPath currentDrawingPath;
    private Paint currentPaint;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setCurrentPaint();
        drawingSurface = (DrawingSurface) findViewById(R.id.drawingSurface);
        drawingSurface.setOnTouchListener(this);

    }

    private void setCurrentPaint() {
        currentPaint = new Paint();
        currentPaint.setDither(true);
        currentPaint.setColor(Color.WHITE);
        currentPaint.setStyle(Paint.Style.STROKE);
        currentPaint.setStrokeJoin(Paint.Join.ROUND);
        currentPaint.setStrokeCap(Paint.Cap.ROUND);
        currentPaint.setStrokeWidth(2);

    }

    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {

            drawingSurface.setBackgroundColor(0);
            currentDrawingPath = new DrawingPath();
            currentDrawingPath.paint = currentPaint;
            currentDrawingPath.path = new Path();
            currentDrawingPath.path.moveTo(motionEvent.getX(),
                    motionEvent.getY());
            currentDrawingPath.path.lineTo(motionEvent.getX(),
                    motionEvent.getY());

        } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
            currentDrawingPath.path.lineTo(motionEvent.getX(),motionEvent.getY());
            drawingSurface.addDrawingPath(currentDrawingPath);

        } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
            currentDrawingPath.path.lineTo(motionEvent.getX(),motionEvent.getY());
        }

        return true;
    }
    //To save file as  Image
    public void saveDrawing(View v) throws IOException {

        File mediaStorageDir = new File(
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                "MySignatures");

        Bitmap nBitmap = drawingSurface.getBitmap();
        try {
            if (!mediaStorageDir.exists()) {
                mediaStorageDir.mkdirs();
            }
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                    .format(new Date());
            File mediaFile = new File(mediaStorageDir.getPath()
                    + File.separator + "SIGN_" + timeStamp + ".png");
            FileOutputStream out = new FileOutputStream(mediaFile);

            nBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
            out.flush();
            out.close();
            Toast.makeText(this, "Signature saved  to " + mediaFile,
                    Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(), "Not saved",
                    Toast.LENGTH_SHORT).show();
        }

    }

    //To clear Surface
    public void clearScreen(View v) {
        //drawingSurface.setBackgroundColor(Color.BLACK);
        drawingSurface.clear();
    }
}

DrawingSurface.java

package com.pop.digitalsign;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;


public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
    private Boolean _run;
    protected DrawThread thread;
    private Bitmap mBitmap;
    Canvas canvas;


    private CommandManager commandManager;

    public DrawingSurface(Context context, AttributeSet attrs) {
        super(context, attrs);

        getHolder().addCallback(this);
        commandManager = new CommandManager();
        thread = new DrawThread(getHolder());
    }


    class DrawThread extends  Thread{

         public SurfaceHolder mSurfaceHolder;

        public DrawThread(SurfaceHolder surfaceHolder){
            mSurfaceHolder = surfaceHolder;

        }
        public DrawThread() {
            // TODO Auto-generated constructor stub
        }

        public void setRunning(boolean run) {
            _run = run;
        }


        @Override
        public void run() {
            canvas = null;
            while (_run){
                try{
                    canvas = mSurfaceHolder.lockCanvas(null);
                    //canvas.drawColor(Color.WHITE);
                    if(mBitmap == null){
                        mBitmap =  Bitmap.createBitmap (1, 1, Bitmap.Config.ARGB_8888);;
                    }
                    final Canvas c = new Canvas (mBitmap);
                    c.drawColor(0, PorterDuff.Mode.CLEAR);
                    commandManager.executeAll(c);
                    canvas.drawBitmap (mBitmap, 0,  0,null);
                } finally {
                    if(canvas!=null){
                        mSurfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }
    }


    public void addDrawingPath (DrawingPath drawingPath){
        commandManager.addCommand(drawingPath);
    }


    public void clear(){
        //Here i want to clear surface
         canvas.drawColor(Color.BLACK);//it has no effect
    }

    public boolean hasMoreUndo(){
        return commandManager.hasMoreUndo();
    }

    public Bitmap getBitmap(){
        return mBitmap;
    }


    public void surfaceChanged(SurfaceHolder holder, int format, int width,  int height) {
        mBitmap =  Bitmap.createBitmap (width, height, Bitmap.Config.ARGB_8888);;
    }


    public void surfaceCreated(SurfaceHolder holder) {
        thread.setRunning(true);
        thread.start();
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        boolean retry = true;
        thread.setRunning(false);
        while (retry) {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
    }

}

CommandManager.java

package com.pop.digitalsign;

import android.graphics.Canvas;

import java.util.Iterator;
import java.util.List;
import java.util.Collections;
import java.util.ArrayList;


public class CommandManager {
    private List<DrawingPath> currentStack;

    public  CommandManager(){
        currentStack = Collections.synchronizedList(new ArrayList<DrawingPath>());
    }

    public void addCommand(DrawingPath command){
        currentStack.add(command);
    }

    public void undo (){
        final int length = currentStackLength();
        if ( length > 0) {
            final DrawingPath undoCommand = currentStack.get(  length - 1  );
            currentStack.remove( length - 1 );
            undoCommand.undo();
        }
    }

    public int currentStackLength(){
        final int length = currentStack.toArray().length;
        return length;
    }


    public void executeAll( Canvas canvas){
        if( currentStack != null ){
            synchronized( currentStack ) {
                final Iterator<?> i = currentStack.iterator();
                while ( i.hasNext() ){
                    final DrawingPath drawingPath = (DrawingPath) i.next();
                    drawingPath.draw( canvas );
                }
            }
        }
    }

    public boolean hasMoreUndo(){
        return  currentStack.toArray().length > 0;
    }
}

DrawingPath.java

package com.pop.digitalsign;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;

public class DrawingPath {
    public Path path;
    public Paint paint;

    public void draw(Canvas canvas) {
        canvas.drawPath( path, paint );
    }

    public void undo() {
    }
}

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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" >

     <com.pop.digitalsign.DrawingSurface
        android:id="@+id/drawingSurface"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

      <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center" >

      <Button
            android:id="@+id/saveBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="saveDrawing"
            android:text="@string/save" />
       <Button
            android:id="@+id/clearBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="clearScreen"
            android:text="@string/clear" />
       </LinearLayout>

</RelativeLayout>
P Srinivas Goud
  • 886
  • 1
  • 12
  • 30

3 Answers3

1

the best suggestion i have is to use this

if (surfaceHolder.getSurface().isValid()) {
                    Canvas c = surfaceHolder.lockCanvas();
                    if (first >= 0) {
                        c.drawARGB(255, 255, 255, 255);
                        first--;
                    }

The value of first is 2 you can use what every name you want. The reason is that the canvas is double buffered so you need to clear both screen by painting it white. This stops the flickering

Lpc_dark
  • 2,834
  • 7
  • 32
  • 49
0
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
deviant
  • 3,539
  • 4
  • 32
  • 47
-1

In DrawingSurface add this method

public void resetCanvas(){ commandManager.clearAllPath(); }

and call this method, when you need to action for clear..

objectNameofDrawingSurefaceClass.resetCanvas();

add the code in CommandManager

public void clearAllPath(){currentStack.clear();  }

ok..

David O'Meara
  • 2,983
  • 25
  • 38
Gandhi Ishan
  • 149
  • 4