Android官方文档翻译-相机Camera

Camera 官方文档翻译

Manifest 声明

在使用 Camera API 开发应用前,你需要确认 Manifest 已经包含允许使用相机硬件和其他相关特性的声明。

  • 相机权限 -你的应用必须申请使用相机的权限
<uses-permission android:name="android.permission.CAMERA" />
  • 相机特性 -你的应用也必须声明相机特性的使用,例如:
<uses-feature android:name="android.hardware.camera" />

(译者注: <uses-feature> 的具体使用方法不是本文关心的重点,需要读者自己查阅)

  • 存储权限 -如果你的应用需要在设备的 externel storage 中保存图片或者视频,你也需要声明以下权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • 音频采集权限 -录制视频时需要采集音频时,需要声明音频采集权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
···

- 位置权限 -如果你需要用GPS位置信息标志图片,你需要获取 ACCESS_FINE_LOCATION 权限。如果你的应用运行在 Android 5.0 以上,你还需要声明应用使用了设备 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" />

构建一个相机应用

以下引导使用 Camera API.
创建一个自定义的相机接口主要分为几步:

  • 检测并获取相机 -检测相机是否存在并获取

  • 创建一个预览类 -创建一个继承自 SurfaceView 的类并实现 SurfaceHolder 接口。这个类展示相机的实时图像。

  • 构建一个预览界面 -创建完相机预览累以后,创建一个布局以展示预览图和需要的 UI 界面。

  • 创建采集的监听 -连接控制开始采集图片和视频的接口以响应用户的操作,比如按下按钮。

  • 采集并保存文件 -采集图片或视频并保存输出。

  • 释放相机 -使用完相机以后,你的应用必须正确的释放相机以供其他应用使用。

检测相机硬件

如果你的应用没有使用 manifest 的 Camera 的 <uses-feature> 声明,你应该检查运行时相机是否可用。使用 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 设备可以有多个摄像头,比如一个用于拍照的后置摄像头和视频电话的前置摄像头。 Android 2.3 及以上,你可以使用 Camera.getNumberOfCameras() 方法检查设备中可用相机数。

获取相机

如果你确定设备有相机硬件,你必须通过得到相机的实例来获取(除非你使用 Intent 获取相机)。
使用 Camera.open() 方法获取基础的相机,示例代码如下:

/** 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) 获取特定的相机。以上的示例代码将在有多个相机的设备上获取第一个、后置摄像头。

检查相机特性

得到相机实例以后,你可以使用 Camera.getParameters() 方法获取关于相机的更多信息并检查返回而来的 Camera。Parameters 对象。在 API 9 及以上,使用 Camera.getCameraInfo() 检查相机在设备的前/后,及图像的方向。

创建一个预览类

以下的实例代码展示了如何创建一个基本的相机预览类。

/** 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());
        }
    }
}

如果想要设置相机预览的大小,在 surfaceChanged() 方法中设置。设置预览大小时,你必须使用 getSupportedPreviewSizes() 中的值。不能随便设置其他值。

在布局中写入预览界面

以下布局代码提供了一个用来展示相机预览界面的视图。在示例中, FrameLayout 元素用来作为相机预览类的容器。

<?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>

在大多数设备上,相机的默认方向为横屏。这个示例中制定了一个水平布局切一下的代码制定了应用的方向为水平。

<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>

注意:相机预览不一定必须水平布局。从 API 8 开始,你可以使用 setDisplayOrientation() 方法设置预览图片的旋转角度。当用于改变手机方向时,你可以在预览类的 surfaceChanged() 方法中改变预览方向,首先用 Camera.stopPreview() 方法停止预览并改变方向,然后使用 Camera.startPreview() 方法开始预览。

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() 方法可以拍摄照片。这个方法传入三个从相机接收的三个参数。必须实现 Camera。PictureCallback 接口接收 JPEG 格式的数据并写入文件。

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

推荐阅读更多精彩内容

  • 上一篇介绍了如何使用系统相机简单、快速的进行拍照,本篇将介绍如何使用框架提供的API直接控制摄像机硬件。 你还在为...
    Xiao_Mai阅读 7,161评论 4 18
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,825评论 25 707
  • 以下内容翻译来源,Google官方开发文档:https://developer.android.google.cn...
    肱二头肌的孤单阅读 5,212评论 5 47
  • 我们从出生那一刻,就开始被束缚。结束了子宫里自由自在的日子,来到了这个有光,有空气,有温差,有各种物品和规则的世界...
    暖暖如风阅读 609评论 0 0
  • 室友是什么呢?室友就是那个你来陌生城市跟你第一个跟你相处的人,那个你在外面玩耍回到寝室,第一眼看到的人。那个缘分...
    黄悠悠阅读 372评论 0 3