Android自定义相机实现身份证拍照,并加入自动对焦与图片不规则裁剪

本文主要是介绍Android自定义相机实现身份证拍照,并加入自动对焦与图片不规则裁剪,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://www.jianshu.com/p/5e3cb0c63cd5

当Glide访问同一个uri的时候,默认是有缓存 的,当uri的图片改变时候,glide默认还是加载之前的图片,所以要清除glide的缓存

1 前言

前段时间,应公司要求实现一个自定义相机,需要有自动对焦和图片不规则裁剪功能,其实难点主要也是这2个功能。经Google搜索,发现并没有现成的轮子。最后通过各种查找资料,自己封装了一个,效果图如下:

身份证来源网络虚拟构造

2 使用

Step 1. 添加JitPack仓库

在项目的build.gradle添加JitPack仓库

allprojects {repositories {...maven { url "https://jitpack.io" }}
}

Step 2. 添加依赖

在需要使用的module中添加依赖

dependencies {compile 'com.github.wildma:IDCardCamera:1.0.0'
}

或者引用本地lib

compile project(':idcardcamera')

Step 3. 调用CameraActivity类的toCameraActivity方法打开拍照界面

CameraActivity.toCameraActivity(this, CameraActivity.TYPE_IDCARD_FRONT);

Step 4. 在onActivityResult方法中获取裁剪后的图片

    @Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == CameraActivity.REQUEST_CODE && resultCode == CameraActivity.RESULT_CODE) {//获取图片路径,显示图片final String path = CameraActivity.getImagePath(data);if (!TextUtils.isEmpty(path)) {imageView.setImageBitmap(BitmapFactory.decodeFile(path));}}}

3 功能特点

自定义相机的代码我就不重复造轮子了,网上很多,我找了个UI比较不错的项目 CertificateCamera ,然后在该项目的基础上进行功能增加的,主要增加的内容如下:

  1. 解决该项目拍照不成功的问题(该项目代码有问题,博主也一直没有去修改,这里帮他改过来了)
  2. 增加自动对焦功能
  3. 增加图片不规则裁剪功能

3.1 自动对焦

实现自动对焦有多种方式,这里列举下:

3.1.1 使用原生API

  1. 调用autoFocus方法,如下:
        camera.autoFocus(new Camera.AutoFocusCallback() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {}});

结论:不满足,大部分手机只对焦一次。

  1. 设置对焦模式,如下:
camera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

camera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);

结论:不满足,不能兼容所有手机。

3.1.2 使用定时器

即使用一个定时器,每隔一段时间进行自动对焦。代码如下:

package com.wildma.idcardcamera.camera;import android.annotation.SuppressLint;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.RejectedExecutionException;public class AutoFocusManager implements Camera.AutoFocusCallback {private static final String TAG = AutoFocusManager.class.getSimpleName();private static final long AUTO_FOCUS_INTERVAL_MS = 2000L;private static final Collection<String> FOCUS_MODES_CALLING_AF;static {FOCUS_MODES_CALLING_AF = new ArrayList<String>(2);FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);}private final boolean            useAutoFocus;private final Camera             camera;private       boolean            stopped;private       boolean            focusing;private       AsyncTask<?, ?, ?> outstandingTask;public AutoFocusManager(Camera camera) {this.camera = camera;String currentFocusMode = camera.getParameters().getFocusMode();useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode);//  Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);start();}@Overridepublic synchronized void onAutoFocus(boolean success, Camera theCamera) {focusing = false;autoFocusAgainLater();}@SuppressLint("NewApi")private synchronized void autoFocusAgainLater() {if (!stopped && outstandingTask == null) {AutoFocusTask newTask = new AutoFocusTask();try {if (Build.VERSION.SDK_INT >= 11) {newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);} else {newTask.execute();}outstandingTask = newTask;} catch (RejectedExecutionException ree) {Log.w(TAG, "Could not request auto focus", ree);}}}public synchronized void start() {if (useAutoFocus) {outstandingTask = null;if (!stopped && !focusing) {try {camera.autoFocus(this);Log.w(TAG, "自动对焦");focusing = true;} catch (RuntimeException re) {// Have heard RuntimeException reported in Android 4.0.x+;// continue?Log.w(TAG, "Unexpected exception while focusing", re);// Try again later to keep cycle goingautoFocusAgainLater();}}}}private synchronized void cancelOutstandingTask() {if (outstandingTask != null) {if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) {outstandingTask.cancel(true);}outstandingTask = null;}}public synchronized void stop() {stopped = true;if (useAutoFocus) {cancelOutstandingTask();// Doesn't hurt to call this even if not focusingtry {camera.cancelAutoFocus();} catch (RuntimeException re) {// Have heard RuntimeException reported in Android 4.0.x+;// continue?Log.w(TAG, "Unexpected exception while cancelling focusing", re);}}}private final class AutoFocusTask extends AsyncTask<Object, Object, Object> {@Overrideprotected Object doInBackground(Object... voids) {try {Thread.sleep(AUTO_FOCUS_INTERVAL_MS);} catch (InterruptedException e) {}start();return null;}}}

