zoukankan      html  css  js  c++  java
  • android——创建camera应用(译)

       只是选择相机部分来翻译。下面是主要内容

      有些开发者可能需要Camera的接口,来定制自己程序的外观和特殊功能。创建自定义的Camera界面比使用using an Intent需要编写更多的代码,但是它能提供更好的体验给用户。

    创建自定义camera界面的一般步骤,可以参考一下步骤:

    1. 检测和连接相机—检测camera是否存在和请求连接
    2. 创建预览类—创建Preview,它继承SurfaceView和实现了SurfaceHolder接口。这个类可以预览相机中动态的画面。
    3. 构造预览的布局一旦你拥有了Preview类,就需要创建一个View布局。布局中放入Preview和你想要的其他UI。
    4. 给拍照设置监听器—连接监听器去启动拍照,来响应用户的动作,例如按下按钮。
    5. 拍照和保存文件—编写代码实现拍照和保存输出。
    6. 释放相机—使用camera后,程序必须合理的释放它,给其他程序使用。

      相机硬件上一个共享的资源,必须被安全的管理,所以当使用相机时,你的程序不能和其他程序冲突。下面部分讲述怎样检测相机硬件,怎样连接相机,怎样拍照和当不使用时怎样释放相机。

      注意:当应用程序不使用相机时,记得通过调用Camera.release()来释放Camera对象。如果没有合理释放camera,后面全部对camera的连接都会失败,将导致你的或其他程序被关闭。

    检测相机硬件

       如果你的程序没有在manifest声明需要相机,你应该在代码运行时检测相机是否可用。使用PackageManage.hasSystemFeature()方法来执行检测,下面是例子:

     1 /** Check if this device has a camera */
     2 private boolean checkCameraHardware(Context context) {
     3     if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
     4         // this device has a camera
     5         return true;
     6     } else {
     7         // no camera on this device
     8         return false;
     9     }
    10 }

       android设备可以用多个相机,例如后置相机用来拍照,前置相机用来摄像。Aandroid 2.3(API Level 9)和以后版本,你可以使用Camera.getNumberOfCameras()方法来检测相机的数目。

    连接相机

      如果你已经确定程序运行的设备上有相机,你必须请求连接来获取一个Camera实例(除非你使用intent来连接相机)。

      使用Camera.opern()连接主要的相机,要确保捕获异常,就像下面的代码:

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

      注意:当使用Camera.open()时,总是要检查异常。如果不检查,当相机正在被使用或者不存在时,你的程序将会被系统关闭。

      运行Android 2.3(API Level 9)或以上版本的设备,你可以使用Camera.open(int)连接特定的相机。上面的代码将会连接设备的第一个后置相机,如果存在多个相机。

    检查相机特征

      一旦你获取到相机的连接,你可以使用Camera.getParameters()方法获取有关它的功能的更多信息,检查返回的Camera.Parameters对象来知道相机支持的功能。

      当使用API Level 9或以上的版本,使用Camera.getCameraInfo()确定相机是前置还是后置,图片的方向。

    创建预览类

      为了用户能有效地拍照,他们必须能够看到设备相机看到的。一个相机预览类是一个SurfaceView,它能展示来自相机的动态的图像数据,所以用户可以能拍摄到照片。

      下面的例子展示了如何创建一个基本的相机预览类,它被包含在一个View布局中。这个类实现了SurfaceHolder.Callback接口,为了能捕捉到创建和销毁这个类时的回调事件。

     1 /** A basic Camera preview class */
     2 public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
     3     private SurfaceHolder mHolder;
     4     private Camera mCamera;
     5 
     6     public CameraPreview(Context context, Camera camera) {
     7         super(context);
     8         mCamera = camera;
     9 
    10         // Install a SurfaceHolder.Callback so we get notified when the
    11         // underlying surface is created and destroyed.
    12         mHolder = getHolder();
    13         mHolder.addCallback(this);
    14         // deprecated setting, but required on Android versions prior to 3.0
    15         mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    16     }
    17 
    18     public void surfaceCreated(SurfaceHolder holder) {
    19         // The Surface has been created, now tell the camera where to draw the preview.
    20         try {
    21             mCamera.setPreviewDisplay(holder);
    22             mCamera.startPreview();
    23         } catch (IOException e) {
    24             Log.d(TAG, "Error setting camera preview: " + e.getMessage());
    25         }
    26     }
    27 
    28     public void surfaceDestroyed(SurfaceHolder holder) {
    29         // empty. Take care of releasing the Camera preview in your activity.
    30     }
    31 
    32     public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    33         // If your preview can change or rotate, take care of those events here.
    34         // Make sure to stop the preview before resizing or reformatting it.
    35 
    36         if (mHolder.getSurface() == null){
    37           // preview surface does not exist
    38           return;
    39         }
    40 
    41         // stop preview before making changes
    42         try {
    43             mCamera.stopPreview();
    44         } catch (Exception e){
    45           // ignore: tried to stop a non-existent preview
    46         }
    47 
    48         // set preview size and make any resize, rotate or
    49         // reformatting changes here
    50 
    51         // start preview with new settings
    52         try {
    53             mCamera.setPreviewDisplay(mHolder);
    54             mCamera.startPreview();
    55 
    56         } catch (Exception e){
    57             Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    58         }
    59     }
    60 }

       如果你想为相机预览类设定一个特定的大小,在上面的surfaceChaned()方法中设定。当设定大小时,你必须从getSupportedPreviewSizes()获取数值。不要随意设定一个值。

    放置preview入一个布局中

      相机预览类,如同上面展示的,它必须被放置进Activity的布局中,这样其他UI可以控制拍照。下面一节展示了如何为这个preview创建一个基本的布局和Activity。

      下面的布局代码提供了一个非常基本的view来展示相机预览类。在这个例子中,FrameLayout元素就是相机预览类的容器。使用这个布局类型,可以把另外的图片信息或者控制覆盖在动态相机预览图像上。

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:orientation="horizontal"
     4     android:layout_width="fill_parent"
     5     android:layout_height="fill_parent"
     6     >
     7   <FrameLayout
     8     android:id="@+id/camera_preview"
     9     android:layout_width="fill_parent"
    10     android:layout_height="fill_parent"
    11     android:layout_weight="1"
    12     />
    13 
    14   <Button
    15     android:id="@+id/button_capture"
    16     android:text="Capture"
    17     android:layout_width="wrap_content"
    18     android:layout_height="wrap_content"
    19     android:layout_gravity="center"
    20     />
    21 </LinearLayout>

      在大多数设备中,相机预览默认的方向是横向的。这个例子设定了水平布局,下面的代码中修改了应用程序的方向为横向。为了使相机预览类渲染简单,你应该应该把照着下面在manifest中把应用程序预览所在的ctivity为横向。

     1 <activity android:name=".CameraActivity"
     2           android:label="@string/app_name"
     3 
     4           android:screenOrientation="landscape">
     5           <!-- configure this activity to use landscape orientation -->
     6 
     7           <intent-filter>
     8         <action android:name="android.intent.action.MAIN" />
     9         <category android:name="android.intent.category.LAUNCHER" />
    10     </intent-filter>
    11 </activity>

      注意:相机预览不一定要是横向的。从android 2.2(API 8)开始,你可以使用setDisplayOrientation()方法去旋转预览的图像。当用户改变了手机方向,如果要调整预览的方向,可以在预览类的surfaceChanged()方法中,先使用Camer.stopPreview()停止预览,然后改变方向,最后再使用Camera.startPreview()打开预览.

      在你相机视图所在的activity中,下面的例子中,添加了预览类到FrameLayout元素中。这个activity必须确保当它被暂停(paused)或者关闭时,要释放相机。下面的例子,展示了如何向activity添加预览类(在创建预览类一节提到的)。

     1 public class CameraActivity extends Activity {
     2 
     3     private Camera mCamera;
     4     private CameraPreview mPreview;
     5 
     6     @Override
     7     public void onCreate(Bundle savedInstanceState) {
     8         super.onCreate(savedInstanceState);
     9         setContentView(R.layout.main);
    10 
    11         // Create an instance of Camera
    12         mCamera = getCameraInstance();
    13 
    14         // Create our Preview view and set it as the content of our activity.
    15         mPreview = new CameraPreview(this, mCamera);
    16         FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    17         preview.addView(mPreview);
    18     }
    19 }

     注意:getCameraInstance()方法,是在连接相机一节的。

    拍照

      一旦你构建了预览类(preview)和一个展示它的视图布局,你将要在你的应用程序中开始编写拍照了。你必须设置监听器给你的UI去响应用户的拍照动作。
    为了获取照片,使用Camera.takePicture()方法。这个方法需要三个参数,它们从camera中获取数据。为了获取JPEG格式的数据,你必须实现一个Camera.PictureCallback接口来获取图像数据,并且写入一个文件中。

      下面的代码展示了一个基本的实现,如何保存来自camera的图像。

     1 private PictureCallback mPicture = new PictureCallback() {
     2 
     3     @Override
     4     public void onPictureTaken(byte[] data, Camera camera) {
     5 
     6         File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
     7         if (pictureFile == null){
     8             Log.d(TAG, "Error creating media file, check storage permissions: " +
     9                 e.getMessage());
    10             return;
    11         }
    12 
    13         try {
    14             FileOutputStream fos = new FileOutputStream(pictureFile);
    15             fos.write(data);
    16             fos.close();
    17         } catch (FileNotFoundException e) {
    18             Log.d(TAG, "File not found: " + e.getMessage());
    19         } catch (IOException e) {
    20             Log.d(TAG, "Error accessing file: " + e.getMessage());
    21         }
    22     }
    23 };

       

      通过Camera.takePicture()触发拍照。下面的例子展示了如何通过button的View.OnClickListener调用此方法。

     1 // Add a listener to the Capture button
     2 Button captureButton = (Button) findViewById(id.button_capture);
     3 captureButton.setOnClickListener(
     4     new View.OnClickListener() {
     5         @Override
     6         public void onClick(View v) {
     7             // get an image from the camera
     8             mCamera.takePicture(null, null, mPicture);
     9         }
    10     }
    11 );

      提示:mPicture成员变量来自上面的例子。
      注意:记得当你的应用程序停止使用Camera对象时通过Camera.release()释放它。如何释放camera的细节,情况释放相机一节。

    释放相机

      相机作用一种资源,被设备中的多个应用程序共享。你的应用程序在获取Camera实例后可以使用它,当你的程序停止使用它时,或者一旦你的程序暂停(Activity.onPause()),你必须特别注意去释放它。如果你的程序没有适当的释放它,所有后续对它的连接请求,都会导致你的程序或者其他程序都会被关闭。

      使用Camera.release()方法释放一个Camera对象的实例,下面是例子。

     1 public class CameraActivity extends Activity {
     2     private Camera mCamera;
     3     private SurfaceView mPreview;
     4 
     5     ...
     6 
     7     @Override
     8     protected void onPause() {
     9         super.onPause();
    10         releaseCamera();              // release the camera immediately on pause event
    11     }
    12 
    13     private void releaseCamera(){
    14         if (mCamera != null){
    15             mCamera.release();        // release the camera for other applications
    16             mCamera = null;
    17         }
    18     }
    19 }

     参考:http://developer.android.com/guide/topics/media/camera.html

  • 相关阅读:
    SpringMVC运行原理浅析
    JavaEE就业学习路线(给初学者以及自学者一个学习方向)
    Java 教程
    EL表达式
    Java 教程 (Java 对象和类)
    Java 教程(开发环境配置+基础语法)
    简介几种负载均衡原理
    Linux常用命令大全
    Java 数据结构
    Java 包(package)
  • 原文地址:https://www.cnblogs.com/dann/p/3315721.html
Copyright © 2011-2022 走看看