当前位置:   article > 正文

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

koltlin自定义身份证相机

一、 前言

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

身份证来源网络虚拟构造

二、使用

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

  1. allprojects{
  2. repositories {
  3. ...
  4. maven { url "https://jitpack.io" }
  5. }
  6. }

Step 2. 添加依赖
在需要使用的module中添加依赖(最新版本见 WildmaIDCardCamera

  1. dependencies{
  2. compile 'com.github.wildma:IDCardCamera:1.0.1'
  3. }

或者引用本地lib

compileproject(':idcardcamera')

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

CameraActivity.toCameraActivity(this, CameraActivity.TYPE_IDCARD_FRONT);

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

  1. @Override
  2. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  3. if (requestCode == CameraActivity.REQUEST_CODE && resultCode == CameraActivity.RESULT_CODE) {
  4. //获取图片路径,显示图片
  5. final String path = CameraActivity.getImagePath(data);
  6. if (!TextUtils.isEmpty(path)) {
  7. imageView.setImageBitmap(BitmapFactory.decodeFile(path));
  8. }
  9. }
  10. }

三、功能特点

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

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

3.1 自动对焦

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

3.1.1 使用原生API
  1. 调用autoFocus方法,如下:

    1. camera.autoFocus(new Camera.AutoFocusCallback() {
    2. @Override
    3. public void onAutoFocus(boolean success, Camera camera) {
    4. }
    5. });

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

  2. 设置对焦模式,如下:

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

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

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

3.1.2 使用定时器

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

  1. package com.wildma.idcardcamera.camera;
  2. import android.annotation.SuppressLint;
  3. import android.hardware.Camera;
  4. import android.os.AsyncTask;
  5. import android.os.Build;
  6. import android.util.Log;
  7. import java.util.ArrayList;
  8. import java.util.Collection;
  9. import java.util.concurrent.RejectedExecutionException;
  10. public class AutoFocusManager implements Camera.AutoFocusCallback {
  11. private static final String TAG = AutoFocusManager.class.getSimpleName();
  12. private static final long AUTO_FOCUS_INTERVAL_MS = 2000L;
  13. private static final Collection<String> FOCUS_MODES_CALLING_AF;
  14. static {
  15. FOCUS_MODES_CALLING_AF = new ArrayList<String>(2);
  16. FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO);
  17. FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO);
  18. }
  19. private final boolean useAutoFocus;
  20. private final Camera camera;
  21. private boolean stopped;
  22. private boolean focusing;
  23. private AsyncTask<?, ?, ?> outstandingTask;
  24. public AutoFocusManager(Camera camera) {
  25. this.camera = camera;
  26. String currentFocusMode = camera.getParameters().getFocusMode();
  27. useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode);
  28. // Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);
  29. start();
  30. }
  31. @Override
  32. public synchronized void onAutoFocus(boolean success, Camera theCamera) {
  33. focusing = false;
  34. autoFocusAgainLater();
  35. }
  36. @SuppressLint("NewApi")
  37. private synchronized void autoFocusAgainLater() {
  38. if (!stopped && outstandingTask == null) {
  39. AutoFocusTask newTask = new AutoFocusTask();
  40. try {
  41. if (Build.VERSION.SDK_INT >= 11) {
  42. newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  43. } else {
  44. newTask.execute();
  45. }
  46. outstandingTask = newTask;
  47. } catch (RejectedExecutionException ree) {
  48. Log.w(TAG, "Could not request auto focus", ree);
  49. }
  50. }
  51. }
  52. public synchronized void start() {
  53. if (useAutoFocus) {
  54. outstandingTask = null;
  55. if (!stopped && !focusing) {
  56. try {
  57. camera.autoFocus(this);
  58. Log.w(TAG, "自动对焦");
  59. focusing = true;
  60. } catch (RuntimeException re) {
  61. // Have heard RuntimeException reported in Android 4.0.x+;
  62. // continue?
  63. Log.w(TAG, "Unexpected exception while focusing", re);
  64. // Try again later to keep cycle going
  65. autoFocusAgainLater();
  66. }
  67. }
  68. }
  69. }
  70. private synchronized void cancelOutstandingTask() {
  71. if (outstandingTask != null) {
  72. if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) {
  73. outstandingTask.cancel(true);
  74. }
  75. outstandingTask = null;
  76. }
  77. }
  78. public synchronized void stop() {
  79. stopped = true;
  80. if (useAutoFocus) {
  81. cancelOutstandingTask();
  82. // Doesn't hurt to call this even if not focusing
  83. try {
  84. camera.cancelAutoFocus();
  85. } catch (RuntimeException re) {
  86. // Have heard RuntimeException reported in Android 4.0.x+;
  87. // continue?
  88. Log.w(TAG, "Unexpected exception while cancelling focusing", re);
  89. }
  90. }
  91. }
  92. private final class AutoFocusTask extends AsyncTask<Object, Object, Object> {
  93. @Override
  94. protected Object doInBackground(Object... voids) {
  95. try {
  96. Thread.sleep(AUTO_FOCUS_INTERVAL_MS);
  97. } catch (InterruptedException e) {
  98. }
  99. start();
  100. return null;
  101. }
  102. }
  103. }

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

