Zxing中的camera

現(xiàn)在的工作需要用到camera模塊,所以打算分析Zxing中的camera實現(xiàn),來了解android的camera释漆。zxing有完整的camera控制。

廢話不多說剪决,開始camera的分析之旅灵汪!

一.源碼下載? https://github.com/zxing/zxing

二.CameraManager類,就是我們要分析的第一個類柑潦。

接下來看一下CameraManager這個類為我們提供了什么方法

1.openDriver(SurfaceHolder holder) ?打開攝像頭

2.isOpen() ?判斷攝像頭是否打開

3.closeDriver() 關(guān)閉攝像頭

4.startPreview() 啟動預(yù)覽

5.stopPreview() 關(guān)閉預(yù)覽

6.setTorch(boolean newSetting) 設(shè)置對焦

7.requestPreviewFrame(Handler handler, int message) 獲取預(yù)覽的圖片(重要的一個方法)

8.getFramingRect() 獲取矩形框(根據(jù)屏幕分辨率然后按照一個固定的比例來設(shè)置方框大小)

9.getFramingRectInPreview() 獲取掃描區(qū)域的矩形框(getFramingRect是UI的顯示峻凫,這是掃描的區(qū)域渗鬼,其實豎屏掃描的時候,形式是正方形的框荧琼,但是獲取到的圖片確實長方形的)

10.setManualCameraId(int cameraId) 設(shè)置camera 的Id

11.setManualFramingRect(int width, int height) ?設(shè)置矩形框的寬高(UI)

12.buildLuminanceSource(byte[] data, int width, int height) 對byte[] Source進(jìn)行統(tǒng)一的處理(不同設(shè)備譬胎,相機返回的Source是不一樣的)


三.關(guān)鍵代碼分析

1.打開攝像頭OpenCamera

OpenCameraInterface打開打開攝像頭的控制類,OpenCamera類存放打開攝像頭的對象命锄,CameraFacing類,枚舉堰乔,兩個參數(shù),前置和后置攝像頭脐恩。staticOpenCameraopen方法對各種攝像頭的情況做了判斷镐侯,例如相判斷該設(shè)備有沒有攝像頭,然后判斷打開的攝像頭是不是空驶冒,空就啟動后置攝像頭等苟翻,具體看下面的代碼。

public staticOpenCameraopen(intcameraId) {

intnumCameras = Camera.getNumberOfCameras();//獲取攝像頭的個數(shù)

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) {//不同的設(shè)備骗污,攝像頭的個數(shù)不一樣

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類獲取預(yù)覽圖片setOneShotPreviewCallback這個接口就是獲取預(yù)覽圖片崇猫,previewCallback是回調(diào)接口

public synchronized voidrequestPreviewFrame(Handler handler, intmessage) {

OpenCamera theCamera =camera;

if(theCamera !=null&&previewing) {

previewCallback.setHandler(handler,message);

theCamera.getCamera().setOneShotPreviewCallback(previewCallback);

}

}

3.CameraConfigurationManager類,相機的配置管理類initFromCameraParameters初始化方法需忿。根據(jù)不同的設(shè)備诅炉,還有橫豎屏的方向蜡歹,給Camera計算出最好的size。然后通過setDesiredCameraParameters方法設(shè)置Camera的配置參數(shù)涕烧,例如設(shè)置聚焦模式月而,照片的大小,場景澈魄,特效等等景鼠。

一些常用的配置:

1、setPictureFormat()方法用于設(shè)置相機照片的格式,其參數(shù)是一個字符型參數(shù)痹扇,位于PixelFormat類中铛漓,我們在這里選擇PixelFormat.JPEG。)

2鲫构、setSceneMode()方法用于設(shè)置相機場景類型浓恶,其參是是一個字符型參數(shù),位于Parameters類中结笨,以SCENE_MODE_開頭包晰。

3、setZoom()方法用于設(shè)置相機焦距炕吸,其參數(shù)是一個整型的參數(shù)伐憾,該參數(shù)的范圍是0到Camera.getParameters().getMaxZoom()。

4赫模、setPictureSize()方法用于設(shè)置相機照片的大小树肃,參數(shù)為整型。

5瀑罗、setWhiteBalance()胸嘴,方法用于設(shè)置相機照片白平衡,其參數(shù)是一個字符型參數(shù)斩祭,位于Parameters類中劣像,以WHITE_BALANCE開頭。

6摧玫、setJpegQuality()方法用于設(shè)置相機照片的質(zhì)量耳奕,其參數(shù)是一個整型參數(shù),取值范圍為1到100席赂。

7吮铭、setFlashMode()方法用于設(shè)置閃光燈的類型,其參數(shù)是一個字符型參數(shù)颅停,位于Parameters類中谓晌,以FLASH_MODE_開頭。

8癞揉、setColorEffect()方法用于設(shè)置照片顏色特效的類型纸肉,其參數(shù)是一個字符型參數(shù)溺欧,位于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) { //根據(jù)橫豎屏給previewSizeOnScreen賦值

previewSizeOnScreen=bestPreviewSize;

}else{

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

}

......

}

CameraConfigurationUtils.findBestPreviewSizeValue這個方法的實現(xiàn)邏輯:(代碼不貼了)

