Androidプログラマへの道 〜 Moonlight 明日香 〜 - 写真を撮影する
カメラを制御して写真の撮影を行うには, Camera.PictureCallbackインタフェースを利用する.

写真の撮影

  • src/Camera01.java
package com.moonlight_aska.android.camera01;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

public class Camera01 extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 画面をフルスクリーンに設定
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    // カメラ用ビューの設定
    setContentView(new CameraView(this));
  }
}
  • src/CameraView.java
    • PictureCallbackインターフェースのonPictureTakenメソッドをオーバーライドする.
      • 撮影したデータ(data)をsdcardに保存する.
    • View#onTouchEventメソッドをオーバーライドする.
      • Camera#takePictureメソッドで, 写真を撮影する. 引数には, JPEG画像データを処理するコールバック関数を渡す.
shutterシャッターを押した瞬間のコールバック関数 or null
rawRAW画像データを処理するためのコールバック関数 or null
jpegJPEG画像データを処理するためのコールバック関数 or null
package com.moonlight_aska.android.camera01;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CameraView extends SurfaceView
    implements SurfaceHolder.Callback, PictureCallback {
  private Camera mCamera = null;
  private static final String SDCARD_FOLDER = "/sdcard/CameraSample/";

  public CameraView(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
    SurfaceHolder holder = getHolder();
    holder.addCallback(this);
    // holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // API Level 11で廃止予定に
    // 保存用フォルダ作成
    File dirs = new File(SDCARD_FOLDER);
    if(!dirs.exists()) {
      dirs.mkdir();
    }
  }

  @Override
  public void onPictureTaken(byte[] data, Camera camera) {
    // TODO Auto-generated method stub
    SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_kkmmss");
    String datName = "P" + date.format(new Date()) + ".jpg";
    try {
      // データ保存
      savePhotoData(datName, data);
    } catch (Exception e) {
      // TODO Auto-generated catch block
      if(mCamera != null) {
        mCamera.release();
        mCamera = null;
      }
    }
    // プレビュー再開
    mCamera.startPreview();
  }

  // 画像データのセーブ
  private void savePhotoData(String datName, byte[] data) throws Exception {
    // TODO Auto-generated method stub
    FileOutputStream outStream = null;

    try {
      outStream = new FileOutputStream(SDCARD_FOLDER + datName);
      outStream.write(data);
      outStream.close();
    } catch (Exception e) {
      if(outStream != null) {
        outStream.close();
      }
      throw e;
    }
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    // TODO Auto-generated method stub
    if(event.getAction() == MotionEvent.ACTION_DOWN) {
      // シャッターを切る
      mCamera.takePicture(null, null, this);
    }
    return true;
  }

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    mCamera = Camera.open();
    try {
      mCamera.setPreviewDisplay(holder);
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    // TODO Auto-generated method stub
    mCamera.stopPreview();
    Camera.Parameters params = mCamera.getParameters();
    List<Size> previewSizes = params.getSupportedPreviewSizes();
    Size size = previewSizes.get(0);
    params.setPreviewSize(size.width, size.height);
    mCamera.setParameters(params);
    // プレビュー開始
    mCamera.startPreview();
  }

  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    mCamera.stopPreview();
    mCamera.release();
    mCamera = null;
  }
}
  • AndroidManifest.xml
    • カメラを使用するには, "android.permission.CAMERA"パーミッションを設定する.
    • "android.hardware.camera"で, カメラ機能を備えたハードに限定する.
    • "android.hardware.camera.autofocus"で, オートフォーカス機能を備えたハードに限定する.
    • sdcardにデータを保存するには, "android.permission.WRITE_EXTERNAL_STORAGE"パーミションを設定する.
    • 画面を横向き(landscape)に固定する. Androidのカメラは横向き専用なので...
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.moonlight_aska.android.camerasample"
   android:versionCode="1"
   android:versionName="1.0">
  <uses-sdk android:minSdkVersion="8" />
  <uses-permission android:name="android.permission.CAMERA"></uses-permission>
  <uses-feature android:name="android.hardware.camera"></uses-feature>
  <uses-feature android:name="android.hardware.camera.autofocus"></uses-feature>
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

  <application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".CameraSample"
      android:label="@string/app_name"
      android:screenOrientation="landscape">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>
</manifest>
  • 動作例
カメラが起動したら, 画面にタッチすることで写真が撮影できる.
写真データは, /sdcard/CameraSampleの下に保存される.
端末:SHARP SH-03C / Android 2.2