3.1.3 使用传感器

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

  1. package com.wildma.idcardcamera.camera;
  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.hardware.Sensor;
  5. import android.hardware.SensorEvent;
  6. import android.hardware.SensorEventListener;
  7. import android.hardware.SensorManager;
  8. import android.util.Log;
  9. import java.util.Calendar;
  10. public class SensorControler implements SensorEventListener {
  11. public static final String TAG = "SensorControler";
  12. private SensorManager mSensorManager;
  13. private Sensor mSensor;
  14. private int mX, mY, mZ;
  15. private long lastStaticStamp = 0;
  16. Calendar mCalendar;
  17. public static final int DELEY_DURATION = 500;
  18. private static SensorControler mInstance;
  19. private int foucsing = 1; //1 表示没有被锁定 0表示被锁定
  20. boolean isFocusing = false;
  21. boolean canFocusIn = false; //内部是否能够对焦控制机制
  22. boolean canFocus = false;
  23. public static final int STATUS_NONE = 0;
  24. public static final int STATUS_STATIC = 1;
  25. public static final int STATUS_MOVE = 2;
  26. private int STATUE = STATUS_NONE;
  27. private SensorControler(Context context) {
  28. mSensorManager = (SensorManager) context.getSystemService(Activity.SENSOR_SERVICE);
  29. mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);// TYPE_GRAVITY
  30. }
  31. public static SensorControler getInstance(Context context) {
  32. if (mInstance == null) {
  33. mInstance = new SensorControler(context);
  34. }
  35. return mInstance;
  36. }
  37. public void onStart() {
  38. restParams();
  39. canFocus = true;
  40. mSensorManager.registerListener(this, mSensor,
  41. SensorManager.SENSOR_DELAY_NORMAL);
  42. }
  43. public void onStop() {
  44. mSensorManager.unregisterListener(this, mSensor);
  45. canFocus = false;
  46. }
  47. @Override
  48. public void onAccuracyChanged(Sensor sensor, int accuracy) {
  49. }
  50. @Override
  51. public void onSensorChanged(SensorEvent event) {
  52. if (event.sensor == null) {
  53. return;
  54. }
  55. if (isFocusing) {
  56. restParams();
  57. return;
  58. }
  59. if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
  60. int x = (int) event.values[0];
  61. int y = (int) event.values[1];
  62. int z = (int) event.values[2];
  63. mCalendar = Calendar.getInstance();
  64. long stamp = mCalendar.getTimeInMillis();// 1393844912
  65. int second = mCalendar.get(Calendar.SECOND);// 53
  66. if (STATUE != STATUS_NONE) {
  67. int px = Math.abs(mX - x);
  68. int py = Math.abs(mY - y);
  69. int pz = Math.abs(mZ - z);
  70. // Log.d(TAG, "pX:" + px + " pY:" + py + " pZ:" + pz + " stamp:"
  71. // + stamp + " second:" + second);
  72. double value = Math.sqrt(px * px + py * py + pz * pz);
  73. if (value > 1.4) {
  74. // textviewF.setText("检测手机在移动..");
  75. // Log.i(TAG,"mobile moving");
  76. STATUE = STATUS_MOVE;
  77. } else {
  78. // textviewF.setText("检测手机静止..");
  79. // Log.i(TAG,"mobile static");
  80. //上一次状态是move,记录静态时间点
  81. if (STATUE == STATUS_MOVE) {
  82. lastStaticStamp = stamp;
  83. canFocusIn = true;
  84. }
  85. if (canFocusIn) {
  86. if (stamp - lastStaticStamp > DELEY_DURATION) {
  87. //移动后静止一段时间,可以发生对焦行为
  88. if (!isFocusing) {
  89. canFocusIn = false;
  90. // onCameraFocus();
  91. if (mCameraFocusListener != null) {
  92. mCameraFocusListener.onFocus();
  93. }
  94. // Log.i(TAG,"mobile focusing");
  95. }
  96. }
  97. }
  98. STATUE = STATUS_STATIC;
  99. }
  100. } else {
  101. lastStaticStamp = stamp;
  102. STATUE = STATUS_STATIC;
  103. }
  104. mX = x;
  105. mY = y;
  106. mZ = z;
  107. }
  108. }
  109. /**
  110. * 重置参数
  111. */
  112. private void restParams() {
  113. STATUE = STATUS_NONE;
  114. canFocusIn = false;
  115. mX = 0;
  116. mY = 0;
  117. mZ = 0;
  118. }
  119. /**
  120. * 对焦是否被锁定
  121. *
  122. * @return
  123. */
  124. public boolean isFocusLocked() {
  125. if (canFocus) {
  126. return foucsing <= 0;
  127. }
  128. return false;
  129. }
  130. /**
  131. * 锁定对焦
  132. */
  133. public void lockFocus() {
  134. isFocusing = true;
  135. foucsing--;
  136. Log.i(TAG, "lockFocus");
  137. }
  138. /**
  139. * 解锁对焦
  140. */
  141. public void unlockFocus() {
  142. isFocusing = false;
  143. foucsing++;
  144. Log.i(TAG, "unlockFocus");
  145. }
  146. public void restFoucs() {
  147. foucsing = 1;
  148. }
  149. private CameraFocusListener mCameraFocusListener;
  150. public interface CameraFocusListener {
  151. void onFocus();
  152. }
  153. public void setCameraFocusListener(CameraFocusListener mCameraFocusListener) {
  154. this.mCameraFocusListener = mCameraFocusListener;
  155. }
  156. }

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

