Android implements the function of converting signatures into pictures and printing

Android implements signature function

Customize a signature canvas panel

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

public class SignatureView extends View {
    
    
    private Paint paint = new Paint();
    private Path path = new Path();
    private Paint borderPaint = new Paint();

    public SignatureView(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(5f);

        borderPaint.setStyle(Paint.Style.STROKE);
        borderPaint.setStrokeWidth(10f);
        borderPaint.setColor(Color.RED);

        setBackgroundColor(Color.WHITE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
    
    
        canvas.drawPath(path, paint);
        canvas.drawRect(0, 0, getWidth(), getHeight(), borderPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
    
    
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
    
    
            case MotionEvent.ACTION_DOWN:
                path.moveTo(x, y);
                return true;
            case MotionEvent.ACTION_MOVE:
                path.lineTo(x, y);
                break;
            case MotionEvent.ACTION_UP:
                // do nothing
                break;
            default:
                return false;
        }

        invalidate();
        return true;
    }

    public Bitmap getSignatureBitmap() {
    
    
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        draw(canvas);
        return bitmap;
    }

    public void clearSignature() {
    
    
        path.reset();
        invalidate();
    }
}

Write a signature page layout

After the canvas panel is defined, just use it directly in the layout file: the red box is where the signature is.
signed page

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="match_parent"
    tools:context=".activity.util.SignatureActivity">

    <com.pft.mobilemr.customview.SignatureView
        android:id="@+id/signature_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/bottom_button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/bottom_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/signature_view">

        <Button
            android:id="@+id/cancel_signature"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_marginHorizontal="10dp"
            android:text="@string/cancel_signature"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/clear_signature"
            app:layout_constraintHorizontal_weight="1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/clear_signature"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_marginHorizontal="10dp"
            android:text="@string/clear_signature"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/confirm_signature"
            app:layout_constraintHorizontal_weight="1"
            app:layout_constraintStart_toEndOf="@+id/cancel_signature"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/confirm_signature"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:layout_marginHorizontal="10dp"
            android:text="@string/confirm_signature"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_weight="1"
            app:layout_constraintStart_toEndOf="@+id/clear_signature"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Some logic and function implementation required when signing in activity

Write the logic directly in the activity, and set the logic of each of the three buttons. The code for the specific button method implementation is written on the custom View page. Just call it directly. After clicking the confirmation button, the signature will be converted into a bitmap format image, and then converted Put it in byte[] format and then pass it to other pages.

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;

import com.pft.mobilemr.R;
import com.pft.mobilemr.customview.SignatureView;

import java.io.ByteArrayOutputStream;

/**
 * 签名页面
 */
public class SignatureActivity extends AppCompatActivity {
    
    

    private SignatureView signatureView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signature);
        init();
    }

    private void init() {
    
    
        signatureView = findViewById(R.id.signature_view);

        findViewById(R.id.clear_signature).setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                signatureView.clearSignature();
            }
        });

        findViewById(R.id.cancel_signature).setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent = new Intent();
                setResult(RESULT_CANCELED, intent);
                finish();
            }
        });

        findViewById(R.id.confirm_signature).setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Bitmap signatureBitmap = signatureView.getSignatureBitmap();
                Intent intent = new Intent();
                byte[] signature = Bitmap2Bytes(signatureBitmap);
                intent.putExtra("signature", signature);
                setResult(RESULT_OK, intent);
                finish();
            }
        });
    }

    private byte[] Bitmap2Bytes(Bitmap bm) {
    
    
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        return baos.toByteArray();
    }
}

Overall, the logic is not very confusing, and the implementation of the code is not difficult.
It is best to use landscape screen for signature, so set the opening mode of this activity to landscape screen.

<activity
    android:name=".activity.util.SignatureActivity"
    android:label="@string/activity_signature"
    android:screenOrientation="landscape" />

Display and print the signed image

Other pages receive data and display it

After clicking to confirm the signature on the signature page, it will jump back to the previous page and the signature content will be transferred there. After obtaining the image in byte[] format, convert it into bitmap and put the bitmap image in the imageView control.

if (requestCode == REQUEST_CODE_SIGNATURE && resultCode == RESULT_OK && data != null) {
    
    
	byteArray = data.getByteArrayExtra("signature");
	if (byteArray == null) {
    
    
		toastMsg("签名数据为空");
		return;
	}

	// 处理签名数据
	ImageView imageView = findViewById(R.id.signature_img);
	imageBitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
	imageView.setImageBitmap(imageBitmap);
}

Print signature

Before printing the signature, the bitmap of the signature needs to be trimmed so that its size matches the width of our signature paper, otherwise only half of it will be printed.

Start printing:

try {
    
    
	p.reset();
	byte[] bytes = Printer.draw2PxPoint(p.bmpzoomTo58(imageBitmap));
	p.write(bytes);
	p.enter();
	p.feed();
	p.feed();
	p.close();
} catch (Exception e) {
    
    
	e.printStackTrace();
}