首先姐刁,查找手機支持的預(yù)覽尺寸集合,如果集合為空烦味,就返回默認(rèn)的尺寸聂使;否則,對尺寸集合根據(jù)尺寸的像素從小到大進(jìn)行排序谬俄;

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

在者溃论,在剩余的尺寸集合中屎蜓,剔除預(yù)覽寬高比與屏幕分辨率寬高比之差的絕對值大于0.15的所有尺寸;

最后钥勋,尋找能夠精確的與屏幕寬高匹配上的預(yù)覽尺寸炬转,如果存在則返回該寬高比;如果不存在算灸,則使用尺寸集合中最大的那個尺寸扼劈。如果說尺寸集合已經(jīng)在前面的過濾中被全部排除,則返回相機默認(rèn)的尺寸值菲驴。

附加:UI的簡單分析

1.CaptureActivity是掃描的UI實現(xiàn)测僵,數(shù)據(jù)的傳遞都是通過Handler實現(xiàn)的,設(shè)置都保存到Preference里面谢翎,PreferenceManager就是設(shè)置保存的管理類,ViewfinderView繼承View沐旨,camera的UI顯示就是通過這個View森逮。

CaptureActivity類的部分代碼

public voidonCreate(Bundle icicle) {

super.onCreate(icicle);

Window window = getWindow();

window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//設(shè)置常亮

......

PreferenceManager.setDefaultValues(this,R.xml.preferences, false);//設(shè)置默認(rèn)的配置,文件放在xml文件夾下

}

看一下onResume方法

protected void onResume() {

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

//根據(jù)配置文件來和傳感器切換橫豎屏的顯示

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

getCurrentOrientation();

}else{

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);

}

resetStatusView();

//...

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

// 判斷跳轉(zhuǎn)過來的時候是否帶上了寬度磁携,高度

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類,不同的設(shè)備獲取的照片是不一樣的谊迄,所以必須要做處理

總結(jié):camera部分就分析到這里闷供,如果上述有錯誤,請指出统诺,謝謝歪脏!

此文由暴風(fēng)雨1024原創(chuàng),?轉(zhuǎn)載粮呢,請注明出處婿失,謝謝钞艇!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市豪硅,隨后出現(xiàn)的幾起案子哩照,更是在濱河造成了極大的恐慌,老刑警劉巖懒浮,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件飘弧,死亡現(xiàn)場離奇詭異,居然都是意外死亡砚著,警方通過查閱死者的電腦和手機次伶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赖草,“玉大人学少,你說我怎么就攤上這事⊙砥铮” “怎么了版确?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乎折。 經(jīng)常有香客問我绒疗,道長,這世上最難降的妖魔是什么骂澄? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任吓蘑,我火速辦了婚禮,結(jié)果婚禮上坟冲,老公的妹妹穿的比我還像新娘磨镶。我一直安慰自己,他們只是感情好健提,可當(dāng)我...
    茶點故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布琳猫。 她就那樣靜靜地躺著,像睡著了一般私痹。 火紅的嫁衣襯著肌膚如雪脐嫂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天紊遵,我揣著相機與錄音账千,去河邊找鬼。 笑死暗膜,一個胖子當(dāng)著我的面吹牛匀奏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桦山,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼攒射,長吁一口氣:“原來是場噩夢啊……” “哼醋旦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起会放,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤饲齐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后咧最,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捂人,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年矢沿,在試婚紗的時候發(fā)現(xiàn)自己被綠了滥搭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡捣鲸,死狀恐怖瑟匆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情栽惶,我是刑警寧澤愁溜,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站外厂,受9級特大地震影響冕象,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜汁蝶,卻給世界環(huán)境...
    茶點故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一渐扮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧掖棉,春花似錦墓律、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至紫谷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捐寥,已是汗流浹背笤昨。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留握恳,地道東北人瞒窒。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像乡洼,于是被迫代替她去往敵國和親崇裁。 傳聞我的和親對象是個殘疾皇子匕坯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,573評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 二維碼掃描最近兩年簡直是風(fēng)靡移動互聯(lián)網(wǎng)時代,尤其在國內(nèi)發(fā)展神速拔稳。圍繞條碼掃碼功能葛峻,首先說說通過本文你可以知道啥。一...
    55book閱讀 4,153評論 0 1
  • public classCamera.Parametersextends Objectjava.lang.Obje...
    冉冉升起的小太陽閱讀 10,920評論 0 7
  • 上一篇介紹了如何使用系統(tǒng)相機簡單巴比、快速的進(jìn)行拍照术奖,本篇將介紹如何使用框架提供的API直接控制攝像機硬件。 你還在為...
    Xiao_Mai閱讀 7,192評論 4 18
  • (1) 晚上11點半才開始匆匆忙忙的寫今天的文章轻绞,為的是參與簡年活動采记,也為的是堅持日更這件事不停下來。 如果換在以...
    從小白到精通閱讀 213評論 2 1
  • 今天吃了早飯之后就開始做事了政勃,主要就是幫客棧收拾下那些退了的房間唧龄,就是做一些換床單被套然后打掃一下衛(wèi)...
    天空藍(lán)上閱讀 150評論 0 0