3.2 图片不规则裁剪

要实现的效果如下:
alt

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

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

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

  1. package com.wildma.idcardcamera.cropper;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.Canvas;
  5. import android.graphics.Color;
  6. import android.graphics.Matrix;
  7. import android.graphics.Paint;
  8. import android.graphics.Path;
  9. import android.graphics.Point;
  10. import android.graphics.PorterDuff;
  11. import android.graphics.PorterDuffXfermode;
  12. import android.graphics.Rect;
  13. import android.graphics.Region;
  14. import android.support.annotation.Nullable;
  15. import android.util.AttributeSet;
  16. import android.util.Log;
  17. import android.view.MotionEvent;
  18. import android.view.View;
  19. public class CropOverlayView extends View {
  20. private int defaultMargin = 100;
  21. private int minDistance = 100;
  22. private int vertexSize = 30;
  23. private int gridSize = 3;
  24. private Bitmap bitmap;
  25. private Point topLeft, topRight, bottomLeft, bottomRight;
  26. private float touchDownX, touchDownY;
  27. private CropPosition cropPosition;
  28. private int currentWidth = 0;
  29. private int currentHeight = 0;
  30. private int minX, maxX, minY, maxY;
  31. public CropOverlayView(Context context) {
  32. super(context);
  33. }
  34. public CropOverlayView(Context context, @Nullable AttributeSet attrs) {
  35. super(context, attrs);
  36. }
  37. public void setBitmap(Bitmap bitmap) {
  38. this.bitmap = bitmap;
  39. resetPoints();
  40. invalidate();
  41. }
  42. @Override
  43. protected void onDraw(Canvas canvas) {
  44. super.onDraw(canvas);
  45. if (getWidth() != currentWidth || getHeight() != currentHeight) {
  46. currentWidth = getWidth();
  47. currentHeight = getHeight();
  48. resetPoints();
  49. }
  50. Log.e("stk", "canvasSize=" + getWidth() + "x" + getHeight());
  51. drawBackground(canvas);
  52. drawVertex(canvas);
  53. drawEdge(canvas);
  54. // drawGrid(canvas);//裁剪框内部线条
  55. }
  56. private void resetPoints() {
  57. Log.e("stk", "resetPoints, bitmap=" + bitmap);
  58. // 1. calculate bitmap size in new canvas
  59. float scaleX = bitmap.getWidth() * 1.0f / getWidth();
  60. float scaleY = bitmap.getHeight() * 1.0f / getHeight();
  61. float maxScale = Math.max(scaleX, scaleY);
  62. // 2. determine minX , maxX if maxScale = scaleY | minY, maxY if maxScale = scaleX
  63. int minX = 0;
  64. int maxX = getWidth();
  65. int minY = 0;
  66. int maxY = getHeight();
  67. if (maxScale == scaleY) { // image very tall
  68. int bitmapInCanvasWidth = (int) (bitmap.getWidth() / maxScale);
  69. minX = (getWidth() - bitmapInCanvasWidth) / 2;
  70. maxX = getWidth() - minX;
  71. } else { // image very wide
  72. int bitmapInCanvasHeight = (int) (bitmap.getHeight() / maxScale);
  73. minY = (getHeight() - bitmapInCanvasHeight) / 2;
  74. maxY = getHeight() - minY;
  75. }
  76. this.minX = minX;
  77. this.minY = minY;
  78. this.maxX = maxX;
  79. this.maxY = maxY;
  80. if (maxX - minX < defaultMargin || maxY - minY < defaultMargin)
  81. defaultMargin = 0; // remove min
  82. else
  83. defaultMargin = 100;
  84. Log.e("stk", "maxX - minX=" + (maxX - minX));
  85. Log.e("stk", "maxY - minY=" + (maxY - minY));
  86. topLeft = new Point(minX + defaultMargin, minY + defaultMargin);
  87. topRight = new Point(maxX - defaultMargin, minY + defaultMargin);
  88. bottomLeft = new Point(minX + defaultMargin, maxY - defaultMargin);
  89. bottomRight = new Point(maxX - defaultMargin, maxY - defaultMargin);
  90. }
  91. @Override
  92. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  93. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  94. }
  95. private void drawBackground(Canvas canvas) {
  96. Paint paint = new Paint();
  97. paint.setColor(Color.parseColor("#66000000"));
  98. paint.setStyle(Paint.Style.FILL);
  99. Path path = new Path();
  100. path.moveTo(topLeft.x, topLeft.y);
  101. path.lineTo(topRight.x, topRight.y);
  102. path.lineTo(bottomRight.x, bottomRight.y);
  103. path.lineTo(bottomLeft.x, bottomLeft.y);
  104. path.close();
  105. canvas.save();
  106. canvas.clipPath(path, Region.Op.DIFFERENCE);
  107. canvas.drawColor(Color.parseColor("#66000000"));
  108. canvas.restore();
  109. }
  110. private void drawVertex(Canvas canvas) {
  111. Paint paint = new Paint();
  112. paint.setColor(Color.WHITE);
  113. paint.setStyle(Paint.Style.FILL);
  114. canvas.drawCircle(topLeft.x, topLeft.y, vertexSize, paint);
  115. canvas.drawCircle(topRight.x, topRight.y, vertexSize, paint);
  116. canvas.drawCircle(bottomLeft.x, bottomLeft.y, vertexSize, paint);
  117. canvas.drawCircle(bottomRight.x, bottomRight.y, vertexSize, paint);
  118. Log.e("stk",
  119. "vertextPoints=" +
  120. topLeft.toString() + " " + topRight.toString() + " " + bottomRight.toString() + " " + bottomLeft.toString());
  121. }
  122. private void drawEdge(Canvas canvas) {
  123. Paint paint = new Paint();
  124. paint.setColor(Color.WHITE);
  125. paint.setStrokeWidth(3);
  126. paint.setAntiAlias(true);
  127. canvas.drawLine(topLeft.x, topLeft.y, topRight.x, topRight.y, paint);
  128. canvas.drawLine(topLeft.x, topLeft.y, bottomLeft.x, bottomLeft.y, paint);
  129. canvas.drawLine(bottomRight.x, bottomRight.y, topRight.x, topRight.y, paint);
  130. canvas.drawLine(bottomRight.x, bottomRight.y, bottomLeft.x, bottomLeft.y, paint);
  131. }
  132. private void drawGrid(Canvas canvas) {
  133. Paint paint = new Paint();
  134. paint.setColor(Color.WHITE);
  135. paint.setStrokeWidth(2);
  136. paint.setAntiAlias(true);
  137. for (int i = 1; i <= gridSize; i++) {
  138. int topDistanceX = Math.abs(topLeft.x - topRight.x) / (gridSize + 1) * i;
  139. int topDistanceY = Math.abs((topLeft.y - topRight.y) / (gridSize + 1) * i);
  140. Point top = new Point(
  141. topLeft.x < topRight.x ? topLeft.x + topDistanceX : topLeft.x - topDistanceX,
  142. topLeft.y < topRight.y ? topLeft.y + topDistanceY : topLeft.y - topDistanceY);
  143. int bottomDistanceX = Math.abs((bottomLeft.x - bottomRight.x) / (gridSize + 1) * i);
  144. int bottomDistanceY = Math.abs((bottomLeft.y - bottomRight.y) / (gridSize + 1) * i);
  145. Point bottom = new Point(
  146. bottomLeft.x < bottomRight.x ? bottomLeft.x + bottomDistanceX : bottomLeft.x - bottomDistanceX,
  147. bottomLeft.y < bottomRight.y ? bottomLeft.y + bottomDistanceY : bottomLeft.y - bottomDistanceY);
  148. canvas.drawLine(top.x, top.y, bottom.x, bottom.y, paint);
  149. int leftDistanceX = Math.abs((topLeft.x - bottomLeft.x) / (gridSize + 1) * i);
  150. int leftDistanceY = Math.abs((topLeft.y - bottomLeft.y) / (gridSize + 1) * i);
  151. Point left = new Point(
  152. topLeft.x < bottomLeft.x ? topLeft.x + leftDistanceX : topLeft.x - leftDistanceX,
  153. topLeft.y < bottomLeft.y ? topLeft.y + leftDistanceY : topLeft.y - leftDistanceY);
  154. int rightDistanceX = Math.abs((topRight.x - bottomRight.x) / (gridSize + 1) * i);
  155. int rightDistanceY = Math.abs((topRight.y - bottomRight.y) / (gridSize + 1) * i);
  156. Point right = new Point(
  157. topRight.x < bottomRight.x ? topRight.x + rightDistanceX : topRight.x - rightDistanceX,
  158. topRight.y < bottomRight.y ? topRight.y + rightDistanceY : topRight.y - rightDistanceY);
  159. canvas.drawLine(left.x, left.y, right.x, right.y, paint);
  160. }
  161. }
  162. @Override
  163. public boolean onTouchEvent(MotionEvent event) {
  164. switch (event.getAction()) {
  165. case MotionEvent.ACTION_UP:
  166. getParent().requestDisallowInterceptTouchEvent(false);
  167. break;
  168. case MotionEvent.ACTION_DOWN:
  169. getParent().requestDisallowInterceptTouchEvent(false);
  170. onActionDown(event);
  171. return true;
  172. case MotionEvent.ACTION_MOVE:
  173. getParent().requestDisallowInterceptTouchEvent(true);
  174. onActionMove(event);
  175. return true;
  176. }
  177. return false;
  178. }
  179. private void onActionDown(MotionEvent event) {
  180. touchDownX = event.getX();
  181. touchDownY = event.getY();
  182. Point touchPoint = new Point((int) event.getX(), (int) event.getY());
  183. int minDistance = distance(touchPoint, topLeft);
  184. cropPosition = CropPosition.TOP_LEFT;
  185. if (minDistance > distance(touchPoint, topRight)) {
  186. minDistance = distance(touchPoint, topRight);
  187. cropPosition = CropPosition.TOP_RIGHT;
  188. }
  189. if (minDistance > distance(touchPoint, bottomLeft)) {
  190. minDistance = distance(touchPoint, bottomLeft);
  191. cropPosition = CropPosition.BOTTOM_LEFT;
  192. }
  193. if (minDistance > distance(touchPoint, bottomRight)) {
  194. minDistance = distance(touchPoint, bottomRight);
  195. cropPosition = CropPosition.BOTTOM_RIGHT;
  196. }
  197. }
  198. private int distance(Point src, Point dst) {
  199. return (int) Math.sqrt(Math.pow(src.x - dst.x, 2) + Math.pow(src.y - dst.y, 2));
  200. }
  201. private void onActionMove(MotionEvent event) {
  202. int deltaX = (int) (event.getX() - touchDownX);
  203. int deltaY = (int) (event.getY() - touchDownY);
  204. switch (cropPosition) {
  205. case TOP_LEFT:
  206. adjustTopLeft(deltaX, deltaY);
  207. invalidate();
  208. break;
  209. case TOP_RIGHT:
  210. adjustTopRight(deltaX, deltaY);
  211. invalidate();
  212. break;
  213. case BOTTOM_LEFT:
  214. adjustBottomLeft(deltaX, deltaY);
  215. invalidate();
  216. break;
  217. case BOTTOM_RIGHT:
  218. adjustBottomRight(deltaX, deltaY);
  219. invalidate();
  220. break;
  221. }
  222. touchDownX = event.getX();
  223. touchDownY = event.getY();
  224. }
  225. private void adjustTopLeft(int deltaX, int deltaY) {
  226. int newX = topLeft.x + deltaX;
  227. if (newX < minX)
  228. newX = minX;
  229. if (newX > maxX)
  230. newX = maxX;
  231. int newY = topLeft.y + deltaY;
  232. if (newY < minY)
  233. newY = minY;
  234. if (newY > maxY)
  235. newY = maxY;
  236. topLeft.set(newX, newY);
  237. }
  238. private void adjustTopRight(int deltaX, int deltaY) {
  239. int newX = topRight.x + deltaX;
  240. if (newX > maxX)
  241. newX = maxX;
  242. if (newX < minX)
  243. newX = minX;
  244. int newY = topRight.y + deltaY;
  245. if (newY < minY)
  246. newY = minY;
  247. if (newY > maxY)
  248. newY = maxY;
  249. topRight.set(newX, newY);
  250. }
  251. private void adjustBottomLeft(int deltaX, int deltaY) {
  252. int newX = bottomLeft.x + deltaX;
  253. if (newX < minX)
  254. newX = minX;
  255. if (newX > maxX)
  256. newX = maxX;
  257. int newY = bottomLeft.y + deltaY;
  258. if (newY > maxY)
  259. newY = maxY;
  260. if (newY < minY)
  261. newY = minY;
  262. bottomLeft.set(newX, newY);
  263. }
  264. private void adjustBottomRight(int deltaX, int deltaY) {
  265. int newX = bottomRight.x + deltaX;
  266. if (newX > maxX)
  267. newX = maxX;
  268. if (newX < minX)
  269. newX = minX;
  270. int newY = bottomRight.y + deltaY;
  271. if (newY > maxY)
  272. newY = maxY;
  273. if (newY < minY)
  274. newY = minY;
  275. bottomRight.set(newX, newY);
  276. }
  277. public void crop(CropListener cropListener, boolean needStretch) {
  278. if (topLeft == null)
  279. return;
  280. // calculate bitmap size in new canvas
  281. float scaleX = bitmap.getWidth() * 1.0f / getWidth();
  282. float scaleY = bitmap.getHeight() * 1.0f / getHeight();
  283. float maxScale = Math.max(scaleX, scaleY);
  284. // re-calculate coordinate in original bitmap
  285. Log.e("stk", "maxScale=" + maxScale);
  286. Point bitmapTopLeft = new Point((int) ((topLeft.x - minX) * maxScale), (int) ((topLeft.y - minY) * maxScale));
  287. Point bitmapTopRight = new Point((int) ((topRight.x - minX) * maxScale), (int) ((topRight.y - minY) * maxScale));
  288. Point bitmapBottomLeft = new Point((int) ((bottomLeft.x - minX) * maxScale), (int) ((bottomLeft.y - minY) * maxScale));
  289. Point bitmapBottomRight = new Point((int) ((bottomRight.x - minX) * maxScale), (int) ((bottomRight.y - minY) * maxScale));
  290. Log.e("stk", "bitmapPoints="
  291. + bitmapTopLeft.toString() + " "
  292. + bitmapTopRight.toString() + " "
  293. + bitmapBottomRight.toString() + " "
  294. + bitmapBottomLeft.toString() + " ");
  295. Bitmap output = Bitmap.createBitmap(bitmap.getWidth() + 1, bitmap.getHeight() + 1, Bitmap.Config.ARGB_8888);
  296. Canvas canvas = new Canvas(output);
  297. Paint paint = new Paint();
  298. // 1. draw path
  299. Path path = new Path();
  300. path.moveTo(bitmapTopLeft.x, bitmapTopLeft.y);
  301. path.lineTo(bitmapTopRight.x, bitmapTopRight.y);
  302. path.lineTo(bitmapBottomRight.x, bitmapBottomRight.y);
  303. path.lineTo(bitmapBottomLeft.x, bitmapBottomLeft.y);
  304. path.close();
  305. canvas.drawPath(path, paint);
  306. // 2. draw original bitmap
  307. paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
  308. canvas.drawBitmap(bitmap, 0, 0, paint);
  309. // 3. cut
  310. Rect cropRect = new Rect(
  311. Math.min(bitmapTopLeft.x, bitmapBottomLeft.x),
  312. Math.min(bitmapTopLeft.y, bitmapTopRight.y),
  313. Math.max(bitmapBottomRight.x, bitmapTopRight.x),
  314. Math.max(bitmapBottomRight.y, bitmapBottomLeft.y));
  315. Bitmap cut = Bitmap.createBitmap(
  316. output,
  317. cropRect.left,
  318. cropRect.top,
  319. cropRect.width(),
  320. cropRect.height()
  321. );
  322. if (!needStretch) {
  323. cropListener.onFinish(cut);
  324. } else {
  325. // 4. re-calculate coordinate in cropRect
  326. Point cutTopLeft = new Point();
  327. Point cutTopRight = new Point();
  328. Point cutBottomLeft = new Point();
  329. Point cutBottomRight = new Point();
  330. cutTopLeft.x = bitmapTopLeft.x > bitmapBottomLeft.x ? bitmapTopLeft.x - bitmapBottomLeft.x : 0;
  331. cutTopLeft.y = bitmapTopLeft.y > bitmapTopRight.y ? bitmapTopLeft.y - bitmapTopRight.y : 0;
  332. cutTopRight.x = bitmapTopRight.x > bitmapBottomRight.x ? cropRect.width() : cropRect.width() - Math.abs(bitmapBottomRight.x - bitmapTopRight.x);
  333. cutTopRight.y = bitmapTopLeft.y > bitmapTopRight.y ? 0 : Math.abs(bitmapTopLeft.y - bitmapTopRight.y);
  334. cutBottomLeft.x = bitmapTopLeft.x > bitmapBottomLeft.x ? 0 : Math.abs(bitmapTopLeft.x - bitmapBottomLeft.x);
  335. cutBottomLeft.y = bitmapBottomLeft.y > bitmapBottomRight.y ? cropRect.height() : cropRect.height() - Math.abs(bitmapBottomRight.y - bitmapBottomLeft.y);
  336. cutBottomRight.x = bitmapTopRight.x > bitmapBottomRight.x ? cropRect.width() - Math.abs(bitmapBottomRight.x - bitmapTopRight.x) : cropRect.width();
  337. cutBottomRight.y = bitmapBottomLeft.y > bitmapBottomRight.y ? cropRect.height() - Math.abs(bitmapBottomRight.y - bitmapBottomLeft.y) : cropRect.height();
  338. Log.e("stk", cut.getWidth() + "x" + cut.getHeight());
  339. Log.e("stk", "cutPoints="
  340. + cutTopLeft.toString() + " "
  341. + cutTopRight.toString() + " "
  342. + cutBottomRight.toString() + " "
  343. + cutBottomLeft.toString() + " ");
  344. float width = cut.getWidth();
  345. float height = cut.getHeight();
  346. float[] src = new float[]{cutTopLeft.x, cutTopLeft.y, cutTopRight.x, cutTopRight.y, cutBottomRight.x, cutBottomRight.y, cutBottomLeft.x, cutBottomLeft.y};
  347. float[] dst = new float[]{0, 0, width, 0, width, height, 0, height};
  348. Matrix matrix = new Matrix();
  349. matrix.setPolyToPoly(src, 0, dst, 0, 4);
  350. Bitmap stretch = Bitmap.createBitmap(cut.getWidth(), cut.getHeight(), Bitmap.Config.ARGB_8888);
  351. Canvas stretchCanvas = new Canvas(stretch);
  352. // stretchCanvas.drawBitmap(cut, matrix, null);
  353. stretchCanvas.concat(matrix);
  354. stretchCanvas.drawBitmapMesh(cut, WIDTH_BLOCK, HEIGHT_BLOCK, generateVertices(cut.getWidth(), cut.getHeight()), 0, null, 0, null);
  355. cropListener.onFinish(stretch);
  356. }
  357. }
  358. private int WIDTH_BLOCK = 40;
  359. private int HEIGHT_BLOCK = 40;
  360. private float[] generateVertices(int widthBitmap, int heightBitmap) {
  361. float[] vertices = new float[(WIDTH_BLOCK + 1) * (HEIGHT_BLOCK + 1) * 2];
  362. float widthBlock = (float) widthBitmap / WIDTH_BLOCK;
  363. float heightBlock = (float) heightBitmap / HEIGHT_BLOCK;
  364. for (int i = 0; i <= HEIGHT_BLOCK; i++)
  365. for (int j = 0; j <= WIDTH_BLOCK; j++) {
  366. vertices[i * ((HEIGHT_BLOCK + 1) * 2) + (j * 2)] = j * widthBlock;
  367. vertices[i * ((HEIGHT_BLOCK + 1) * 2) + (j * 2) + 1] = i * heightBlock;
  368. }
  369. return vertices;
  370. }
  371. }

github地址:WildmaIDCardCamera

参考资料:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/683033
推荐阅读
相关标签
  

闽ICP备14008679号