The draw2PxPoint() method is to modify the signature image.

Picture retouching

/*************************************************************************
 * 假设一个240*240的图片,分辨率设为24, 共分10行打印
 * 每一行,是一个 240*24 的点阵, 每一列有24个点,存储在3个byte里面。
 * 每个byte存储8个像素点信息。因为只有黑白两色,所以对应为1的位是黑色,对应为0的位是白色
 **************************************************************************/
/**
 * 把一张Bitmap图片转化为打印机可以打印的字节流
 *
 * @param bmp
 * @return
 */
public static byte[] draw2PxPoint(Bitmap bmp) throws IOException {
    
    

	//用来存储转换后的 bitmap 数据。为什么要再加1000,这是为了应对当图片高度无法
	//整除24时的情况。比如bitmap 分辨率为 240 * 250,占用 7500 byte,
	//但是实际上要存储11行数据,每一行需要 24 * 240 / 8 =720byte 的空间。再加上一些指令存储的开销,
	//所以多申请 1000byte 的空间是稳妥的,不然运行时会抛出数组访问越界的异常。
	int size = bmp.getWidth() * bmp.getHeight() / 8 + 7500;
	byte[] data = new byte[size];
	int k = 0;
	//设置行距为0的指令
	data[k++] = 0x1B;
	data[k++] = 0x33;
	data[k++] = 0x01;
	// 逐行打印
	for (int j = 0; j < bmp.getHeight() / 24f; j++) {
    
    
		//打印图片的指令
		data[k++] = 0x1B;
		data[k++] = 0x2A;
		data[k++] = 33;
		data[k++] = (byte) (bmp.getWidth() % 256); //nL
		data[k++] = (byte) (bmp.getWidth() / 256); //nH
		//对于每一行,逐列打印
		for (int i = 0; i < bmp.getWidth(); i++) {
    
    
			//每一列24个像素点,分为3个字节存储
			for (int m = 0; m < 3; m++) {
    
    
				//每个字节表示8个像素点,0表示白色,1表示黑色
				for (int n = 0; n < 8; n++) {
    
    
					byte b = px2Byte(i, j * 24 + m * 8 + n, bmp);
					data[k] += data[k] + b;
				}
				k++;
			}
		}
		if (k < data.length) {
    
    
			data[k++] = 10;//换行
		}
	}
	return data;
}

/**
 * 灰度图片黑白化,黑色是1,白色是0
 *
 * @param x   横坐标
 * @param y   纵坐标
 * @param bit 位图
 * @return
 *
 */
public static byte px2Byte(int x, int y, Bitmap bit) {
    
    
	if (x < bit.getWidth() && y < bit.getHeight()) {
    
    
		byte b;
		int pixel = bit.getPixel(x, y);
		int red = (pixel & 0x00ff0000) >> 16; // 取高两位
		int green = (pixel & 0x0000ff00) >> 8; // 取中两位
		int blue = pixel & 0x000000ff; // 取低两位
		int gray = RGB2Gray(red, green, blue);
		if (gray < 128) {
    
    
			b = 1;
		} else {
    
    
			b = 0;
		}
		return b;
	}
	return 0;
}

/**
 * 图片灰度的转化
 *
 */
private static int RGB2Gray(int r, int g, int b) {
    
    
	int gray = (int) (0.29900 * r + 0.58700 * g + 0.11400 * b); //灰度转化公式
	return gray;
}

DecimalFormat df = new DecimalFormat("0.00");

public Bitmap bmpzoomTo58(Bitmap mBitmap) {
    
    
	if (mBitmap.getWidth() >= 380) {
    
    
		float c = Float.valueOf(df.format((float) mBitmap.getWidth() / 380));
		int newHight = Integer.parseInt(new java.text.DecimalFormat("0").format(mBitmap.getHeight() / c));
		mBitmap = zoomImg(mBitmap, 380, newHight);
	} else {
    
    
		float c = Float.valueOf(df.format((float) 380 / mBitmap.getWidth()));

		Log.e("", "c:" + c);
		int newHight1 = Integer.parseInt(new java.text.DecimalFormat("0").format(c * mBitmap.getHeight()));
		mBitmap = zoomImg(mBitmap, 380, newHight1);
	}
	return mBitmap;
}

// 缩放图片
private static Bitmap zoomImg(Bitmap bm, int newWidth, int newHeight) {
    
    
	// 获得图片的宽高
	int width = bm.getWidth();
	int height = bm.getHeight();
	// 计算缩放比例
	float scaleWidth = ((float) newWidth) / width;
	float scaleHeight = ((float) newHeight) / height;
	// 取得想要缩放的matrix参数
	Matrix matrix = new Matrix();
	matrix.postScale(scaleWidth, scaleHeight);
	// 得到新的图片
	Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
	return newbm;
}

Example image:
signature panel signature
Signature print result

Guess you like

Origin blog.csdn.net/jxj960417/article/details/132879671