Android 自定义相机 身份证拍照 自定义身份证相机

来源:互联网 发布:wap网投源码 编辑:程序博客网 时间:2024/05/21 09:45

项目中需要用到拍摄身份证,拍完照片后直接拿到和身份证比例一致的图片,做成功的结果如下:

  

拍完照后直接拿到裁剪好的图本文的核心技术来自: 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拍照回调,未压缩数据的回调
3拍照回调,jpeg照片数据回调
} //创建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();//原始图片的高
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

 
原创粉丝点击