结论:虽然可以实现,但是你对比下手机自带的相机,发现并不是每隔一段时间进行自动对焦的,都是通过移动手机后才自动对焦的,所以这种方式是不合理的。

3.1.3 使用传感器

即根据传感器来判断手机的运动状态,如果手机从静止状态变成运行状态后再次进入静止状态,此时就是手机的对焦时机。代码如下:

package com.wildma.idcardcamera.camera;import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;import java.util.Calendar;public class SensorControler implements SensorEventListener {public static final String TAG = "SensorControler";private SensorManager mSensorManager;private Sensor        mSensor;private int           mX, mY, mZ;private long lastStaticStamp = 0;Calendar mCalendar;public static final int DELEY_DURATION = 500;private static SensorControler mInstance;private int foucsing = 1;  //1 表示没有被锁定 0表示被锁定boolean isFocusing = false;boolean canFocusIn = false;  //内部是否能够对焦控制机制boolean canFocus   = false;public static final int STATUS_NONE   = 0;public static final int STATUS_STATIC = 1;public static final int STATUS_MOVE   = 2;private             int STATUE        = STATUS_NONE;private SensorControler(Context context) {mSensorManager = (SensorManager) context.getSystemService(Activity.SENSOR_SERVICE);mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);// TYPE_GRAVITY}public static SensorControler getInstance(Context context) {if (mInstance == null) {mInstance = new SensorControler(context);}return mInstance;}public void onStart() {restParams();canFocus = true;mSensorManager.registerListener(this, mSensor,SensorManager.SENSOR_DELAY_NORMAL);}public void onStop() {mSensorManager.unregisterListener(this, mSensor);canFocus = false;}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}@Overridepublic void onSensorChanged(SensorEvent event) {if (event.sensor == null) {return;}if (isFocusing) {restParams();return;}if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {int x = (int) event.values[0];int y = (int) event.values[1];int z = (int) event.values[2];mCalendar = Calendar.getInstance();long stamp = mCalendar.getTimeInMillis();// 1393844912int second = mCalendar.get(Calendar.SECOND);// 53if (STATUE != STATUS_NONE) {int px = Math.abs(mX - x);int py = Math.abs(mY - y);int pz = Math.abs(mZ - z);//                Log.d(TAG, "pX:" + px + "  pY:" + py + "  pZ:" + pz + "    stamp:"//                        + stamp + "  second:" + second);double value = Math.sqrt(px * px + py * py + pz * pz);if (value > 1.4) {//                    textviewF.setText("检测手机在移动..");//                    Log.i(TAG,"mobile moving");STATUE = STATUS_MOVE;} else {//                    textviewF.setText("检测手机静止..");//                    Log.i(TAG,"mobile static");//上一次状态是move,记录静态时间点if (STATUE == STATUS_MOVE) {lastStaticStamp = stamp;canFocusIn = true;}if (canFocusIn) {if (stamp - lastStaticStamp > DELEY_DURATION) {//移动后静止一段时间,可以发生对焦行为if (!isFocusing) {canFocusIn = false;//                                onCameraFocus();if (mCameraFocusListener != null) {mCameraFocusListener.onFocus();}//                                Log.i(TAG,"mobile focusing");}}}STATUE = STATUS_STATIC;}} else {lastStaticStamp = stamp;STATUE = STATUS_STATIC;}mX = x;mY = y;mZ = z;}}/*** 重置参数*/private void restParams() {STATUE = STATUS_NONE;canFocusIn = false;mX = 0;mY = 0;mZ = 0;}/*** 对焦是否被锁定** @return*/public boolean isFocusLocked() {if (canFocus) {return foucsing <= 0;}return false;}/*** 锁定对焦*/public void lockFocus() {isFocusing = true;foucsing--;Log.i(TAG, "lockFocus");}/*** 解锁对焦*/public void unlockFocus() {isFocusing = false;foucsing++;Log.i(TAG, "unlockFocus");}public void restFoucs() {foucsing = 1;}private CameraFocusListener mCameraFocusListener;public interface CameraFocusListener {void onFocus();}public void setCameraFocusListener(CameraFocusListener mCameraFocusListener) {this.mCameraFocusListener = mCameraFocusListener;}
}

