zoukankan      html  css  js  c++  java
  • Android实现身份证拍摄框

    http://blog.csdn.net/lhbtm/article/details/55505668

    最近项目需要实现身份证拍照的功能,系统的相机并不能满足需求,故需要自定义相机,先上效果图,使用了Camera+ SurfaceView;

    布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
       >
        <com.example.administrator.camerasurfaceview.CameraSurfaceView
            android:id="@+id/cameraSurfaceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <com.example.administrator.camerasurfaceview.CameraTopRectView
            android:id="@+id/rectOnCamera"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <Button
                android:layout_alignParentBottom="true"
                android:layout_centerHorizontal="true"
                android:layout_marginBottom="20px"
                android:id="@+id/takePic"
                android:layout_width="80dp"
                android:layout_height="50dp"
                android:background="#88427ac7"
                android:text="拍照"
                android:textColor="#aaa" />
        </RelativeLayout>
    
    
    </FrameLayout>
    
    MainActivity
    package com.example.administrator.camerasurfaceview;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends AppCompatActivity {
    
        private Button button;
        private CameraSurfaceView mCameraSurfaceView;
        private RectOnCamera rectOnCamera;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
    //        requestWindowFeature(Window.FEATURE_NO_TITLE);
    //        // 全屏显示
    //        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
            setContentView(R.layout.activity_main);
    
            mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.cameraSurfaceView);
            button = (Button) findViewById(R.id.takePic);
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mCameraSurfaceView.takePicture();
                }
            });
        }
    
    
    //    public void autoFocus() {
    //        mCameraSurfaceView.setAutoFocus();
    //    }
    }
    

    自定义相机类

    package com.example.administrator.camerasurfaceview;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Matrix;
    import android.hardware.Camera;
    import android.os.Environment;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.WindowManager;
    import android.widget.FrameLayout;
    import android.widget.Toast;
    
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.List;
    
    /**
     * Created by Administrator on 2017/2/15 0015.//自定义相机
     */
    public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
    
        private static final String TAG = "CameraSurfaceView";
    
        private Context mContext;
        private SurfaceHolder holder;
        private Camera mCamera;
    
        private int mScreenWidth;
        private int mScreenHeight;
        private CameraTopRectView topView;
    
        public CameraSurfaceView(Context context) {
            this(context, null);
        }
    
        public CameraSurfaceView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            getScreenMetrix(context);
            topView = new CameraTopRectView(context,attrs);
    
            initView();
    
    
        }
    
        //拿到手机屏幕大小
        private void getScreenMetrix(Context context) {
            WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            DisplayMetrics outMetrics = new DisplayMetrics();
            WM.getDefaultDisplay().getMetrics(outMetrics);
            mScreenWidth = outMetrics.widthPixels;
            mScreenHeight = outMetrics.heightPixels;
    
        }
    
        private void initView() {
            holder = getHolder();//获得surfaceHolder引用
            holder.addCallback(this);
    //        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置类型
    
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            Log.i(TAG, "surfaceCreated");
            if (mCamera == null) {
                mCamera = Camera.open();//开启相机
                try {
                    mCamera.setPreviewDisplay(holder);//摄像头画面显示在Surface上
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            Log.i(TAG, "surfaceChanged");
    
            setCameraParams(mCamera, mScreenWidth, mScreenHeight);
            mCamera.startPreview();
    //        mCamera.takePicture(null, null, jpeg);
    
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            Log.i(TAG, "surfaceDestroyed");
            mCamera.stopPreview();//停止预览
            mCamera.release();//释放相机资源
            mCamera = null;
            holder = null;
        }
    
        @Override
        public void onAutoFocus(boolean success, Camera Camera) {
            if (success) {
                Log.i(TAG, "onAutoFocus success="+success);
                System.out.println(success);
            }
        }
    
    
        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 FrameLayout.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);
    
        }
    
        /**
         * 从列表中选取合适的分辨率
         * 默认w:h = 4:3
         * <p>注意:这里的w对应屏幕的height
         *            h对应屏幕的width<p/>
         */
        private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) {
            Log.i(TAG, "screenRatio=" + screenRatio);
            Camera.Size result = null;
            for (Camera.Size size : pictureSizeList) {
                float currentRatio = ((float) size.width) / size.height;
                if (currentRatio - screenRatio == 0) {
                    result = size;
                    break;
                }
            }
    
            if (null == result) {
                for (Camera.Size size : pictureSizeList) {
                    float curRatio = ((float) size.width) / size.height;
                    if (curRatio == 4f / 3) {// 默认w:h = 4:3
                        result = size;
                        break;
                    }
                }
            }
    
            return result;
        }
    
    
        // 拍照瞬间调用
        private Camera.ShutterCallback shutter = new Camera.ShutterCallback() {
            @Override
            public void onShutter() {
                Log.i(TAG,"shutter");
                System.out.println("执行了吗+1");
            }
        };
    
        // 获得没有压缩过的图片数据
        private Camera.PictureCallback raw = new Camera.PictureCallback() {
    
            @Override
            public void onPictureTaken(byte[] data, Camera Camera) {
                Log.i(TAG, "raw");
                System.out.println("执行了吗+2");
            }
        };
    
        //创建jpeg图片回调数据对象
        private Camera.PictureCallback jpeg = new Camera.PictureCallback() {
    
            private Bitmap bitmap;
    
            @Override
            public void onPictureTaken(byte[] data, Camera Camera) {
    
    
                topView.draw(new Canvas());
    
                BufferedOutputStream bos = null;
                Bitmap bm = null;
                if(data != null){
    
    
    
    
                }
    
                try {
                    // 获得图片
                    bm = BitmapFactory.decodeByteArray(data, 0, data.length);
    
                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                        String filePath = "/sdcard/dyk"+System.currentTimeMillis()+".JPEG";//照片保存路径
    
    //                    //图片存储前旋转
                        Matrix m = new Matrix();
                        int height = bm.getHeight();
                        int width = bm.getWidth();
                        m.setRotate(90);
                        //旋转后的图片
                        bitmap = Bitmap.createBitmap(bm, 0, 0, width, height, m, true);
    
    
                        System.out.println("执行了吗+3");
                        File file = new File(filePath);
                        if (!file.exists()){
                            file.createNewFile();
                        }
                        bos = new BufferedOutputStream(new FileOutputStream(file));
    
    //                    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
    //                            data.length);
                        Bitmap sizeBitmap = Bitmap.createScaledBitmap(bitmap,
                                topView.getViewWidth(), topView.getViewHeight(), true);
                        bm = Bitmap.createBitmap(sizeBitmap, topView.getRectLeft(),
                                topView.getRectTop(),
                                topView.getRectRight() - topView.getRectLeft(),
                                topView.getRectBottom() - topView.getRectTop());// 截取
    
    
                        bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//将图片压缩到流中
    
                    }else{
                        Toast.makeText(mContext,"没有检测到内存卡", Toast.LENGTH_SHORT).show();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        bos.flush();//输出
                        bos.close();//关闭
                        bm.recycle();// 回收bitmap空间
                        mCamera.stopPreview();// 关闭预览
                        mCamera.startPreview();// 开启预览
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
    
            }
        };
    
        public void takePicture(){
            //设置参数,并拍照
            setCameraParams(mCamera, mScreenWidth, mScreenHeight);
            // 当调用camera.takePiture方法后,camera关闭了预览,这时需要调用startPreview()来重新开启预览
            mCamera.takePicture(null,null, jpeg);
        }
    
    //    public void setAutoFocus(){
    //        mCamera.autoFocus(this);
    //    }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
        }
    
    }

    自定义身份证方框

    
    
    package com.example.administrator.camerasurfaceview;
    
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Paint.FontMetricsInt;
    import android.graphics.Paint.Style;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.view.View;
    import android.view.WindowManager;
    
    //import cn.jiazhengye.panda_home.application.BaseApplication;
    //import cn.jiazhengye.panda_home.common.Constant;
    //import cn.jiazhengye.panda_home.utils.DisplayUtil;
    //import cn.jiazhengye.panda_home.utils.LoggerUtil;
    
    class CameraTopRectView extends View {
    
        private int panelWidth;
        private int panelHeght;
    
        private int viewWidth;
        private int viewHeight;
    
        public int rectWidth;
        public int rectHeght;
    
        private int rectTop;
        private int rectLeft;
        private int rectRight;
        private int rectBottom;
    
        private int lineLen;
        private int lineWidht;
        private static final int LINE_WIDTH = 5;
        private static final int TOP_BAR_HEIGHT = 50;
        private static final int BOTTOM_BTN_HEIGHT = 66;
    
    //    private static final int TOP_BAR_HEIGHT = Constant.RECT_VIEW_TOP;
    //    private static final int BOTTOM_BTN_HEIGHT = Constant.RECT_VIEW_BOTTOM;
    
        private static final int LEFT_PADDING = 10;
        private static final int RIGHT_PADDING = 10;
        private static final String TIPS = "请将身份证放入到方框中";
    
        private Paint linePaint;
        private Paint wordPaint;
        private Rect rect;
        private int baseline;
    
        public CameraTopRectView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // TODO Auto-generated constructor stub
    Activity activity = (Activity) context;
    
            WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
            panelWidth = wm.getDefaultDisplay().getWidth();//拿到屏幕的宽
            panelHeght = wm.getDefaultDisplay().getHeight();//拿到屏幕的高
    
            //高度不需要dp转换px,不然整体相机会向上移动一小节
    //        viewHeight = panelHeght - (int) DisplayUtil.dp2px(activity,TOP_BAR_HEIGHT + BOTTOM_BTN_HEIGHT);
    
            viewHeight = panelHeght;
            //viewHeight,界面的高,viewWidth,界面的宽
            viewWidth = panelWidth;
    
            /*rectWidth = panelWidth
                    - UnitUtils.getInstance(activity).dip2px(
                            LEFT_PADDING + RIGHT_PADDING);*/
    rectWidth = panelWidth - (int) DisplayUtil.dp2px(activity,LEFT_PADDING + RIGHT_PADDING);
    
            rectHeght = (int) (rectWidth * 54 / 85.6);
            // 相对于此view
            rectTop = (viewHeight - rectHeght) / 2;
            rectLeft = (viewWidth - rectWidth) / 2;
            rectBottom = rectTop + rectHeght;
            rectRight = rectLeft + rectWidth;
    
            lineLen = panelWidth / 8;
    
            linePaint = new Paint();
            linePaint.setAntiAlias(true);
            linePaint.setColor(Color.rgb(0xdd, 0x42, 0x2f));
            linePaint.setStyle(Style.STROKE);
            linePaint.setStrokeWidth(LINE_WIDTH);// 设置线宽
            linePaint.setAlpha(255);
    
            wordPaint = new Paint();
            wordPaint.setAntiAlias(true);
            wordPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            wordPaint.setStrokeWidth(3);
            wordPaint.setTextSize(35);
    
            rect = new Rect(rectLeft, rectTop - 80, rectRight, rectTop - 10);
            FontMetricsInt fontMetrics = wordPaint.getFontMetricsInt();
            baseline = rect.top + (rect.bottom - rect.top - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
            wordPaint.setTextAlign(Paint.Align.CENTER);
        }
    
        @Override
        public void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            wordPaint.setColor(Color.TRANSPARENT);
            canvas.drawRect(rect, wordPaint);
    
            //画蒙层
            wordPaint.setColor(0xa0000000);
            rect = new Rect(0, viewHeight/2+rectHeght/2, viewWidth, viewHeight);
            canvas.drawRect(rect, wordPaint);
    
            rect = new Rect(0, 0, viewWidth, viewHeight/2-rectHeght/2);
            canvas.drawRect(rect, wordPaint);
    
            rect = new Rect(0, viewHeight/2-rectHeght/2, (viewWidth-rectWidth)/2, viewHeight/2+rectHeght/2);
            canvas.drawRect(rect, wordPaint);
    
            rect = new Rect(viewWidth-(viewWidth-rectWidth)/2, viewHeight/2-rectHeght/2, viewWidth, viewHeight/2+rectHeght/2);
            canvas.drawRect(rect, wordPaint);
    
    
            //重制rect  并画文字  吧文字置于rect中间
            rect = new Rect(rectLeft, rectTop - 80, rectRight, rectTop - 10);
            wordPaint.setColor(Color.WHITE);
            canvas.drawText(TIPS, rect.centerX(), baseline, wordPaint);
            canvas.drawLine(rectLeft, rectTop, rectLeft + lineLen, rectTop,
                    linePaint);
            canvas.drawLine(rectRight - lineLen, rectTop, rectRight, rectTop,
                    linePaint);
            canvas.drawLine(rectLeft, rectTop, rectLeft, rectTop + lineLen,
                    linePaint);
            canvas.drawLine(rectRight, rectTop, rectRight, rectTop + lineLen,
                    linePaint);
            canvas.drawLine(rectLeft, rectBottom, rectLeft + lineLen, rectBottom,
                    linePaint);
            canvas.drawLine(rectRight - lineLen, rectBottom, rectRight, rectBottom,
                    linePaint);
            canvas.drawLine(rectLeft, rectBottom - lineLen, rectLeft, rectBottom,
                    linePaint);
            canvas.drawLine(rectRight, rectBottom - lineLen, rectRight, rectBottom,
                    linePaint);
        }
    
        public int getRectLeft() {
            return rectLeft;
        }
    
        public int getRectTop() {
            return rectTop;
        }
    
        public int getRectRight() {
            return rectRight;
        }
    
        public int getRectBottom() {
            return rectBottom;
        }
    
        public int getViewWidth() {
            return viewWidth;
        }
    
        public int getViewHeight() {
            return viewHeight;
        }
    
    }
    DisplayUtil工具类
    package com.example.administrator.camerasurfaceview;
    
    import android.content.Context;
    
    /**
     * Created by Administrator on 2017/2/16 0016.
     */
    public class DisplayUtil {
        /**
         * 将px装换成dp,保证尺寸不变
         * @param context
         * @param pxValue
         * @return
         */
        public static int px2dp(Context context, float pxValue){
            float density = context.getResources().getDisplayMetrics().density;//得到设备的密度
            return (int) (pxValue/density+0.5f);
        }
        public static int dp2px(Context context, float dpValue){
            float density = context.getResources().getDisplayMetrics().density;
            return (int) (dpValue*density+0.5f);
        }
        public static int px2sp(Context context, float pxValue){
            float scaleDensity = context.getResources().getDisplayMetrics().scaledDensity;//缩放密度
            return (int) (pxValue/scaleDensity+0.5f);
        }
        public static int sp2px(Context context, float spValue) {
            float scaleDensity = context.getResources().getDisplayMetrics().scaledDensity;
            return (int) (spValue*scaleDensity+0.5f);
        }
    }
  • 相关阅读:
    Cordova各个插件使用介绍系列(四)—canvas2ImagePlugin保存二维码到手机本地
    如何实现一个简单的MVVM框架
    2015年总结
    基于setTimeout制作滚动广告板
    (Frontend Newbie)JavaScript基础之函数
    (Frontend Newbie)JavaScript基础之常见数据类型
    (Frontend Newbie)Web三要素(三)
    (Frontend Newbie)Web三要素(二)
    (Frontend Newbie) Web三要素(一)
    (Frontend Newbie)Web简史
  • 原文地址:https://www.cnblogs.com/wcLT/p/8489385.html
Copyright © 2011-2022 走看看