Android Camera探究之路——起步

Android Camera探究之路——起步

Camera在手機(jī)中有著舉足輕重的地位宛琅,不管是二維碼還是照片浅碾、識(shí)別,都離不開攝像頭纵刘,本文將對(duì)Android中的Camera進(jìn)行全面解析穴翩。

權(quán)限鎮(zhèn)樓:

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<uses-feature android:name="android.hardware.camera"/>

調(diào)用系統(tǒng)Camera

通過(guò)系統(tǒng)定義的Intent Action犬第,我們可以很方便的使用所有實(shí)現(xiàn)了Camera功能的App。

ACTION_IMAGE_CAPTURE

這個(gè)action是最常用的一個(gè)調(diào)用系統(tǒng)Camera的action芒帕。

使用方式如下:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

通過(guò)這樣一個(gè)Action歉嗓,我們就可以調(diào)用所有聲明了Camera的App。
那么如何收到拍攝的圖片呢背蟆?我們自然是需要使用startActivityForResult方法鉴分。

這里我們先來(lái)看最簡(jiǎn)單的:

我們?cè)冢?/p>

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    }

onActivityResult方法中,通過(guò)data參數(shù)來(lái)獲取圖像:

/**
 * 通過(guò)data取得圖片
 */
Bundle extras = data.getExtras();
Bitmap bitmap = (Bitmap) extras.get("data");
mImageViewShow.setImageBitmap(bitmap);

但是带膀,現(xiàn)在手機(jī)像素這么高志珍,萬(wàn)一圖片特別大呢,會(huì)不會(huì)data過(guò)大而FC呢垛叨?放心伦糯,Android早就考慮到了,所以嗽元,data里面壓根就不是完整的圖片敛纲,它只是一張縮略圖,對(duì)还棱,真的是縮略圖载慈。所以惭等,我們需要獲取到拍攝的原圖珍手,就不能使用這種方法。但是我們可以這樣做,我們可以指定MediaStore類的一個(gè)EXTRA_OUTPUT來(lái)指定拍攝圖像保存的位置琳要,相當(dāng)于建立一個(gè)臨時(shí)文件寡具。在onActivityResult中,我們不使用data來(lái)獲取圖像稚补,而是直接去讀這個(gè)臨時(shí)文件即可童叠。

指定EXTRA_OUTPUT:

String tempPath = Environment.getExternalStorageDirectory().getPath();
mFilePath = tempPath + "/" + "test1.png";
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri photoUri = Uri.fromFile(new File(mFilePath));
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(intent, CAMERA_CODE1);

onActivityResult:

/**
 * 通過(guò)暫存路徑取得圖片
 */
FileInputStream fis = null;
Bitmap bitmap = null;
try {
    fis = new FileInputStream(mFilePath);
    bitmap = BitmapFactory.decodeStream(fis);
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

這樣我們就可以獲取到完整的拍攝圖片了。后面你可以讓圖像顯示出來(lái)课幕,顯示的時(shí)候厦坛,同樣需要考慮大圖的處理,避免圖像尺寸帶來(lái)的問(wèn)題乍惊,這些東西杜秸,請(qǐng)參考這里:

http://blog.csdn.net/eclipsexys/article/details/44459771

這里就不贅述了。如果你的App僅僅是需要非常簡(jiǎn)單的拍攝功能润绎,那么通過(guò)調(diào)用系統(tǒng)Intent就足夠了撬碟,但是大部分時(shí)候,這都是不可能的莉撇,所以下面我們來(lái)看看如何自定義Camera呢蛤。

自定義Camera

根據(jù)Google Android Doc,自定義一個(gè)Camera需要如下幾個(gè)步驟:

1.檢查Camera是否存在棍郎,并在AndroidManifest.xml中賦予相關(guān)的權(quán)限其障;

2.創(chuàng)建一個(gè)繼承于SurfaceView并實(shí)現(xiàn)SurfaceHolder接口的Camera Preview類;

3.新建一個(gè)Camera Preview布局文件涂佃;

4.設(shè)置一個(gè)拍照的監(jiān)聽事件静秆,例如單擊按鈕事件等;

5.實(shí)現(xiàn)拍照巡李,并保存拍照后的圖片到設(shè)備抚笔;

6.釋放Camera。

看上去還是比較復(fù)雜的侨拦。所以我們一步步來(lái)殊橙。

首先,我們創(chuàng)建預(yù)覽Camera的界面:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_switch_camera"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:onClick="switchCamera"
            android:text="切換攝像頭"/>

        <Button
            android:id="@+id/btn_capture"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:onClick="capture"
            android:text="拍照"/>
    </LinearLayout>

    <SurfaceView
        android:id="@+id/sv_camera"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/ll"
        android:text="camera"/>

</RelativeLayout>  

非常簡(jiǎn)單狱从,兩個(gè)button下面一個(gè)surfaceview:

這里寫圖片描述

然后膨蛮,我們創(chuàng)建一個(gè)Activity,用來(lái)展示Camera的預(yù)覽:

這個(gè)Activity里面肯定有SurfaceView季研,所以敞葛,SurfaceView的那一套東西,自然是少不了与涡,不懂的請(qǐng)自行腦補(bǔ)惹谐。

那么在這個(gè)Activity里面持偏,我們需要做什么呢??jī)杉虑椋?/p>

  1. 初始化相機(jī)
  2. 將內(nèi)容顯示到SurfaceView

