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原创, 转载,请注明出处,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 二维码扫描最近两年简直是风靡移动互联网时代,尤其在国内发展神速。围绕条码扫码功能,首先说说通过本文你可以知道啥。一...
    55book阅读 4,136评论 0 1
  • public classCamera.Parametersextends Objectjava.lang.Obje...
    冉冉升起的小太阳阅读 10,860评论 0 7
  • 上一篇介绍了如何使用系统相机简单、快速的进行拍照,本篇将介绍如何使用框架提供的API直接控制摄像机硬件。 你还在为...
    Xiao_Mai阅读 7,137评论 4 18
  • (1) 晚上11点半才开始匆匆忙忙的写今天的文章,为的是参与简年活动,也为的是坚持日更这件事不停下来。 如果换在以...
    从小白到精通阅读 204评论 2 1
  • 今天吃了早饭之后就开始做事了,主要就是帮客栈收拾下那些退了的房间,就是做一些换床单被套然后打扫一下卫...
    天空蓝上阅读 144评论 0 0