Android官方文檔翻譯-相機(jī)Camera

Camera 官方文檔翻譯

Manifest 聲明

在使用 Camera API 開發(fā)應(yīng)用前,你需要確認(rèn) Manifest 已經(jīng)包含允許使用相機(jī)硬件和其他相關(guān)特性的聲明。

  • 相機(jī)權(quán)限 -你的應(yīng)用必須申請使用相機(jī)的權(quán)限
<uses-permission android:name="android.permission.CAMERA" />
  • 相機(jī)特性 -你的應(yīng)用也必須聲明相機(jī)特性的使用,例如:
<uses-feature android:name="android.hardware.camera" />

(譯者注: <uses-feature> 的具體使用方法不是本文關(guān)心的重點(diǎn),需要讀者自己查閱)

  • 存儲(chǔ)權(quán)限 -如果你的應(yīng)用需要在設(shè)備的 externel storage 中保存圖片或者視頻,你也需要聲明以下權(quán)限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • 音頻采集權(quán)限 -錄制視頻時(shí)需要采集音頻時(shí),需要聲明音頻采集權(quán)限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
···

- 位置權(quán)限 -如果你需要用GPS位置信息標(biāo)志圖片,你需要獲取 ACCESS_FINE_LOCATION 權(quán)限。如果你的應(yīng)用運(yùn)行在 Android 5.0 以上,你還需要聲明應(yīng)用使用了設(shè)備 GPS:
```java
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
...
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
<uses-feature android:name="android.hardware.location.gps" />

構(gòu)建一個(gè)相機(jī)應(yīng)用

以下引導(dǎo)使用 Camera API.
創(chuàng)建一個(gè)自定義的相機(jī)接口主要分為幾步:

  • 檢測并獲取相機(jī) -檢測相機(jī)是否存在并獲取

  • 創(chuàng)建一個(gè)預(yù)覽類 -創(chuàng)建一個(gè)繼承自 SurfaceView 的類并實(shí)現(xiàn) SurfaceHolder 接口。這個(gè)類展示相機(jī)的實(shí)時(shí)圖像。

  • 構(gòu)建一個(gè)預(yù)覽界面 -創(chuàng)建完相機(jī)預(yù)覽累以后,創(chuàng)建一個(gè)布局以展示預(yù)覽圖和需要的 UI 界面。

  • 創(chuàng)建采集的監(jiān)聽 -連接控制開始采集圖片和視頻的接口以響應(yīng)用戶的操作,比如按下按鈕。

  • 采集并保存文件 -采集圖片或視頻并保存輸出。

  • 釋放相機(jī) -使用完相機(jī)以后,你的應(yīng)用必須正確的釋放相機(jī)以供其他應(yīng)用使用。

檢測相機(jī)硬件

如果你的應(yīng)用沒有使用 manifest 的 Camera 的 <uses-feature> 聲明,你應(yīng)該檢查運(yùn)行時(shí)相機(jī)是否可用。使用 PackageManager.hasSystemFeature() 方法檢查,示例代碼如下:

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}

Android 設(shè)備可以有多個(gè)攝像頭,比如一個(gè)用于拍照的后置攝像頭和視頻電話的前置攝像頭。 Android 2.3 及以上,你可以使用 Camera.getNumberOfCameras() 方法檢查設(shè)備中可用相機(jī)數(shù)。

獲取相機(jī)

如果你確定設(shè)備有相機(jī)硬件,你必須通過得到相機(jī)的實(shí)例來獲取(除非你使用 Intent 獲取相機(jī))。
使用 Camera.open() 方法獲取基礎(chǔ)的相機(jī),示例代碼如下:

/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

在 Android 2.3 以上,你可以使用 Camera。open(int) 獲取特定的相機(jī)。以上的示例代碼將在有多個(gè)相機(jī)的設(shè)備上獲取第一個(gè)、后置攝像頭。

檢查相機(jī)特性

得到相機(jī)實(shí)例以后,你可以使用 Camera.getParameters() 方法獲取關(guān)于相機(jī)的更多信息并檢查返回而來的 Camera。Parameters 對象。在 API 9 及以上,使用 Camera.getCameraInfo() 檢查相機(jī)在設(shè)備的前/后,及圖像的方向。

創(chuàng)建一個(gè)預(yù)覽類

以下的實(shí)例代碼展示了如何創(chuàng)建一個(gè)基本的相機(jī)預(yù)覽類。

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

如果想要設(shè)置相機(jī)預(yù)覽的大小,在 surfaceChanged() 方法中設(shè)置。設(shè)置預(yù)覽大小時(shí),你必須使用 getSupportedPreviewSizes() 中的值。不能隨便設(shè)置其他值。

在布局中寫入預(yù)覽界面

以下布局代碼提供了一個(gè)用來展示相機(jī)預(yù)覽界面的視圖。在示例中, FrameLayout 元素用來作為相機(jī)預(yù)覽類的容器。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
  <FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    />

  <Button
    android:id="@+id/button_capture"
    android:text="Capture"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    />
</LinearLayout>

在大多數(shù)設(shè)備上,相機(jī)的默認(rèn)方向?yàn)闄M屏。這個(gè)示例中制定了一個(gè)水平布局切一下的代碼制定了應(yīng)用的方向?yàn)樗健?/p>

<activity android:name=".CameraActivity"
          android:label="@string/app_name"

          android:screenOrientation="landscape">
          <!-- configure this activity to use landscape orientation -->

          <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

注意:相機(jī)預(yù)覽不一定必須水平布局。從 API 8 開始,你可以使用 setDisplayOrientation() 方法設(shè)置預(yù)覽圖片的旋轉(zhuǎn)角度。當(dāng)用于改變手機(jī)方向時(shí),你可以在預(yù)覽類的 surfaceChanged() 方法中改變預(yù)覽方向,首先用 Camera.stopPreview() 方法停止預(yù)覽并改變方向,然后使用 Camera.startPreview() 方法開始預(yù)覽。

public class CameraActivity extends Activity {

    private Camera mCamera;
    private CameraPreview mPreview;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Create an instance of Camera
        mCamera = getCameraInstance();

        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(this, mCamera);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(mPreview);
    }

拍照

使用 Camera.takePicture() 方法可以拍攝照片。這個(gè)方法傳入三個(gè)從相機(jī)接收的三個(gè)參數(shù)。必須實(shí)現(xiàn) Camera。PictureCallback 接口接收 JPEG 格式的數(shù)據(jù)并寫入文件。

private PictureCallback mPicture = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d(TAG, "Error creating media file, check storage permissions: " +
                e.getMessage());
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }
};
···

```java
// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
captureButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // get an image from the camera
            mCamera.takePicture(null, null, mPicture);
        }
    }
);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 上一篇介紹了如何使用系統(tǒng)相機(jī)簡單、快速的進(jìn)行拍照,本篇將介紹如何使用框架提供的API直接控制攝像機(jī)硬件。 你還在為...
    Xiao_Mai閱讀 7,226評論 4 18
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,841評論 25 708
  • 以下內(nèi)容翻譯來源,Google官方開發(fā)文檔:https://developer.android.google.cn...
    肱二頭肌的孤單閱讀 5,269評論 5 47
  • 我們從出生那一刻,就開始被束縛。結(jié)束了子宮里自由自在的日子,來到了這個(gè)有光,有空氣,有溫差,有各種物品和規(guī)則的世界...
    暖暖如風(fēng)閱讀 627評論 0 0
  • 室友是什么呢?室友就是那個(gè)你來陌生城市跟你第一個(gè)跟你相處的人,那個(gè)你在外面玩耍回到寢室,第一眼看到的人。那個(gè)緣分...
    黃悠悠閱讀 379評論 0 3