控制攝像頭拍照

10.3 控制攝像頭拍照
現在的智能手機和平板電腦一般都會提供攝像頭拍照功能。在Android中提供了專門用於處理攝像頭相關事件的類,即android.hardware包中的Camera類。Camera類沒有構造方法,可以通過其提供的open()方法打開攝像頭。打開攝像頭後,可以通過Camera.Parameters類處理攝像頭的拍照參數。拍照參數設置完成後,可以調用startPreview()方法預覽拍照畫面,也可以調用takePicture()方法進行拍照。結束程序時,可以調用Camera類的stopPreview()方法結束預覽,並調用release()方法釋放攝像頭資源。Camera類常用的方法如表10.9所示。
表10.9 Camera類常用的方法
控制攝像頭拍照
下面通過一個實例來說明控制攝像頭拍照的具體過程。

實例 實現控制攝像頭拍照功能 實例位置:

在Android Studio中創建Module,名稱爲“Camera”,在該Module中實現本實例,具體步驟如下。
(1)修改佈局文件activity_main.xml,首先將默認添加的佈局管理器修改爲幀佈局管理器,然後將TextView組件刪除,再添加一個SurfaceView組件(用於顯示攝像頭預覽畫面),最後添加一個預覽按鈕和一個拍照按鈕。具體代碼請參見光盤。
(2)打開MainActivity類,該類繼承Activity,然後在該類中,定義所需的成員變量,關鍵代碼如下:

01  private Camera camera;                                  //定義相機對象
02  private boolean isPreview = false;                     //定義非預覽狀態

(3)在MainActivity類的onCreate()方法中,首先設置全屏顯示,然後判斷手機是否安裝SD卡,關鍵代碼如下:

01  //設置全屏顯示
02  getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
03          WindowManager.LayoutParams.FLAG_FULLSCREEN);
04  if (!Environment.getExternalStorageState().equals(   //判斷手機是否安裝SD卡
05          Environment.MEDIA_MOUNTED)) {
06      Toast.makeText(this, "請安裝SD卡!", Toast.LENGTH_SHORT).show(); // 提示安裝SD卡
07  }

(4)獲取SurfaceView組件與SurfaceHolder對象,用於顯示攝像頭預覽,關鍵代碼如下:

01  //獲取SurfaceView組件,用於顯示攝像頭預覽
02  SurfaceView sv = (SurfaceView) findViewById(R.id.surfaceView);  
03  final SurfaceHolder sh = sv.getHolder();              //獲取SurfaceHolder對象
04  //設置該SurfaceHolder自己不維護緩衝
05  sh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);   
06  ImageButton preview = (ImageButton) findViewById(R.id.preview);        //獲取“預覽”按鈕
07  ImageButton takePicture = (ImageButton) findViewById(R.id.takephoto);  //獲取“拍照”按鈕

(5)爲預覽按鈕添加單擊事件監聽器,實現攝像頭的預覽功能,關鍵代碼如下:

01  preview.setOnClickListener(new View.OnClickListener() {         //實現攝像頭預覽功能
02      @Override
03      public void onClick(View v) {
04          // 如果攝像頭爲非預覽模式,則打開相機
05          if (!isPreview) {
06              camera = Camera.open();                /打開相機
07              isPreview = true;                       //設置爲預覽狀態
08          }
09          try {
10              camera.setPreviewDisplay(sh);           //設置用於顯示預覽的SurfaceView
11              Camera.Parameters parameters = camera.getParameters();  //獲取相機參數
12              parameters.setPictureFormat(PixelFormat.JPEG);    //指定圖片爲JPEG圖片
13              parameters.set("jpeg-quality", 80);   //設置圖片的質量
14              camera.setParameters(parameters);      //重新設置相機參數
15              camera.startPreview();                  //開始預覽
16              camera.autoFocus(null);                 //設置自動對焦
17          } catch (IOException e) {                   //輸出異常信息
18              e.printStackTrace();
19          }
20      }
21  });

(6)在MainActivity中,創建實現重新預覽的方法resetCamera(),在該方法中,當isPreview變量的值爲真時,調用攝像頭的startPreview()方法開啓預覽,具體代碼如下:

01  private void resetCamera() {        //創建resetCamera()方法,實現重新預覽功能
02      if (!isPreview) {                //如果爲非預覽模式
03          camera.startPreview();       //開啓預覽
04          isPreview = true;
05      }
06  }

