SQLの窓

2016年10月25日


Android : 画像関連のテスト用カメラアプリ

カメラそのものをどうこうしたいのでは無く、他の機能(Firebase storage 等)との連携テストに使いたいので、いわゆる旧式のカメラ API を使用しています。

▼ Android Studio では 『非推奨』と言われます


また、撮影は AndroidManifest.xml で縦の portrait 固定にして行う為、実際に横にした時の判定にセンサを使い、縦の時は 90度回転して画像を保存しなおしています。テストの実機は 4.4.4 のみですが、そもそもテスト用なので全ての対応はソース次第で好きに変更できます。

いろいろサンプルを探したのですが、全方向に対応したものが無かったので機能を集めました。

※ センサの判定はかなり適当です

MyCamera クラス
public class MyCamera implements SurfaceHolder.Callback {

	// 古いカメラAPI。カメラで何かしたいわけでは無いのでこれで実装
	private Camera camera;
	private SurfaceHolder holder;
	private Camera.Size size;
	private MainActivity mainActivity;
	private SurfaceView cameraView;
	private List<Camera.Size> sizeList;

	public MyCamera(Context context) {

		Log.i("lightbox", "コンストラクタ");

		this.mainActivity = (MainActivity) context;

		// MainActivity の画面のSurfaceView を使う
		cameraView = (SurfaceView)mainActivity.findViewById(R.id.cameraView);
		// SurfaceView から holder を取り出して、カメラに渡す
		holder = cameraView.getHolder();
		// この中でイベント処理を行う
		holder.addCallback(MyCamera.this);

	}

	public Camera getCamera() {

		return camera;

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {

		Log.i("lightbox", "開く");

		// カメラを開く
		camera = Camera.open();
		try {
			// カメラに holder を渡す
			camera.setPreviewDisplay(holder);
		} catch (IOException e) {
			e.printStackTrace();
		}

		// 縦固定(AndroidManifest.xml) で、portrait 撮影を前提
		camera.setDisplayOrientation(90);

		// カメラの情報
		Camera.Parameters params = camera.getParameters();
		// サポートされているサイズの一覧
		sizeList = params.getSupportedPreviewSizes();
		// 対応しているサイズの先頭のサイズ
		size = sizeList.get(0);

	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

		// 縦固定(AndroidManifest.xml) なので一度しか通らない

		Log.i("lightbox", "開始");

		// 縦横サイズの設定
		Camera.Parameters params = camera.getParameters();
		// ギャラリーでは縦になるが、保存画像は横
		params.setRotation(90);
		Camera.Size optimalSize = getOptimalPreviewSize(sizeList,width,height);
		params.setPreviewSize(optimalSize.width,optimalSize.height);
		camera.setParameters(params);

		camera.startPreview();

	}

	// http://qiita.com/zaburo/items/b5d3815d3ec45b0daf4f
	private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {

		final double ASPECT_TOLERANCE = 0.1;
		double targetRatio=(double)h / w;

		if (sizes == null) return null;

		Camera.Size optimalSize = null;
		double minDiff = Double.MAX_VALUE;

		int targetHeight = h;

		for (Camera.Size size : sizes) {
			double ratio = (double) size.width / size.height;
			if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
			if (Math.abs(size.height - targetHeight) < minDiff) {
				optimalSize = size;
				minDiff = Math.abs(size.height - targetHeight);
			}
		}

		if (optimalSize == null) {
			minDiff = Double.MAX_VALUE;
			for (Camera.Size size : sizes) {
				if (Math.abs(size.height - targetHeight) < minDiff) {
					optimalSize = size;
					minDiff = Math.abs(size.height - targetHeight);
				}
			}
		}
		return optimalSize;
	}


	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {

		Log.i("lightbox", "終了");

		// プレビュー終了
		if ( camera != null ) {
			camera.stopPreview();
			camera.release();
			camera = null;
		}

	}
}


MainActivity
public class MainActivity extends AppCompatActivity implements SensorEventListener {

	private String imagePath;
	private MyCamera camera;
	private SensorManager sensor;
	private Sensor acc;
	private boolean portrait;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		camera = new MyCamera(MainActivity.this);
		sensor = (SensorManager)getSystemService(SENSOR_SERVICE);
		acc = sensor.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		sensor.registerListener(MainActivity.this,acc,SensorManager.SENSOR_DELAY_NORMAL);
		portrait = true;

		// *************************************
		// ギャラリーに保存
		// *************************************
		Button galleryButton = (Button) MainActivity.this.findViewById(R.id.galleryButton);
		galleryButton.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("lightbox", "クリック");

				Camera.Parameters params = camera.getCamera().getParameters();
				if ( portrait ) {
					// ギャラリーでは縦になるが、保存画像は横
					params.setRotation(90);
				}
				else {
					// ギャラリーで横、保存画像も横
					params.setRotation(0);
				}
				camera.getCamera().setParameters(params);


				// 撮影
				camera.getCamera().takePicture(null, null, new Camera.PictureCallback() {
					@Override
					public void onPictureTaken(byte[] data, Camera camera) {

						if (data != null) {

							// ギャラリー用に内部ストレージにフォルダを作成
							String firebaseImageDir = Environment.getExternalStorageDirectory().getPath() + "/firebase";
							File file = new File(firebaseImageDir);
							// ディレクトリ初期作成
							if (!file.exists()) {
								if (file.mkdir() == false) {
									Log.i("lightbox", "ディレクトリを作成できませんでした");
									return;
								}
							}

							// ギャラリー用画像保存パス
							Calendar cal = Calendar.getInstance();
							SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd_HHmmss");
							imagePath = firebaseImageDir + "/" + sf.format(cal.getTime()) + ".jpg";

							FileOutputStream jpg;
							try {
								jpg = new FileOutputStream(imagePath);
								if ( portrait ) {
									// 縦の場合、回転して保存する
									Bitmap bmp1 = BitmapFactory.decodeByteArray (data, 0, data.length);
									int width = bmp1.getWidth();
									int height = bmp1.getHeight();
									Matrix matrix = new Matrix();
									matrix.postRotate (90);
									Bitmap bmp2 = Bitmap.createBitmap (bmp1, 0, 0, width, height, matrix, true);

									bmp2.compress(Bitmap.CompressFormat.JPEG,90,jpg);
								}
								else {
									jpg.write(data);
									jpg.close();
								}

								// ギャラリーに反映
								MediaScannerConnection.scanFile(
									MainActivity.this,
									new String[] { imagePath },
									new String[] { "image/jpeg" },
									null);

							} catch (Exception e) {
								e.printStackTrace();
							}

							// イベントの引数のカメラ
							camera.startPreview();

						}
					}
				});

			}
		});

	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {

	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		// センサで実際の縦と横を判定
		if ( -4 <= event.values[0] && event.values[0] <= 4  ) {
			portrait = true;
		}
		else {
			portrait = false;
		}
	}

	public boolean getPortrait (){
		return portrait;
	}

	@Override
	protected void onResume() {
		super.onResume();
		sensor.registerListener(MainActivity.this,acc,SensorManager.SENSOR_DELAY_NORMAL);

	}

	@Override
	protected void onPause() {
		super.onPause();
		sensor.unregisterListener(this);
	}


}


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest package="lightbox.sep.fire1"
          xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:screenOrientation="portrait">
            <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.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA"/>

</manifest>



【2016 Android Studioの最新記事】
posted by lightbox at 2016-10-25 03:15 | 2016 Android Studio | このブログの読者になる | 更新情報をチェックする
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり