android camera

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">经常在项目中有这样的需求:预览并拍摄照片, 照片的比例为w/h=4/3,并在预览页面中有取景框。 取景框通常为正方形或者长方形, 正方形一般为标记或者条码扫描,长方形一般为卡片类,如身份证、银行卡等。</span>

对于这类需求主要在与对相机的控制。常见的有3个大小: previewSize, pictureSize, 和surfaceViewSize,这三个大小必须在比例上一致方可使得拍摄和预览的图片不发生变形问题。  要获取合适大小的比例可以通过以下代码来获取

 if (camera == null){
                try {
                    camera = Camera.open();
                }catch (Exception e){
                    event.setStatus(BaseEvent.EVENT_STATUS.EVENT_ERROR);
                    event.setMsg("相机不可用,请保证应用可以访问相机");
                    EventBus.getDefault().post(event);
                    return;
                }
                if(camera == null){//提醒
                    event.setStatus(BaseEvent.EVENT_STATUS.EVENT_ERROR);
                    event.setMsg("相机不可用,请保证应用可以访问相机");
                    EventBus.getDefault().post(event);
                    return;
                }
            }

            //相机参数设置
            parameters = camera.getParameters();
            parameters.setPictureFormat(PixelFormat.JPEG);//设置拍照后存储的图片格式
            parameters.setRotation(90);
            camera.setDisplayOrientation(90);
            Camera.Size presize = getFitSize(parameters.getSupportedPreviewSizes(), 1.3f, 640);
            Camera.Size picsize = getFitSize(parameters.getSupportedPictureSizes(), 1.3f, 640);
            if (presize == null || picsize == null){
                camera.release();
                camera = null;
                event.setStatus(BaseEvent.EVENT_STATUS.EVENT_ERROR);
                event.setMsg("相机格式不支持");
                EventBus.getDefault().post(event);
                return;
            }
            parameters.setPreviewSize(presize.width, presize.height);
            parameters.setPictureSize(picsize.width, picsize.height);
            camera.setParameters(parameters);
            try {
                camera.setPreviewDisplay(holder);
                camera.startPreview();
            } catch (IOException e) {
                e.printStackTrace();
                camera.release();
                camera=null;
            }

 /**获取适配大小
         * */
        protected Camera.Size getFitSize(List<Camera.Size> list, float rate, int width){
            sort(list);
            Camera.Size tmp = null;
            for (Camera.Size size:list){
                float sub = Math.abs(size.width*1.0f/size.height - rate);
                if ( sub < 0.039 && sub > 0.031 && size.width == width){
                    return size;
                }else if (sub < 0.039 && sub > 0.031 ){
                    tmp = size;
                }
            }
            return tmp;
        }

        private void sort(List<Camera.Size> list){
            Collections.sort(list, new Comparator<Camera.Size>() {
                @Override
                public int compare(Camera.Size lhs, Camera.Size rhs) {
                    if (lhs.width>rhs.width)
                        return 1;
                    else if (lhs.width < rhs.width)
                        return -1;
                    return 0;
                }
            });
        }


在上述代码中我使用 4/3的比例,  也有16/9的比例,即1.7左右。

同时应该注意到有两行代码

parameters.setRotation(90);
camera.setDisplayOrientation(90);

这两行代码是设置显示图像和获取的图片的偏转角度, 在竖屏格式下, 设置90偏转才能得到理想的照片。 否则你会发现预览和获取的图片与想要得到的图片偏转了90度。

另一个需要注意的是 previewSize和pictureSize 的width和height 和屏幕的width与height正好相反, 前两者width>height而后者width<height。  在调整surfaceView的宽度和高度时需要注意这个问题,可以使用下面代码调整:

/**分辨率定位4/3, 根据屏幕自身来进行匹配
         * */
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        ViewGroup.LayoutParams params = mSurfaceView.getLayoutParams();
        params.width = metrics.widthPixels;
        params.height = (int) (metrics.widthPixels/3.0*4);
        mSurfaceView.setLayoutParams(params);
        ocrView.setLayoutParams(params);


最后 获取到图片后,怎么截取取景框中的图片呢,思路是这样的可以直接根据比例,即取景框的比例与surfaceview比例和要截取的比例与图片的相同

camera.takePicture(null, null, new Camera.PictureCallback() {
                @Override
                public void onPictureTaken(byte[] data, Camera camera) {//保存为jpeg格式的图片
                    TakePicEvent takePicEvent = new TakePicEvent();
                    Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
                    float width = bitmap.getWidth()*0.8f;
                    float height = width*0.75f;
                    int posx = (int) ((bitmap.getWidth()-width)/2.0);
                    int posy = (int)((bitmap.getHeight() - height)/2.0);
                    Rect r = new Rect(posx, posy, (int)(posx+width), (int)(posy+height));
                    Bitmap  nb  = Bitmap.createBitmap(bitmap, r.left,r.top, r.width(),r.height());
                    File file = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() +"img.jpg");
                    try {
                        FileOutputStream outputStream = new FileOutputStream(file);
                        nb.compress(Bitmap.CompressFormat.JPEG,100,outputStream);
                        outputStream.close();
                        takePicEvent.setStatus(BaseEvent.EVENT_STATUS.EVENT_OK);
                        takePicEvent.setMsg(file.getAbsolutePath());
                        EventBus.getDefault().post(takePicEvent);
                        return;
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //File file = new File(getBaseContext().getFilesDir(),String.format("%dimg.jpg",System.currentTimeMillis()));
                    takePicEvent.setStatus(BaseEvent.EVENT_STATUS.EVENT_ERROR);
                    takePicEvent.setMsg("获取图片失败,请确认存储卡可用");
                    EventBus.getDefault().post(takePicEvent);
                }
            });


附属:

有的系统带有权限管理,所以需要判断设备是否可以正常打开,即使你在配置文件中已经声明使用相机。  通常需要进行异常捕获和空值检测。

截取框显示窗口

public class OcrPreview extends View {
    public OcrPreview(Context context) {
        super(context);
    }

    public OcrPreview(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public OcrPreview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**蒙版设置*/
        float width = getWidth()*0.8f;
        float height = width*0.75f;
        int posx = (int) ((getWidth()-width)/2.0);
        int posy = (int)((getHeight() - height)/2.0);
        Rect r = new Rect(posx, posy, (int)(posx+width), (int)(posy+height));

        Paint paint = new Paint();
        paint.setColor(Color.parseColor("#00ff00"));
        paint.setStrokeWidth(8);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawRect(r,paint);
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值