android中的数字签名

时间:2011-03-28 11:32:36

标签: android

我想在android中创建数字签名应用程序。它应该捕获用户签名并将其存储为图像。如果有人知道,请告诉我。

5 个答案:

答案 0 :(得分:11)

尝试自定义视图而不是手势:

package com.example.myapp.gui.views;

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.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * A simple view to capture a path traced onto the screen. Initially intended to be used to captures signatures.
 * 
 * @author Andrew Crichton
 * @version 0.1
 */
public class SignatureView extends View {
    private Path mPath;
    private Paint mPaint; 
    private Paint bgPaint = new Paint(Color.TRANSPARENT);

    private Bitmap mBitmap;
    private Canvas mCanvas;

    private float curX, curY;

    private static final int TOUCH_TOLERANCE = 4;
    private static final int STROKE_WIDTH = 4;

    public SignatureView(Context context) {
        super(context);
        init();
    }
    public SignatureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public SignatureView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }
    private void init() {
        setFocusable(true);
        mPath = new Path();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(STROKE_WIDTH);
    }
    public void setSigColor(int color) {
        mPaint.setColor(color);
    }
    public void setSigColor(int a, int red, int green, int blue) {
        mPaint.setARGB(a, red, green, blue);
    }
    public boolean clearSignature() {
        if (mBitmap != null)
            createFakeMotionEvents();
        if (mCanvas != null) {
            mCanvas.drawColor(Color.BLACK);
            mCanvas.drawPaint(bgPaint);
            mPath.reset();
            invalidate();
        }
        else {
            return false;
        }
        return true;
    }
    public Bitmap getImage() {
        return this.mBitmap;
    }
    public void setImage(Bitmap bitmap) {
        this.mBitmap = bitmap;
        this.invalidate();
    }
    @Override
    protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        int bitmapWidth = mBitmap != null ? mBitmap.getWidth() : 0;
        int bitmapHeight = mBitmap != null ? mBitmap.getWidth() : 0;
        if (bitmapWidth >= width && bitmapHeight >= height) 
            return;
        if (bitmapWidth < width) 
            bitmapWidth = width;
        if (bitmapHeight < height) 
            bitmapHeight = height;
        Bitmap newBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
        Canvas newCanvas = new Canvas();
        newCanvas.setBitmap(newBitmap);
        if (mBitmap != null) 
            newCanvas.drawBitmap(mBitmap, 0, 0, null);
        mBitmap = newBitmap;
        mCanvas = newCanvas;
    }
    private void createFakeMotionEvents() {
        MotionEvent downEvent = MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis()+100, MotionEvent.ACTION_DOWN, 1f, 1f ,0);
        MotionEvent upEvent = MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis()+100, MotionEvent.ACTION_UP, 1f, 1f ,0);
        onTouchEvent(downEvent);
        onTouchEvent(upEvent);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.BLACK);
        canvas.drawBitmap(mBitmap, 0, 0, mPaint); 
        canvas.drawPath(mPath, mPaint);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchDown(x, y);
            break;
        case MotionEvent.ACTION_MOVE:
            touchMove(x, y);
            break;
        case MotionEvent.ACTION_UP:
            touchUp();
            break;
        }
        invalidate();
        return true;
    }
    /**----------------------------------------------------------
     * Private methods
     **---------------------------------------------------------*/

    private void touchDown(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        curX = x;
        curY = y;
    }

    private void touchMove(float x, float y) {
        float dx = Math.abs(x - curX);
        float dy = Math.abs(y - curY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(curX, curY, (x + curX)/2, (y + curY)/2);
            curX = x;
            curY = y;
        }
    }

    private void touchUp() {
        mPath.lineTo(curX, curY);
        if (mCanvas == null) {
            mCanvas = new Canvas();
            mCanvas.setBitmap(mBitmap);
        }
        mCanvas.drawPath(mPath, mPaint);
        mPath.reset();
    }
}

然后,在XML中使用此类:<com.example.myapp.gui.views.SignatureView .../> 要获取绘制的签名,请使用:Bitmap bmp = ((SignatureView)findViewById(R.id.signatureview)).getImage();

您最终可以使用以下代码保存位图:

public void saveBitmap(Bitmap bmp) {
    try {
        String root = Environment.getExternalStorageDirectory().getAbsolutePath() + "/";
        String filepath = root + "signature.jpg";

        FileOutputStream fos = new FileOutputStream(filepath);
        bmp.compress(CompressFormat.JPEG, 100, fos);
        fos.flush();
        fos.close();
    }
    catch(Exception e) {
        Log.e("Could not save", e.getMessage());
        e.printStackTrace();
    }
}