Android的Camera是獨(dú)享的氨肌,如果多處調(diào)用鸿秆,就會(huì)拋出異常,所以怎囚,我們需要將Camera的生命周期與Activity的生命周期綁定:

  1. onResume方法中初始化相機(jī)
  2. onPause方法中釋放相機(jī)

初始化相機(jī)非常簡(jiǎn)單:

/**
 * 初始化相機(jī)
 *
 * @return camera
 */
private Camera getCamera() {
    Camera camera;
    try {
        camera = Camera.open();
    } catch (Exception e) {
        camera = null;
    }
    return camera;
}

釋放相機(jī)也非常簡(jiǎn)單:

/**
 * 釋放相機(jī)資源
 */
private void releaseCamera() {
    if (mCamera != null) {
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
}

那么下面我們?cè)賮?lái)看如何把相機(jī)圖像設(shè)置到SurfaceView中進(jìn)行預(yù)覽:

/**
 * 在SurfaceView中預(yù)覽相機(jī)內(nèi)容
 *
 * @param camera camera
 * @param holder SurfaceHolder
 */
private void setStartPreview(Camera camera, SurfaceHolder holder) {
    try {
        camera.setPreviewDisplay(holder);
        camera.setDisplayOrientation(90);
        camera.startPreview();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

尼瑪卿叽,是不是也非常簡(jiǎn)單,camera的一個(gè)方法已經(jīng)幫我們自動(dòng)關(guān)聯(lián)了SurfaceView恳守。

PS 這里需要注意下這個(gè)方法camera.setDisplayOrientation(90)考婴,通過(guò)這個(gè)方法,我們可以調(diào)整攝像頭的角度催烘,不然默認(rèn)是橫屏蕉扮,圖像會(huì)顯示的比較奇怪。當(dāng)然颗圣,即使你設(shè)置的90喳钟,圖像也有可能比較奇怪,這是因?yàn)槟銢](méi)有對(duì)圖像進(jìn)行正確的縮放在岂,比例不對(duì)奔则。

通過(guò)上面的設(shè)置,我們已經(jīng)可以正常預(yù)覽攝像頭的圖像內(nèi)容了蔽午,下面我們就可以拍照了易茬。

唉,拍照真的也非常簡(jiǎn)單及老,就一句話:

mCamera.takePicture(null, null, mPictureCallback);

當(dāng)然抽莱,為了配合拍照,我們需要做一些設(shè)定骄恶,設(shè)置拍照的參數(shù)食铐,并且給拍照之后的動(dòng)作設(shè)定一個(gè)回調(diào):

參數(shù):

Camera.Parameters params = mCamera.getParameters();
params.setPictureFormat(ImageFormat.JPEG);
params.setPreviewSize(800, 400);
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(params);
// 使用自動(dòng)對(duì)焦功能
mCamera.autoFocus(new Camera.AutoFocusCallback() {
    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        mCamera.takePicture(null, null, mPictureCallback);
    }
});

