Zxing中的camera

现在的工作需要用到camera模块,所以打算分析Zxing中的camera实现,来了解android的camera。zxing有完整的camera控制。

废话不多说,开始camera的分析之旅!

一.源码下载  https://github.com/zxing/zxing

二.CameraManager类,就是我们要分析的第一个类。

接下来看一下CameraManager这个类为我们提供了什么方法

1.openDriver(SurfaceHolder holder)  打开摄像头

2.isOpen()  判断摄像头是否打开

3.closeDriver() 关闭摄像头

4.startPreview() 启动预览

5.stopPreview() 关闭预览

6.setTorch(boolean newSetting) 设置对焦

7.requestPreviewFrame(Handler handler, int message) 获取预览的图片(重要的一个方法)

8.getFramingRect() 获取矩形框(根据屏幕分辨率然后按照一个固定的比例来设置方框大小)

9.getFramingRectInPreview() 获取扫描区域的矩形框(getFramingRect是UI的显示,这是扫描的区域,其实竖屏扫描的时候,形式是正方形的框,但是获取到的图片确实长方形的)

10.setManualCameraId(int cameraId) 设置camera 的Id

11.setManualFramingRect(int width, int height)  设置矩形框的宽高(UI)

12.buildLuminanceSource(byte[] data, int width, int height) 对byte[] Source进行统一的处理(不同设备,相机返回的Source是不一样的)


三.关键代码分析

1.打开摄像头OpenCamera

OpenCameraInterface打开打开摄像头的控制类,OpenCamera类存放打开摄像头的对象,CameraFacing类,枚举,两个参数,前置和后置摄像头。staticOpenCameraopen方法对各种摄像头的情况做了判断,例如相判断该设备有没有摄像头,然后判断打开的摄像头是不是空,空就启动后置摄像头等,具体看下面的代码。

public staticOpenCameraopen(intcameraId) {

intnumCameras = Camera.getNumberOfCameras();//获取摄像头的个数

if(numCameras ==0) {

return null;

}

boolean explicitRequest = cameraId >=0;

Camera.CameraInfo selectedCameraInfo =null;

intindex;

if(explicitRequest) {

index = cameraId;

selectedCameraInfo =newCamera.CameraInfo();

Camera.getCameraInfo(index,selectedCameraInfo);

}else{//启动后置摄像头

index =0;

while(index < numCameras) {//不同的设备,摄像头的个数不一样

Camera.CameraInfo cameraInfo =newCamera.CameraInfo();

Camera.getCameraInfo(index,cameraInfo);

CameraFacing reportedFacing = CameraFacing.values()[cameraInfo.facing];

if(reportedFacing == CameraFacing.BACK) {

selectedCameraInfo = cameraInfo;

break;

}

index++;

}

}

Camera camera;

if(index < numCameras) {

Log.i(TAG,"Opening camera #"+ index);

camera = Camera.open(index);//打开摄像头

}else{

if(explicitRequest) {

Log.w(TAG,"Requested camera does not exist: "+ cameraId);

camera =null;

}else{

Log.i(TAG,"No camera facing "+ CameraFacing.BACK+"; returning camera #0");

camera = Camera.open(0);

selectedCameraInfo =newCamera.CameraInfo();

Camera.getCameraInfo(0,selectedCameraInfo);

}

}

if(camera ==null) {

return null;

}

return newOpenCamera(index,

camera,

CameraFacing.values()[selectedCameraInfo.facing],

selectedCameraInfo.orientation);

}

2.CameraManager类获取预览图片setOneShotPreviewCallback这个接口就是获取预览图片,previewCallback是回调接口

public synchronized voidrequestPreviewFrame(Handler handler, intmessage) {

OpenCamera theCamera =camera;

if(theCamera !=null&&previewing) {

previewCallback.setHandler(handler,message);

theCamera.getCamera().setOneShotPreviewCallback(previewCallback);

}

}

3.CameraConfigurationManager类,相机的配置管理类initFromCameraParameters初始化方法。根据不同的设备,还有横竖屏的方向,给Camera计算出最好的size。然后通过setDesiredCameraParameters方法设置Camera的配置参数,例如设置聚焦模式,照片的大小,场景,特效等等。

一些常用的配置:

1、setPictureFormat()方法用于设置相机照片的格式,其参数是一个字符型参数,位于PixelFormat类中,我们在这里选择PixelFormat.JPEG。)

2、setSceneMode()方法用于设置相机场景类型,其参是是一个字符型参数,位于Parameters类中,以SCENE_MODE_开头。

3、setZoom()方法用于设置相机焦距,其参数是一个整型的参数,该参数的范围是0到Camera.getParameters().getMaxZoom()。

4、setPictureSize()方法用于设置相机照片的大小,参数为整型。