将签名作为signature.jpeg保存在SD卡的根目录中。对于写作部分,请确保在您的清单中具有该权限:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

答案 1 :(得分:4)

希望此代码可以帮助您:)

esign_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >


    <android.gesture.GestureOverlayView
        android:id="@+id/signaturePad"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="5"
        android:background="@android:color/white"
        android:clickable="false"
        android:eventsInterceptionEnabled="true"
        android:fadeEnabled="false"
        android:gestureColor="#0000ff"
        android:gestureStrokeLengthThreshold="0.1"
        android:gestureStrokeType="multiple"
        android:longClickable="false"
        android:orientation="vertical"
        android:uncertainGestureColor="#000000"
        android:splitMotionEvents="true" 
        android:fadeOffset="10000000">

    </android.gesture.GestureOverlayView>

    <RelativeLayout
        android:id="@+id/rellay_esign_donebutton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dp"
         >
 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        >
        <Button
            android:id="@+id/DoneButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Done" />

         <Button
             android:id="@+id/ClearButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="Clear" />
</LinearLayout>
    </RelativeLayout>

</LinearLayout>

Esignature.java

public class Esignature extends Activity {
    GestureOverlayView gestureView;
    String path;
    File file;
    Bitmap bitmap;
    public boolean gestureTouch=false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.esign_main);



        Button donebutton = (Button) findViewById(R.id.DoneButton);
        donebutton.setText("Done");
        Button clearButton = (Button) findViewById(R.id.ClearButton);
        clearButton.setText("Clear");

        path=Environment.getExternalStorageDirectory()+"/signature.png";
        file = new File(path);
        file.delete();
        gestureView = (GestureOverlayView) findViewById(R.id.signaturePad);
        gestureView.setDrawingCacheEnabled(true);

        gestureView.setAlwaysDrawnWithCacheEnabled(true);
        gestureView.setHapticFeedbackEnabled(false);
        gestureView.cancelLongPress();
        gestureView.cancelClearAnimation();
        gestureView.addOnGestureListener(new OnGestureListener() {

            @Override
            public void onGesture(GestureOverlayView arg0, MotionEvent arg1) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onGestureCancelled(GestureOverlayView arg0,
                    MotionEvent arg1) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onGestureEnded(GestureOverlayView arg0, MotionEvent arg1) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onGestureStarted(GestureOverlayView arg0,
                    MotionEvent arg1) {
                // TODO Auto-generated method stub
                if (arg1.getAction()==MotionEvent.ACTION_MOVE){
                    gestureTouch=false;                     
             }
             else 
             {
                    gestureTouch=true;
            }
            }});

        donebutton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                try {
                    bitmap = Bitmap.createBitmap(gestureView.getDrawingCache());
                    file.createNewFile();
                    FileOutputStream fos = new FileOutputStream(file);
                    fos = new FileOutputStream(file);
                    // compress to specified format (PNG), quality - which is
                    // ignored for PNG, and out stream
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
                    fos.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            if(gestureTouch==false)
            {
                setResult(0);
                finish();
            }
            else
            {
                setResult(1);
                finish();
            }
            }
        });

        clearButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                gestureView.invalidate();
                gestureView.clear(true);
                gestureView.clearAnimation();
                gestureView.cancelClearAnimation();
            }
        });
    }





}

答案 2 :(得分:0)

这可以在Gestureoverlay的帮助下完成。这在APIDemos中得到了证明。以下链接必须有所帮助:

digital Signature

答案 3 :(得分:0)

对于白色背景的jpg文件:

gestureView.setDrawingCacheBackgroundColor(Color.WHITE);

bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);

使用Harshal Benake解决方案。

答案 4 :(得分:0)

感谢Harhal's answer,这是一种无需访问文件系统即可获取位图的方法。

是的,gestureView.buildDrawingCache() API已过时,但就我而言,这是一个更可接受的解决方案..而不是要求用户保存许可来仅支持整个应用这一功能。

    // .. continuing from Harhal's code here:

    donebutton.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            try {
                gestureView.buildDrawingCache();
                bitmap = gestureView.getDrawingCache();

                // set bitmap somewhere
                // eg: mBinding.signature.setImageBitmap(bitmap);
            }
            catch (Exception e) {
                e.printStackTrace();
            }

            // Activity Stuff ...
        }
    });

要重置视图,gestureView为我卡住了它加载的第一个位图。因此,似乎只是重新加载相同的片段是使所有内容完全重置的最简单方法。

下面是此操作的伪代码,因为每个人似乎对片段堆栈的管理方式不同。

    clearButton.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {

            // Reload this fragment
            // 1. Pop current fragment (current instance) from fragment stack
            // 2. Set this same fragment again 

        }
    });