结论:完美实现,只要带传感器的手机就能兼容。

3.2 图片不规则裁剪

要实现的效果如下:

 

图片来源见文末参考资料

由效果图可得出如下结论:

  1. 需要利用drawline将四个坐标点连接起来
  2. 需要处理触摸与拖拽事件,即随着手指的移动,坐标点跟随移动。
  3. 需要处理裁剪框区域内的全透明化和区域外的半透明化的效果。
  4. 其他等等...

也就是说需要很强的自定义View的能力和计算能力,所以想着还是找找现成的轮子吧。
经过各种Google,发现国内很难找到这种轮子,最终还是在Github上找了一个国外的,主要代码如下:

package com.wildma.idcardcamera.cropper;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Region;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;public class CropOverlayView extends View {private int defaultMargin = 100;private int minDistance   = 100;private int vertexSize    = 30;private int gridSize      = 3;private Bitmap bitmap;private Point  topLeft, topRight, bottomLeft, bottomRight;private float touchDownX, touchDownY;private CropPosition cropPosition;private int currentWidth  = 0;private int currentHeight = 0;private int minX, maxX, minY, maxY;public CropOverlayView(Context context) {super(context);}public CropOverlayView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public void setBitmap(Bitmap bitmap) {this.bitmap = bitmap;resetPoints();invalidate();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (getWidth() != currentWidth || getHeight() != currentHeight) {currentWidth = getWidth();currentHeight = getHeight();resetPoints();}Log.e("stk", "canvasSize=" + getWidth() + "x" + getHeight());drawBackground(canvas);drawVertex(canvas);drawEdge(canvas);//        drawGrid(canvas);//裁剪框内部线条}private void resetPoints() {Log.e("stk", "resetPoints, bitmap=" + bitmap);// 1. calculate bitmap size in new canvasfloat scaleX = bitmap.getWidth() * 1.0f / getWidth();float scaleY = bitmap.getHeight() * 1.0f / getHeight();float maxScale = Math.max(scaleX, scaleY);// 2. determine minX , maxX if maxScale = scaleY | minY, maxY if maxScale = scaleXint minX = 0;int maxX = getWidth();int minY = 0;int maxY = getHeight();if (maxScale == scaleY) { // image very tallint bitmapInCanvasWidth = (int) (bitmap.getWidth() / maxScale);minX = (getWidth() - bitmapInCanvasWidth) / 2;maxX = getWidth() - minX;} else { // image very wideint bitmapInCanvasHeight = (int) (bitmap.getHeight() / maxScale);minY = (getHeight() - bitmapInCanvasHeight) / 2;maxY = getHeight() - minY;}this.minX = minX;this.minY = minY;this.maxX = maxX;this.maxY = maxY;if (maxX - minX < defaultMargin || maxY - minY < defaultMargin)defaultMargin = 0; // remove minelsedefaultMargin = 100;Log.e("stk", "maxX - minX=" + (maxX - minX));Log.e("stk", "maxY - minY=" + (maxY - minY));topLeft = new Point(minX + defaultMargin, minY + defaultMargin);topRight = new Point(maxX - defaultMargin, minY + defaultMargin);bottomLeft = new Point(minX + defaultMargin, maxY - defaultMargin);bottomRight = new Point(maxX - defaultMargin, maxY - defaultMargin);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}private void drawBackground(Canvas canvas) {Paint paint = new Paint();paint.setColor(Color.parseColor("#66000000"));paint.setStyle(Paint.Style.FILL);Path path = new Path();path.moveTo(topLeft.x, topLeft.y);path.lineTo(topRight.x, topRight.y);path.lineTo(bottomRight.x, bottomRight.y);path.lineTo(bottomLeft.x, bottomLeft.y);path.close();canvas.save();canvas.clipPath(path, Region.Op.DIFFERENCE);canvas.drawColor(Color.parseColor("#66000000"));canvas.restore();}private void drawVertex(Canvas canvas) {Paint paint = new Paint();paint.setColor(Color.WHITE);paint.setStyle(Paint.Style.FILL);canvas.drawCircle(topLeft.x, topLeft.y, vertexSize, paint);canvas.drawCircle(topRight.x, topRight.y, vertexSize, paint);canvas.drawCircle(bottomLeft.x, bottomLeft.y, vertexSize, paint);canvas.drawCircle(bottomRight.x, bottomRight.y, vertexSize, paint);Log.e("stk","vertextPoints=" +topLeft.toString() + " " + topRight.toString() + " " + bottomRight.toString() + " " + bottomLeft.toString());}private void drawEdge(Canvas canvas) {Paint paint = new Paint();paint.setColor(Color.WHITE);paint.setStrokeWidth(3);paint.setAntiAlias(true);canvas.drawLine(topLeft.x, topLeft.y, topRight.x, topRight.y, paint);canvas.drawLine(topLeft.x, topLeft.y, bottomLeft.x, bottomLeft.y, paint);canvas.drawLine(bottomRight.x, bottomRight.y, topRight.x, topRight.y, paint);canvas.drawLine(bottomRight.x, bottomRight.y, bottomLeft.x, bottomLeft.y, paint);}private void drawGrid(Canvas canvas) {Paint paint = new Paint();paint.setColor(Color.WHITE);paint.setStrokeWidth(2);paint.setAntiAlias(true);for (int i = 1; i <= gridSize; i++) {int topDistanceX = Math.abs(topLeft.x - topRight.x) / (gridSize + 1) * i;int topDistanceY = Math.abs((topLeft.y - topRight.y) / (gridSize + 1) * i);Point top = new Point(topLeft.x < topRight.x ? topLeft.x + topDistanceX : topLeft.x - topDistanceX,topLeft.y < topRight.y ? topLeft.y + topDistanceY : topLeft.y - topDistanceY);int bottomDistanceX = Math.abs((bottomLeft.x - bottomRight.x) / (gridSize + 1) * i);int bottomDistanceY = Math.abs((bottomLeft.y - bottomRight.y) / (gridSize + 1) * i);Point bottom = new Point(bottomLeft.x < bottomRight.x ? bottomLeft.x + bottomDistanceX : bottomLeft.x - bottomDistanceX,bottomLeft.y < bottomRight.y ? bottomLeft.y + bottomDistanceY : bottomLeft.y - bottomDistanceY);canvas.drawLine(top.x, top.y, bottom.x, bottom.y, paint);int leftDistanceX = Math.abs((topLeft.x - bottomLeft.x) / (gridSize + 1) * i);int leftDistanceY = Math.abs((topLeft.y - bottomLeft.y) / (gridSize + 1) * i);Point left = new Point(topLeft.x < bottomLeft.x ? topLeft.x + leftDistanceX : topLeft.x - leftDistanceX,topLeft.y < bottomLeft.y ? topLeft.y + leftDistanceY : topLeft.y - leftDistanceY);int rightDistanceX = Math.abs((topRight.x - bottomRight.x) / (gridSize + 1) * i);int rightDistanceY = Math.abs((topRight.y - bottomRight.y) / (gridSize + 1) * i);Point right = new Point(topRight.x < bottomRight.x ? topRight.x + rightDistanceX : topRight.x - rightDistanceX,topRight.y < bottomRight.y ? topRight.y + rightDistanceY : topRight.y - rightDistanceY);canvas.drawLine(left.x, left.y, right.x, right.y, paint);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_UP:getParent().requestDisallowInterceptTouchEvent(false);break;case MotionEvent.ACTION_DOWN:getParent().requestDisallowInterceptTouchEvent(false);onActionDown(event);return true;case MotionEvent.ACTION_MOVE:getParent().requestDisallowInterceptTouchEvent(true);onActionMove(event);return true;}return false;}private void onActionDown(MotionEvent event) {touchDownX = event.getX();touchDownY = event.getY();Point touchPoint = new Point((int) event.getX(), (int) event.getY());int minDistance = distance(touchPoint, topLeft);cropPosition = CropPosition.TOP_LEFT;if (minDistance > distance(touchPoint, topRight)) {minDistance = distance(touchPoint, topRight);cropPosition = CropPosition.TOP_RIGHT;}if (minDistance > distance(touchPoint, bottomLeft)) {minDistance = distance(touchPoint, bottomLeft);cropPosition = CropPosition.BOTTOM_LEFT;}if (minDistance > distance(touchPoint, bottomRight)) {minDistance = distance(touchPoint, bottomRight);cropPosition = CropPosition.BOTTOM_RIGHT;}}private int distance(Point src, Point dst) {return (int) Math.sqrt(Math.pow(src.x - dst.x, 2) + Math.pow(src.y - dst.y, 2));}private void onActionMove(MotionEvent event) {int deltaX = (int) (event.getX() - touchDownX);int deltaY = (int) (event.getY() - touchDownY);switch (cropPosition) {case TOP_LEFT:adjustTopLeft(deltaX, deltaY);invalidate();break;case TOP_RIGHT:adjustTopRight(deltaX, deltaY);invalidate();break;case BOTTOM_LEFT:adjustBottomLeft(deltaX, deltaY);invalidate();break;case BOTTOM_RIGHT:adjustBottomRight(deltaX, deltaY);invalidate();break;}touchDownX = event.getX();touchDownY = event.getY();}private void adjustTopLeft(int deltaX, int deltaY) {int newX = topLeft.x + deltaX;if (newX < minX)newX = minX;if (newX > maxX)newX = maxX;int newY = topLeft.y + deltaY;if (newY < minY)newY = minY;if (newY > maxY)newY = maxY;topLeft.set(newX, newY);}private void adjustTopRight(int deltaX, int deltaY) {int newX = topRight.x + deltaX;if (newX > maxX)newX = maxX;if (newX < minX)newX = minX;int newY = topRight.y + deltaY;if (newY < minY)newY = minY;if (newY > maxY)newY = maxY;topRight.set(newX, newY);}private void adjustBottomLeft(int deltaX, int deltaY) {int newX = bottomLeft.x + deltaX;if (newX < minX)newX = minX;if (newX > maxX)newX = maxX;int newY = bottomLeft.y + deltaY;if (newY > maxY)newY = maxY;if (newY < minY)newY = minY;bottomLeft.set(newX, newY);}private void adjustBottomRight(int deltaX, int deltaY) {int newX = bottomRight.x + deltaX;if (newX > maxX)newX = maxX;if (newX < minX)newX = minX;int newY = bottomRight.y + deltaY;if (newY > maxY)newY = maxY;if (newY < minY)newY = minY;bottomRight.set(newX, newY);}public void crop(CropListener cropListener, boolean needStretch) {if (topLeft == null)return;// calculate bitmap size in new canvasfloat scaleX = bitmap.getWidth() * 1.0f / getWidth();float scaleY = bitmap.getHeight() * 1.0f / getHeight();float maxScale = Math.max(scaleX, scaleY);// re-calculate coordinate in original bitmapLog.e("stk", "maxScale=" + maxScale);Point bitmapTopLeft = new Point((int) ((topLeft.x - minX) * maxScale), (int) ((topLeft.y - minY) * maxScale));Point bitmapTopRight = new Point((int) ((topRight.x - minX) * maxScale), (int) ((topRight.y - minY) * maxScale));Point bitmapBottomLeft = new Point((int) ((bottomLeft.x - minX) * maxScale), (int) ((bottomLeft.y - minY) * maxScale));Point bitmapBottomRight = new Point((int) ((bottomRight.x - minX) * maxScale), (int) ((bottomRight.y - minY) * maxScale));Log.e("stk", "bitmapPoints="+ bitmapTopLeft.toString() + " "+ bitmapTopRight.toString() + " "+ bitmapBottomRight.toString() + " "+ bitmapBottomLeft.toString() + " ");Bitmap output = Bitmap.createBitmap(bitmap.getWidth() + 1, bitmap.getHeight() + 1, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(output);Paint paint = new Paint();// 1. draw pathPath path = new Path();path.moveTo(bitmapTopLeft.x, bitmapTopLeft.y);path.lineTo(bitmapTopRight.x, bitmapTopRight.y);path.lineTo(bitmapBottomRight.x, bitmapBottomRight.y);path.lineTo(bitmapBottomLeft.x, bitmapBottomLeft.y);path.close();canvas.drawPath(path, paint);// 2. draw original bitmappaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));canvas.drawBitmap(bitmap, 0, 0, paint);// 3. cutRect cropRect = new Rect(Math.min(bitmapTopLeft.x, bitmapBottomLeft.x),Math.min(bitmapTopLeft.y, bitmapTopRight.y),Math.max(bitmapBottomRight.x, bitmapTopRight.x),Math.max(bitmapBottomRight.y, bitmapBottomLeft.y));Bitmap cut = Bitmap.createBitmap(output,cropRect.left,cropRect.top,cropRect.width(),cropRect.height());if (!needStretch) {cropListener.onFinish(cut);} else {// 4. re-calculate coordinate in cropRectPoint cutTopLeft = new Point();Point cutTopRight = new Point();Point cutBottomLeft = new Point();Point cutBottomRight = new Point();cutTopLeft.x = bitmapTopLeft.x > bitmapBottomLeft.x ? bitmapTopLeft.x - bitmapBottomLeft.x : 0;cutTopLeft.y = bitmapTopLeft.y > bitmapTopRight.y ? bitmapTopLeft.y - bitmapTopRight.y : 0;cutTopRight.x = bitmapTopRight.x > bitmapBottomRight.x ? cropRect.width() : cropRect.width() - Math.abs(bitmapBottomRight.x - bitmapTopRight.x);cutTopRight.y = bitmapTopLeft.y > bitmapTopRight.y ? 0 : Math.abs(bitmapTopLeft.y - bitmapTopRight.y);cutBottomLeft.x = bitmapTopLeft.x > bitmapBottomLeft.x ? 0 : Math.abs(bitmapTopLeft.x - bitmapBottomLeft.x);cutBottomLeft.y = bitmapBottomLeft.y > bitmapBottomRight.y ? cropRect.height() : cropRect.height() - Math.abs(bitmapBottomRight.y - bitmapBottomLeft.y);cutBottomRight.x = bitmapTopRight.x > bitmapBottomRight.x ? cropRect.width() - Math.abs(bitmapBottomRight.x - bitmapTopRight.x) : cropRect.width();cutBottomRight.y = bitmapBottomLeft.y > bitmapBottomRight.y ? cropRect.height() - Math.abs(bitmapBottomRight.y - bitmapBottomLeft.y) : cropRect.height();Log.e("stk", cut.getWidth() + "x" + cut.getHeight());Log.e("stk", "cutPoints="+ cutTopLeft.toString() + " "+ cutTopRight.toString() + " "+ cutBottomRight.toString() + " "+ cutBottomLeft.toString() + " ");float width = cut.getWidth();float height = cut.getHeight();float[] src = new float[]{cutTopLeft.x, cutTopLeft.y, cutTopRight.x, cutTopRight.y, cutBottomRight.x, cutBottomRight.y, cutBottomLeft.x, cutBottomLeft.y};float[] dst = new float[]{0, 0, width, 0, width, height, 0, height};Matrix matrix = new Matrix();matrix.setPolyToPoly(src, 0, dst, 0, 4);Bitmap stretch = Bitmap.createBitmap(cut.getWidth(), cut.getHeight(), Bitmap.Config.ARGB_8888);Canvas stretchCanvas = new Canvas(stretch);//            stretchCanvas.drawBitmap(cut, matrix, null);stretchCanvas.concat(matrix);stretchCanvas.drawBitmapMesh(cut, WIDTH_BLOCK, HEIGHT_BLOCK, generateVertices(cut.getWidth(), cut.getHeight()), 0, null, 0, null);cropListener.onFinish(stretch);}}private int WIDTH_BLOCK  = 40;private int HEIGHT_BLOCK = 40;private float[] generateVertices(int widthBitmap, int heightBitmap) {float[] vertices = new float[(WIDTH_BLOCK + 1) * (HEIGHT_BLOCK + 1) * 2];float widthBlock = (float) widthBitmap / WIDTH_BLOCK;float heightBlock = (float) heightBitmap / HEIGHT_BLOCK;for (int i = 0; i <= HEIGHT_BLOCK; i++)for (int j = 0; j <= WIDTH_BLOCK; j++) {vertices[i * ((HEIGHT_BLOCK + 1) * 2) + (j * 2)] = j * widthBlock;vertices[i * ((HEIGHT_BLOCK + 1) * 2) + (j * 2) + 1] = i * heightBlock;}return vertices;}
}

github地址:WildmaIDCardCamera

参考资料:

  • CertificateCamera
  • PhotoPolygonCropper
  • SweetCamera



作者:wildma
链接:https://www.jianshu.com/p/5e3cb0c63cd5
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

这篇关于Android自定义相机实现身份证拍照,并加入自动对焦与图片不规则裁剪的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/271573

相关文章

Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

Python pyinstaller实现图形化打包工具

《Pythonpyinstaller实现图形化打包工具》:本文主要介绍一个使用PythonPYQT5制作的关于pyinstaller打包工具,代替传统的cmd黑窗口模式打包页面,实现更快捷方便的... 目录1.简介2.运行效果3.相关源码1.简介一个使用python PYQT5制作的关于pyinstall

使用Python实现大文件切片上传及断点续传的方法

《使用Python实现大文件切片上传及断点续传的方法》本文介绍了使用Python实现大文件切片上传及断点续传的方法,包括功能模块划分(获取上传文件接口状态、临时文件夹状态信息、切片上传、切片合并)、整... 目录概要整体架构流程技术细节获取上传文件状态接口获取临时文件夹状态信息接口切片上传功能文件合并功能小

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur

C#实现文件读写到SQLite数据库

《C#实现文件读写到SQLite数据库》这篇文章主要为大家详细介绍了使用C#将文件读写到SQLite数据库的几种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录1. 使用 BLOB 存储文件2. 存储文件路径3. 分块存储文件《文件读写到SQLite数据库China编程的方法》博客中,介绍了文

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里