回調(diào):

/**
 * Camera回調(diào),通過(guò)data[]保持圖片數(shù)據(jù)信息
 */
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        File pictureFile = getOutputMediaFile();
        if (pictureFile == null) {
            return;
        }
        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
            Intent intent = new Intent(CustomCamera.this, CameraResult.class);
            intent.putExtra("picPath", pictureFile.getAbsolutePath());
            startActivity(intent);
            CustomCamera.this.finish();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
};

在回調(diào)中僧鲁,我們將拍攝好的圖片地址傳遞給用于展示的ImageView虐呻。這樣就完成了相機(jī)的拍攝與圖片的展示。

處理圖像變形

由于我們自己在布局中創(chuàng)建了一個(gè)SurfaceView寞秃,而且我們之間讓他match_parent了斟叼,所以,圖像在preview的時(shí)候春寿,肯定是會(huì)有拉伸的朗涩。那么如何處理這些變形呢?

我們可以通過(guò)改變SurfaceView大小的方式來(lái)實(shí)現(xiàn)绑改,在Android API Demo中谢床,Google也給我們提供了這樣一個(gè)實(shí)例:

路徑如下:
android-22/legacy/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java

Google就是通過(guò)設(shè)置新的大小來(lái)適應(yīng)預(yù)覽區(qū)域大小的方式來(lái)解決變形問(wèn)題的兄一,所以說(shuō),內(nèi)事不懂看源碼萤悴,外事不懂看Demo

自定義取景畫面

聽上去非常高大上皆的,其實(shí)覆履,真的非常簡(jiǎn)單,你只需要用一個(gè)FrameLayout把用來(lái)Preview的SurfaceView包起來(lái)就OK了费薄,下面你想加什么硝全,就直接在FrameLayout中加吧,like this:

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@id/ll">

    <SurfaceView
        android:id="@+id/sv_camera"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="拍照區(qū)域"/>

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="center"
        android:src="@drawable/demo"/>
</FrameLayout>

不光了ImageView楞抡,ViewPager也可以伟众,這樣甚至可以做一個(gè)可切換的水印相機(jī)了。是不是非常簡(jiǎn)單召廷,而且加入的一切都是可操作的凳厢,加動(dòng)效、顏色竞慢,分分鐘搞定先紫。

這里寫圖片描述

以上。

起步之后筹煮,我們要開始跑了遮精。

代碼下載,請(qǐng)移步全球最大同性程序猿交友社區(qū):

https://github.com/xuyisheng/CameraGuide

后續(xù)篇章也會(huì)在此repo中更新败潦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末本冲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子劫扒,更是在濱河造成了極大的恐慌檬洞,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沟饥,死亡現(xiàn)場(chǎng)離奇詭異疮胖,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)闷板,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門澎灸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人遮晚,你說(shuō)我怎么就攤上這事性昭。” “怎么了县遣?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵糜颠,是天一觀的道長(zhǎng)汹族。 經(jīng)常有香客問(wèn)我,道長(zhǎng)其兴,這世上最難降的妖魔是什么顶瞒? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮元旬,結(jié)果婚禮上榴徐,老公的妹妹穿的比我還像新娘。我一直安慰自己匀归,他們只是感情好坑资,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著穆端,像睡著了一般袱贮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上体啰,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天攒巍,我揣著相機(jī)與錄音,去河邊找鬼荒勇。 笑死窑业,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枕屉。 我是一名探鬼主播常柄,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼搀擂!你這毒婦竟也來(lái)了西潘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤哨颂,失蹤者是張志新(化名)和其女友劉穎喷市,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體威恼,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡品姓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了箫措。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腹备。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖斤蔓,靈堂內(nèi)的尸體忽然破棺而出植酥,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布友驮,位于F島的核電站漂羊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏卸留。R本人自食惡果不足惜走越,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望耻瑟。 院中可真熱鬧旨指,春花似錦、人聲如沸匆赃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)算柳。三九已至,卻和暖如春姓言,著一層夾襖步出監(jiān)牢的瞬間瞬项,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工何荚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留囱淋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓餐塘,卻偏偏與公主長(zhǎng)得像妥衣,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子戒傻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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