Camera是什么

Camera官方说明The Camera class is used toset image capture settings, start/stop preview, snap pictures, and retrieveframes for encoding for video. This class is a client for the Camera service,which manages the actual camera hardware.

大概意思是Camera是一个用来设置图片获取选项,开启/关闭预览,连续拍照,获取视频解码每一帧,对于管理实际摄像硬件的Camer service来说它相当于一个客户端。

Camera应用场景

项目开发中经常会遇到拍照或录像的需求,有两种实现方式一种是调用系统相机,另一种是使用系统Camera类和surfaceView来实现自定义Camera。

Camera使用

1 Menifest添加权限

<!--允许使用相机-->
<uses-permission android:name="android.permission.CAMERA"/>
<!--允许使用外部存储-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--允许使用闪光灯-->
<uses-permission android:name="android.permission.FLASHLIGHT"/>

<!--使用相机特性-->
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>

 

2.打开相机

判断是否有相机


/**
 * check if the device has a camera
 * @return
 */
private boolean checkCameraHardWare() {
    if(getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        return true;
    }
    return false;
}


 

 

调用Camera的open方法获取实例

/**
  * a safe way to get an instance ofCamera Object
  * @return
  */private CameragetCameraInst() {
     Camera cameraInst = null;
     try {
         cameraInst = cameraInst.open();
     } catch(Exception e) {
         e.printStackTrace();
     }
     returncameraInst;
}

 

3.初始化

a 设置拍摄角度

b 设置相机参数,预览大小,闪光灯开关,缩放比例。

c 设置预览要使用的surfaceholder

d 打开预览

 

Camera.Parameters parameters = mCamera.getParameters();
// ......设置Camera参数
mCamera.setParameters(parameters);

 

mCamera.setPreviewDisplay(holder);
mCamera.startPreview();

 

4 使用相机

获取图片


a.  调用takePictrue,会触发一个异步的图片获取,以及多个回调。此方法会导致预览关闭,若想继续预览在获取图片后再次调用startPreview


参数说明


shutter call back 当图片被获取到的时候会被回调,可以用来播放一个声音让用户知道图片已经被获取到。


PictureCallBack raw 当图片的原始数据可用时会被回调


PictureCallBack postView 当发生缩放时会被回调,并不是所有设备都支持。


PictureCallBack jpeg 当被压缩的图片可用时,会被回调


mCameraInstance.takePicture(null, null, new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        // 在这里处理获取到的图片,data可直接转化为bitmap或图片文件

    }
});


 


b另外获取视频的示例这里暂时不做过多介绍,可参考官方文档https://developer.android.com/guide/topics/media/camera.html

5关闭预览,释放相机资源。

 

注意

a。注意:一定要设置预览大小,否则图片会变形。设置预览尺寸,首先获取设备支持的预览尺寸列表,找到与屏幕分辨率差值最小的并设置。

List<Camera.Size>supportedPreviewSizes = parameters.getSupportedPreviewSizes();
WindowManager windowManager =(WindowManager)  mContext.getSystemService(Context.WINDOW_SERVICE);
 int screenW = windowManager.getDefaultDisplay().getWidth();
 int screenH =windowManager.getDefaultDisplay().getHeight();
Log.d("hezd","supportscreen size:width="+screenW+",height="+screenH);
 int diff = Integer.MAX_VALUE;
Camera.Size beseSize = null;
 for(Camera.Size size : supportedPreviewSizes){
     Log.d("hezd","supportsize:width="+size.width+",height="+size.height);
     int height= Math.abs(screenH-size.height);
     int width= Math.abs(size.width-screenW);
     int currentDiff= width+height;
     if(currentDiff==0||currentDiff<diff){
         beseSize = size;
         diff= currentDiff;
     }
 }
if(beseSize!=null) {
     parameters.setPreviewSize(beseSize.width,beseSize.height);
}

 

B 要截取的预览区域非全屏的情况获取图片

  这种情况还是比较麻烦的,如果直接使用扫描框的坐标去截取获取的图片是不正确,因为这时获取的图片是尺寸不一定是当前扫描框父窗体的的尺寸。我在这里的解决办法是先将图片缩小到同当前父窗体相同尺寸,在根据扫描框坐标去截取。

Matrix matrix = new Matrix();
matrix.postRotate(90);
matrix.postScale(difW,difH);
Bitmap rotateBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix,true);
 if(bitmap!=null){
     bitmap.recycle();
}

 ByteArrayOutputStream bos = new ByteArrayOutputStream();
rotateBitmap.compress(Bitmap.CompressFormat.JPEG,100,bos);
 try {
     BitmapRegionDecoder regionDecoder =BitmapRegionDecoder.newInstance(bos.toByteArray(),0,bos.toByteArray().length,false);
     Rectrect = new Rect(mScaLeft,mScanTop,mScanWidth,mScanHeight);
     BitmapregionBitmap = regionDecoder.decodeRegion(rect, options);
     mShowPicIv.setVisibility(View.VISIBLE);
     mShowPicIv.setImageBitmap(rotateBitmap);
     mPicIv.setImageBitmap(regionBitmap);
} catch(IOException e) {
     e.printStackTrace();
}

 

另外还想到一个办法,没有尝试,有兴趣的同学可以尝试一下,就是去设置相机图片尺寸,然后再去截取。

 

身份证扫描

在应用中需要对身份证扫描获取信息的场景很多,参考很多ocr相关资料和项目后,编写了一个示例工程,在文章最后附上地址。

代码下载

身份证扫描项目地址