5、setWhiteBalance(),方法用于设置相机照片白平衡,其参数是一个字符型参数,位于Parameters类中,以WHITE_BALANCE开头。

6、setJpegQuality()方法用于设置相机照片的质量,其参数是一个整型参数,取值范围为1到100。

7、setFlashMode()方法用于设置闪光灯的类型,其参数是一个字符型参数,位于Parameters类中,以FLASH_MODE_开头。

8、setColorEffect()方法用于设置照片颜色特效的类型,其参数是一个字符型参数,位于Parameters类中,以EFFECT_开头。

接下来看一下代码:

void initFromCameraParameters(OpenCamera camera) {//初始化配置

Camera.Parameters parameters = camera.getCamera().getParameters();

WindowManager manager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

Display display = manager.getDefaultDisplay();

intdisplayRotation = display.getRotation();

intcwRotationFromNaturalToDisplay;

switch(displayRotation) { //手机的方向

caseSurface.ROTATION_0:

cwRotationFromNaturalToDisplay =0;

break;

caseSurface.ROTATION_90:

cwRotationFromNaturalToDisplay =90;

break;

caseSurface.ROTATION_180:

cwRotationFromNaturalToDisplay =180;

break;

......

cameraResolution= CameraConfigurationUtils.findBestPreviewSizeValue(parameters,screenResolution);               //寻找最好的PreviewSize

Log.i(TAG,"Camera resolution: "+cameraResolution);

bestPreviewSize= CameraConfigurationUtils.findBestPreviewSizeValue(parameters,screenResolution);

......

if(isScreenPortrait == isPreviewSizePortrait) { //根据横竖屏给previewSizeOnScreen赋值

previewSizeOnScreen=bestPreviewSize;

}else{

previewSizeOnScreen=newPoint(bestPreviewSize.y,bestPreviewSize.x);

}

......

}

CameraConfigurationUtils.findBestPreviewSizeValue这个方法的实现逻辑:(代码不贴了)

首先,查找手机支持的预览尺寸集合,如果集合为空,就返回默认的尺寸;否则,对尺寸集合根据尺寸的像素从小到大进行排序;

其次,移除不满足最小像素要求的所有尺寸;

在者,在剩余的尺寸集合中,剔除预览宽高比与屏幕分辨率宽高比之差的绝对值大于0.15的所有尺寸;

最后,寻找能够精确的与屏幕宽高匹配上的预览尺寸,如果存在则返回该宽高比;如果不存在,则使用尺寸集合中最大的那个尺寸。如果说尺寸集合已经在前面的过滤中被全部排除,则返回相机默认的尺寸值。

附加:UI的简单分析

1.CaptureActivity是扫描的UI实现,数据的传递都是通过Handler实现的,设置都保存到Preference里面,PreferenceManager就是设置保存的管理类,ViewfinderView继承View,camera的UI显示就是通过这个View。

CaptureActivity类的部分代码

public voidonCreate(Bundle icicle) {

super.onCreate(icicle);

Window window = getWindow();

window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//设置常亮

......

PreferenceManager.setDefaultValues(this,R.xml.preferences, false);//设置默认的配置,文件放在xml文件夹下

}

看一下onResume方法

protected void onResume() {

//...   省略初始化的操作

//根据配置文件来和传感器切换横竖屏的显示

if(prefs.getBoolean(PreferencesActivity.KEY_DISABLE_AUTO_ORIENTATION, true)) {

getCurrentOrientation();

}else{

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);

}

resetStatusView();

//...

if(Intents.Scan.ACTION.equals(action)) {

// 判断跳转过来的时候是否带上了宽度,高度

if(intent.hasExtra(Intents.Scan.WIDTH) && intent.hasExtra(Intents.Scan.HEIGHT)) {

int width = intent.getIntExtra(Intents.Scan.WIDTH,0);

int height = intent.getIntExtra(Intents.Scan.HEIGHT,0);

if(width >0&& height >0) {

cameraManager.setManualFramingRect(width,height);

}

}

//... 省略一些传参和赋值

SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view);

SurfaceHolder surfaceHolder = surfaceView.getHolder();

if(hasSurface) {

initCamera(surfaceHolder);

//最后初始化相机(主要就是这两个方法,打开相机和初始化Handler

//cameraManager.openDriver(surfaceHolder);

//handler=new CaptureActivityHandler(this,decodeFormats,decodeHints,characterSet,cameraManager);)

}

2.其他还有对图片的处理类PlanarYUVLuminanceSource和HybridBinarizer类,不同的设备获取的照片是不一样的,所以必须要做处理

总结:camera部分就分析到这里,如果上述有错误,请指出,谢谢!

此文由暴风雨1024原创, 转载,请注明出处,谢谢!

你可能感兴趣的:(Zxing中的camera)