また1ヶ月空いてしまったが・・・
結局また1ヶ月何も作らなかったが、再開する。
定番だが、QRリーダー作ってみようかと思ってたわけで、先月調べたところSurfaceViewというアニメーション等の更新が必要なものを表示するViewがあり、カメラのプレビューにはそれ使う。
というわけで、まずはSurfaceViewにカメラの表示。
AndroidManifest.xml
<uses-permission>でアプリがカメラを使えるようにして、<uses-feature>を書いておくとアプリ配信時にカメラ無し端末はGooglePlayに表示されなくなる。
APIリファレンスだとカメラはandroid.hardware.Cameraが非推薦でandroid.hardware.camera2を使うように書かれているが、camera2はAPIレベル21。
API 21はAndroid 5.0かな?流石に要件厳しすぎるんでandroid.hardware.Cameraの方使うことに。
MainActivity.java
40行ほどになってしまったが、半分は背面カメラの判別コード。
最初のお試しにはカメラの判別はしなくていいと思うんで、もっと簡単。
layoutファイルでSurfaceViewを定義。
コード中でidでSurfaceViewを取得して、getHolder()でSurfaceHolderを取得。
addCallbackでコールバックを設定。
addCallbackの引数はSurfaceHolder.Callback一つで、SurfaceHolder.Callbackはイベントリスナ的なやつかな?surfaceChanged、surfaceCreated、surfaceDestroyedの3つを定義する。
今回はお試しなんで、surfaceCreatedだけ定義した。これがSurfaceView作成時に1回だけ呼びだされて、内容変更時にsurfaceChanged、破棄時にsurfaceDestroyedが呼び出される感じかな。
Camera.open()で1番目のカメラが起動、カメラ番号を引数に渡すこともできCamera.open(1)だと2番目になるのかな?
Camera.getNumberOfCameras()で端末のカメラ数を取得できる。
SurfaceView作成時に呼び出されるsurfaceCreatedでカメラのプレビューを開始してSurfaceViewに描画する。
起動中のカメラのsetPreviewDisplay(holder)でSurfaceHolderを設定。
startPreview()するだけ。
tryで例外処理する必要があるけど、簡単だね。
今回はカメラが複数ある場合は背面カメラを使い、一つの場合はそれを起動。としたかったわけだが、
Callback内(サブクラス内)でカメラの取得が必要そうなんで、final修飾子つけた。
finalの時はその行で初期化しないとダメなもんだと思ってたが、確実に定義されるなら次以降のif文等で定義することもできるんだね。
対象カメラの判別をしてから定義する必要があるんで、final変数をif文内で初期化にした。
カメラが複数の場合はforで全カメラを判別すべきな気もするが、for内でfinal変数の初期化はできない?やりかたわからん。
端末にカメラが3個以上付いているというのはありえないよね?2個あるなら1番か2番のカメラのどちらかが確実に背面だと思うんで、forじゃなくてif文にした。
カメラの前背面の判別は、Camera.CameraInfo()で判別できるんだが、なんかわかりにくい。
static void Camera.getCameraInfo(int cameraId, Camera.CameraInfo cameraInfo)
↑これ
Cameraのstaticメソッドを使うんだが、直接CameraInfoを返してくれる仕様ならわかりやすいが、voidなんだよね。
空のCameraInfoを自分で作成してgetCameraInfoの引数として渡す。そうすると渡したCameraInfoで情報を得ることができるって仕様。
背面なら、取得したCameraInfoのfacingが、Camera.CameraInfo.CAMERA_FACING_BACKになる。
前面なら、Camera.CameraInfo.CAMERA_FACING_FRONT。
そんなわけで、カメラを扱うのはできた。
QRの解析にはZxingって定番ぽいライブラリ使うつもりだが、プレビュー中のカメラから自動で定期的にビットマップを取得してZxingで処理する感じだね。
やる気出せばとりあえずのものは1日でできると思うが、やる気が出るか・・・
定番だが、QRリーダー作ってみようかと思ってたわけで、先月調べたところSurfaceViewというアニメーション等の更新が必要なものを表示するViewがあり、カメラのプレビューにはそれ使う。
というわけで、まずはSurfaceViewにカメラの表示。
AndroidManifest.xml
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.CAMERA"/>
この2行を、<manifest>の下(<application>の前に書いた)に書いとく。<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission>でアプリがカメラを使えるようにして、<uses-feature>を書いておくとアプリ配信時にカメラ無し端末はGooglePlayに表示されなくなる。
APIリファレンスだとカメラはandroid.hardware.Cameraが非推薦でandroid.hardware.camera2を使うように書かれているが、camera2はAPIレベル21。
API 21はAndroid 5.0かな?流石に要件厳しすぎるんでandroid.hardware.Cameraの方使うことに。
MainActivity.java
import android.app.Activity;
import android.os.Bundle;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.hardware.Camera;
public class MainActivity extends Activity{
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Camera camera;
if(Camera.getNumberOfCameras()==1){
camera=Camera.open();
}else{
Camera.CameraInfo ci=new Camera.CameraInfo();
Camera.getCameraInfo(0,ci);
if(ci.facing==ci.CAMERA_FACING_BACK){
camera=Camera.open(0);
}else{
camera=Camera.open(1);
}
}
SurfaceView sv=(SurfaceView)findViewById(R.id.sv);
sv.getHolder().addCallback(new SurfaceHolder.Callback(){
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
}
public void surfaceCreated(SurfaceHolder holder){
try{
camera.setPreviewDisplay(holder);
camera.startPreview();
}catch(Exception e){
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder holder){
}
});
}
}
import android.os.Bundle;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.hardware.Camera;
public class MainActivity extends Activity{
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Camera camera;
if(Camera.getNumberOfCameras()==1){
camera=Camera.open();
}else{
Camera.CameraInfo ci=new Camera.CameraInfo();
Camera.getCameraInfo(0,ci);
if(ci.facing==ci.CAMERA_FACING_BACK){
camera=Camera.open(0);
}else{
camera=Camera.open(1);
}
}
SurfaceView sv=(SurfaceView)findViewById(R.id.sv);
sv.getHolder().addCallback(new SurfaceHolder.Callback(){
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){
}
public void surfaceCreated(SurfaceHolder holder){
try{
camera.setPreviewDisplay(holder);
camera.startPreview();
}catch(Exception e){
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder holder){
}
});
}
}
40行ほどになってしまったが、半分は背面カメラの判別コード。
最初のお試しにはカメラの判別はしなくていいと思うんで、もっと簡単。
layoutファイルでSurfaceViewを定義。
コード中でidでSurfaceViewを取得して、getHolder()でSurfaceHolderを取得。
addCallbackでコールバックを設定。
addCallbackの引数はSurfaceHolder.Callback一つで、SurfaceHolder.Callbackはイベントリスナ的なやつかな?surfaceChanged、surfaceCreated、surfaceDestroyedの3つを定義する。
今回はお試しなんで、surfaceCreatedだけ定義した。これがSurfaceView作成時に1回だけ呼びだされて、内容変更時にsurfaceChanged、破棄時にsurfaceDestroyedが呼び出される感じかな。
Camera.open()で1番目のカメラが起動、カメラ番号を引数に渡すこともできCamera.open(1)だと2番目になるのかな?
Camera.getNumberOfCameras()で端末のカメラ数を取得できる。
SurfaceView作成時に呼び出されるsurfaceCreatedでカメラのプレビューを開始してSurfaceViewに描画する。
起動中のカメラのsetPreviewDisplay(holder)でSurfaceHolderを設定。
startPreview()するだけ。
tryで例外処理する必要があるけど、簡単だね。
今回はカメラが複数ある場合は背面カメラを使い、一つの場合はそれを起動。としたかったわけだが、
Callback内(サブクラス内)でカメラの取得が必要そうなんで、final修飾子つけた。
finalの時はその行で初期化しないとダメなもんだと思ってたが、確実に定義されるなら次以降のif文等で定義することもできるんだね。
対象カメラの判別をしてから定義する必要があるんで、final変数をif文内で初期化にした。
カメラが複数の場合はforで全カメラを判別すべきな気もするが、for内でfinal変数の初期化はできない?やりかたわからん。
端末にカメラが3個以上付いているというのはありえないよね?2個あるなら1番か2番のカメラのどちらかが確実に背面だと思うんで、forじゃなくてif文にした。
カメラの前背面の判別は、Camera.CameraInfo()で判別できるんだが、なんかわかりにくい。
static void Camera.getCameraInfo(int cameraId, Camera.CameraInfo cameraInfo)
↑これ
Cameraのstaticメソッドを使うんだが、直接CameraInfoを返してくれる仕様ならわかりやすいが、voidなんだよね。
空のCameraInfoを自分で作成してgetCameraInfoの引数として渡す。そうすると渡したCameraInfoで情報を得ることができるって仕様。
背面なら、取得したCameraInfoのfacingが、Camera.CameraInfo.CAMERA_FACING_BACKになる。
前面なら、Camera.CameraInfo.CAMERA_FACING_FRONT。
そんなわけで、カメラを扱うのはできた。
QRの解析にはZxingって定番ぽいライブラリ使うつもりだが、プレビュー中のカメラから自動で定期的にビットマップを取得してZxingで処理する感じだね。
やる気出せばとりあえずのものは1日でできると思うが、やる気が出るか・・・