社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
项目中需要用到拍摄身份证,拍完照片后直接拿到和身份证比例一致的图片,做成功的结果如下:
拍完照后直接拿到裁剪好的图本文的核心技术来自: https://yq.aliyun.com/articles/26706
先看看xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:background="#ffffff"
tools:context="business_android_client.croppercammer.MainActivity">
<business_android_client.croppercammer.ClipCamera
android:id="@+id/surface_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center" />
<business_android_client.croppercammer.view.shadow
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<TextView
android:id="@+id/tv_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请把身份证放入取景框,水平拍摄"
android:textColor="#fff"
android:rotation="90"
android:layout_centerInParent="true"
/>
<Button
android:id="@+id/btn_cancle"
android:layout_width="70dp"
android:layout_height="70dp"
android:background="@drawable/cancle_wite"
/>
<Button
android:layout_alignParentBottom="true"
android:id="@+id/btn_shoot"
android:layout_width="70dp"
android:background="@drawable/sure_wite"
android:layout_height="70dp" />
</RelativeLayout>
1自定义 shadow extends View 灰色的背景框
/** * 获取身份证取景框的矩形 * @return */ private Rect getShadowRegionRect(){ int height = (int) (screenWidth * 0.8);//拍照的阴影框的高度为屏幕宽度的80% 0.8 int width = (int) (height * 1.6);//身份证宽高比例为1.6 // int height= (int) (screenWidth/1.6); int x_center=screenWidth/2; int y_center=screenHeitht/2; // return new Rect(0, y_center - (height / 2), screenWidth, height/2 + y_center); return new Rect(x_center-(height/2), y_center - (width / 2), x_center+(height/2), (width/2)+ y_center); }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.clipRect(0, 0, screenWidth, screenHeitht);//画整个屏幕矩形 canvas.clipRect(getShadowRegionRect(), Region.Op.DIFFERENCE);//裁剪取景框的矩形 canvas.drawColor(0x60000000); canvas.save(); canvas.restore(); }
2.自定义相机 ClipCamera extends SurfaceView
1获取surfaceHolder
private void initView() { getScreenMetrix(ctx); holder = getHolder();//获得surfaceHolder引用 holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置类型 }
2 implements SurfaceHolder.Callback 在回调中打开相机,surfaceHolder连接camera,初始化相机
@Override public void surfaceCreated(SurfaceHolder holder) { if (mCamera == null) { mCamera = Camera.open();//开启相机 setCameraParams(mCamera,mScreenWidth,mScreenHeight); try { mCamera.setPreviewDisplay(holder);//摄像头画面显示在Surface上 } catch (IOException e) { e.printStackTrace(); } } } //初始化相机,主要是选取和屏幕宽高比例最接近的的相机尺寸 ,否则预览图片显示会拉伸
private void setCameraParams(Camera camera, int width, int height) { Log.i(TAG,"setCameraParams width="+width+" height="+height); Camera.Parameters parameters = mCamera.getParameters(); // 获取摄像头支持的PictureSize列表 List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes(); for (Camera.Size size : pictureSizeList) { Log.i(TAG, "pictureSizeList size.width=" + size.width + " size.height=" + size.height); } /**从列表中选取合适的分辨率*/ Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width)); if (null == picSize) { Log.i(TAG, "null == picSize"); picSize = parameters.getPictureSize(); } Log.i(TAG, "picSize.width=" + picSize.width + " picSize.height=" + picSize.height); // 根据选出的PictureSize重新设置SurfaceView大小 float w = picSize.width; float h = picSize.height; parameters.setPictureSize(picSize.width,picSize.height); this.setLayoutParams(new RelativeLayout.LayoutParams((int) (height*(h/w)), height)); // 获取摄像头支持的PreviewSize列表 List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes(); for (Camera.Size size : previewSizeList) { Log.i(TAG, "previewSizeList size.width=" + size.width + " size.height=" + size.height); } Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width); if (null != preSize) { Log.i(TAG, "preSize.width=" + preSize.width + " preSize.height=" + preSize.height); parameters.setPreviewSize(preSize.width, preSize.height); } parameters.setJpegQuality(100); // 设置照片质量 if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式 } mCamera.cancelAutoFocus();//自动对焦。 mCamera.setDisplayOrientation(90);// 设置PreviewDisplay的方向,效果就是将捕获的画面旋转多少度显示 mCamera.setParameters(parameters); }
3拍照,裁剪
裁剪图片只有一行核心代码 bm= Bitmap.creatBitmap(x,y,width,height)
x:拍完图片的x轴中心
y:拍完整图片的y轴中心
height:身份证宽,(因为在图片预览时旋转了90度)阴影框的宽,阴影宽度为屏幕的80%,同样也是照片宽度的80%,因为取景框在屏幕的中间
width:身份证高,身份证宽高比为1.6有了宽后乘以1.6就可以了
参数 String savePath; public void takePicture(String savePath){ this.savePath=savePath; //设置参数,并拍照 setCameraParams(mCamera, mScreenWidth, mScreenHeight); // 当调用camera.takePiture方法后,camera关闭了预览,这时需要调用startPreview()来重新开启预览 mCamera.takePicture(null, null, jpeg);//参数1:按下快门时的回调
2拍照回调,未压缩数据的回调
} //创建jpeg图片回调数据对象 private Camera.PictureCallback jpeg = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera Camera) { BufferedOutputStream bos = null; Bitmap bm = null; try { // 获得图片 bm = BitmapFactory.decodeByteArray(data, 0, data.length); int pic_width = bm.getWidth();//原始图片的宽 int pic_height= bm.getHeight();//原始图片的高3拍照回调,jpeg照片数据回调
int height,width,x_center,y_center; height = (int) (pic_height * 0.8);//截取图片的高 屏幕宽的0.8,拍照取景框的宽为屏幕的0.8 width = (int) (height * 1.6);//截取图片的宽 x_center=pic_width/2;//原始图片x中心 y_center=pic_height/2;//原始图片y轴中心 Matrix matrix = new Matrix(); matrix.postRotate(360,pic_width/2,pic_height/2); bm = Bitmap.createBitmap(bm, x_center - (width / 2) ,//裁剪图片 y_center - (height / 2) , (int) (pic_height*0.8*1.6), (int) (pic_height*0.8), matrix,false); if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { Log.i(TAG, "Environment.getExternalStorageDirectory()="+Environment.getExternalStorageDirectory()); // String filePath = "/sdcard/dyk"+System.currentTimeMillis()+".jpg";//照片保存路径 File file = new File(savePath); if (!file.exists()){ file.createNewFile(); } bos = new BufferedOutputStream(new FileOutputStream(file)); bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//将图片压缩到流中 }else{ Toast.makeText(ctx,"没有检测到内存卡", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { e.printStackTrace(); } finally { try { bos.flush();//输出 bos.close();//关闭 bm.recycle();// 回收bitmap空间 mCamera.stopPreview();// 关闭预览 Uri uri = Uri.fromFile(new File(savePath)); Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(uri); ctx.sendBroadcast(intent); ctx.startActivity(intent.setClass(ctx,PreView.class)); } catch (IOException e) { e.printStackTrace(); } } } };完整的项目下载地址: https://github.com/tianyalian/CropperCammer.git
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!