(8)實現拍照的回調接口,在重寫的onPictureTaken()方法中,首先根據拍照所得的數據創建位圖,然後保存所拍攝的圖片,再把保存的圖片文件插入到系統圖庫,最後通知圖庫更新,具體代碼如下:

01  
02  //實現將照片保存到系統圖庫中
03  final Camera.PictureCallback jpeg = new Camera.PictureCallback() {  //照片回調函數
04      @Override
05      public void onPictureTaken(byte[] data, Camera camera) {
06          // 根據拍照所得的數據創建位圖
07          final Bitmap bm = BitmapFactory.decodeByteArray(data, 0,
08                  data.length);
09          camera.stopPreview();                                          //停止預覽
10          isPreview = false;                                             //設置爲非預覽狀態
11          //獲取sd卡根目錄
12          File appDir = new File(Environment.getExternalStorageDirectory(), "/DCIM/Camera/");
13          if (!appDir.exists()) {                   //如果該目錄不存在
14              appDir.mkdir();                        //創建該目錄
15          }
16          //將獲取的當前系統時間設置爲照片名稱
17          String fileName = System.currentTimeMillis() + ".jpg";
18          File file = new File(appDir, fileName);     //創建文件對象
19          try {  //保存拍到的圖片
20              FileOutputStream fos = new FileOutputStream(file); //創建一個文件輸出流對象
21              //將圖片內容壓縮爲JPEG格式輸出到輸出流對象中
22              bm.compress(Bitmap.CompressFormat.JPEG, 100, fos);
23              //將緩衝區中的數據全部寫出到輸出流中
24              fos.flush();
25              fos.close();                            //關閉文件輸出流對象
26          } catch (FileNotFoundException e) {
27              e.printStackTrace();
28          } catch (IOException e) {
29              e.printStackTrace();
30          }
31          //將照片插入到系統圖庫
32          try {
33              MediaStore.Images.Media.insertImage(MainActivity.this.getContentResolver(),
34                      file.getAbsolutePath(), fileName, null);
35          } catch (FileNotFoundException e) {
36              e.printStackTrace();
37          }
38          //最後通知圖庫更新
39          Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
40          Uri uri = Uri.fromFile(file);
41          intent.setData(uri);
42          MainActivity.this.sendBroadcast(intent);   //這個廣播的目的就是更新圖庫
43          Toast.makeText(MainActivity.this, "照片保存至:" + file, Toast.LENGTH_LONG).show();
44          resetCamera();                                //調用重新預覽resetCamera()方法
45      }
46  };

(9)在onCreate()方法中,爲拍照按鈕添加單擊事件監聽器,實現攝像頭的拍照功能,關鍵代碼如下:

01  takePicture.setOnClickListener(new View.OnClickListener() {
02      @Override
03      public void onClick(View v) {
04          if (camera != null) {                          //相機不爲空
05              camera.takePicture(null, null, jpeg);    //進行拍照
06          }
07      }
08  });

(10)重寫Activity的onPause()方法,用於當暫停Activity時,停止預覽並釋放攝像頭資源,具體代碼如下:

01  @Override
02  protected void onPause() {   
03      if (camera != null) {                         //如果攝像頭不爲空
04          camera.stopPreview();                     //停止預覽
05          camera.release();                          //釋放資源
06      }
07      super.onPause();
08  }

(11)由於本程序需要訪問SD卡和控制攝像頭,所以需要在AndroidManifest.xml文件中賦予程序訪問SD卡和控制攝像頭的權限,關鍵代碼如下:

01  <!-- 授予程序可以向SD卡中保存文件的權限 -->
02  <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
03  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
04  <!-- 授予程序使用攝像頭的權限 -->
05  <uses-permission android:name="android.permission.CAMERA"/>
06  <uses-feature android:name="android.hardware.camera.autofocus"/>
07  <uses-feature android:name="android.hardware.camera"/>

(12)在AndroidManifest.xml文件的<activity>標記中添加screenOrientation屬性,設置其橫屏顯示,關鍵代碼如下:

android:screenOrientation="landscape"

(13)在工具欄中找到 下拉列表框,選擇要運行的應用(這裏爲Camera),再單擊右側的 按鈕,在顯示的界面中,單擊預覽按鈕,啓動攝像頭,單擊拍照按鈕進行拍照,如圖10.9所示。
控制攝像頭拍照
圖10.9 預覽與拍照

說明:本實例需要攝像頭硬件的支持,這裏我們使用真機測試。讀者需要在手機中手動開啓攝像頭權限與sd卡讀寫權限。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章