まずは雛形となるプロジェクトをEasyProjectGenerator for Androidで作る。今回はJavaのSimpleプロジェクトを利用した。

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="https://schemas.android.com/apk/res/android" package="com.Test116" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".Test116Act" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> </manifest>
。今回はメインの背景が緑色のレイアウトに1×1ドットのCameraViewを追加する形にした。CameraViewのサイズはCameraView内で変更することにする。
また総ショット数(画像保存時の連番に利用)を保存/利用するためにonSaveInstanceState()やonRestoreInstanceState()を作り、CameraViewへと渡すようにした。package com.Test116; import android.app.Activity; import android.os.Bundle; import android.widget.LinearLayout; import android.graphics.Color; public class Test116Act extends Activity { private CameraView _view = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout layout = new LinearLayout(this); layout.setBackgroundColor(Color.GREEN); _view = new CameraView(this,savedInstanceState); layout.addView(_view,new LinearLayout.LayoutParams(1,1)); setContentView(layout); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if(_view != null) _view.OnSaveState(outState); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if(_view != null) _view.OnLoadState(savedInstanceState); } }
そして「CameraView.java」ファイルを作成。CameraViewクラスを実装する。
プレビューはカメラがサポートする最小サイズで表示。プレビューを画面タッチすると撮影。撮影時はサポートする最大サイズでjpg保存。ファイル名は総ショット数を利用して決定している。
package com.Test116; import android.hardware.Camera; import android.content.Context; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.MotionEvent; import java.io.FileOutputStream; import java.io.File; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore.Images; import android.provider.MediaStore.Images.Media; import android.util.Log; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.Size; import java.util.List; import android.view.ViewGroup.LayoutParams; import android.content.ContentValues; import android.content.ContentResolver; public class CameraView extends SurfaceView implements SurfaceHolder.Callback { private final String TAG = "Test116"; private SurfaceHolder _SurfaceHolder; private Camera _Camera; private int _nReady; private long _nShotNo; public CameraView(Context context,Bundle savedInstanceState) { super(context); Log.d(TAG, "CameraView::CameraView()"); _nReady = 0; _nShotNo = 0; OnLoadState(savedInstanceState); _SurfaceHolder = getHolder(); _SurfaceHolder.addCallback(this); _SurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } //設定の保存 public void OnSaveState(Bundle outState) { Log.d(TAG, "CameraView::OnSaveState()"); if(outState != null) { outState.putLong("_nShotNo",_nShotNo); } } //設定の読込 public void OnLoadState(Bundle savedInstanceState) { Log.d(TAG, "CameraView::OnLoadState()"); if(savedInstanceState != null) { _nShotNo = savedInstanceState.getLong("_nShotNo"); } } public void surfaceCreated(SurfaceHolder holder) { Log.d(TAG, "CameraView::surfaceCreated()"); try { _Camera = Camera.open(); _Camera.setPreviewDisplay(holder); } catch (Exception e) { Log.e(TAG, "CameraView::surfaceCreated() : Fail to setPreviewDisplay."); } } public void surfaceChanged(SurfaceHolder holder,int format,int w,int h) { Log.d(TAG, "CameraView::surfaceChanged()"); Camera.Parameters paramCamera = _Camera.getParameters(); List<Size> asizeSupport; Size size; //カメラがサポートする撮影サイズ一覧を取得 asizeSupport = paramCamera.getSupportedPictureSizes(); if(asizeSupport.size() != 0) { //一番大きい撮影サイズを利用 size = asizeSupport.get(0); paramCamera.setPictureSize(size.width,size.height); } //カメラがサポートするプレビューサイズ一覧を取得 asizeSupport = paramCamera.getSupportedPreviewSizes(); if(asizeSupport.size() != 0) { //一番小さいプレビューサイズを利用 size = asizeSupport.get(asizeSupport.size() - 1); paramCamera.setPreviewSize(size.width,size.height); LayoutParams paramLayout; //ビューサイズをプレビューサイズに合わせる paramLayout = getLayoutParams(); paramLayout.width = size.width; paramLayout.height = size.height; setLayoutParams(paramLayout); } //カメラパラメーター設定 _Camera.setParameters(paramCamera); _Camera.startPreview(); //プレビューの開始 _nReady = 1; } public void surfaceDestroyed(SurfaceHolder holder) { Log.d(TAG, "CameraView::surfaceDestroyed()"); //カメラの破棄 _nReady = 0; _Camera.setPreviewCallback(null); _Camera.stopPreview(); _Camera.release(); _Camera = null; } @Override public boolean onTouchEvent(MotionEvent event) { //タッチイベント取得 if(event.getAction() == MotionEvent.ACTION_DOWN) { Log.d(TAG, "CameraView::onTouchEvent()"); TakePicture(); //撮影 } return true; } private ShutterCallback _pfnShutterCallback = new ShutterCallback(); private final class ShutterCallback implements android.hardware.Camera.ShutterCallback { public void onShutter() { Log.d(TAG, "CameraView::onShutter()"); } }; private RawPictureCallback _pfnRawPictureCallback = new RawPictureCallback(); private final class RawPictureCallback implements PictureCallback { public void onPictureTaken(byte [] rawData, android.hardware.Camera camera) { Log.d(TAG, "CameraView::onRawPictureTaken()"); }; } private final class JpgPictureCallback implements PictureCallback { public void onPictureTaken(byte [] data, android.hardware.Camera camera) { Log.d(TAG, "CameraView::onJpgPictureTaken()"); String strFolder; String strFile; strFolder = Environment.getExternalStorageDirectory()+"/DCIM/Camera/"; //保存ファイル名 //重複チェックをしていないので、もしもすでにファイルがあったら上書きされる! strFile = strFolder + "test" + _nShotNo + ".jpg"; //if(_nShotNo == 0) //{ // //フォルダ作成 // File newFolder = new File(strFolder); // newFolder.mkdir(); //} try { //撮影画像保存(dataがすでにjpg画像になっているので、これをそのままファイルに落とすだけ) FileOutputStream cFile = new FileOutputStream(strFile); cFile.write(data); cFile.close(); //コンテンツ登録(androidギャラリーへの登録) long nDate; ContentValues values = new ContentValues(); nDate = System.currentTimeMillis(); values.put(Images.Media.MIME_TYPE,"image/jpeg"); //必須 values.put(Images.Media.DATA,strFile); //必須:ファイルパス(uriからストリーム作るなら不要) values.put(Images.Media.SIZE,new File(strFile).length()); //必須:ファイルサイズ(同上) // values.put(Images.Media.TITLE,strFile); // values.put(Images.Media.DISPLAY_NAME,strFile); values.put(Images.Media.DATE_ADDED,nDate); values.put(Images.Media.DATE_TAKEN,nDate); values.put(Images.Media.DATE_MODIFIED,nDate); // values.put(Images.Media.DESCRIPTION,""); // values.put(Images.Media.LATITUDE,0.0); // values.put(Images.Media.LONGITUDE,0.0); // values.put(Images.Media.ORIENTATION,""); ContentResolver contentResolver = getContext().getContentResolver(); contentResolver.insert(Media.EXTERNAL_CONTENT_URI, values); } catch(Exception e) { Log.e(TAG, "CameraView::onJpgPictureTaken() : Fail to save image file."); } _nShotNo++; camera.startPreview(); //プレビュー再開 _nReady = 1; }; }; public void TakePicture() { Log.d(TAG, "CameraView::takePicture()"); if(_nReady != 0) { _nReady = 0; _Camera.takePicture(_pfnShutterCallback, _pfnRawPictureCallback,new JpgPictureCallback()); } } }
デバイスの選択画面で「Choose a running Android device」から実機を選択する。
これで実機でアプリが実行されてプレビューが表示された。プレビュー画面を指でタッチすると撮影される。
撮影した画像はAndroid標準のギャラリーアプリで確認できる。
これが実際に撮影した画像を縮小したもの。保存サイズは2592×1952ドットでした。オートフォーカスを実装していないのでピンぼけすぎです。
プロジェクトファイルをダウンロード