カメラそのものをどうこうしたいのでは無く、他の機能(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の最新記事】
- Android Studio で Twitter4J で ListView に検索結果を表示する
- Android Studio で Twitter4J で画像付きツイート
- 内部ストレージを起点とした画像データの処理 / Android
- カメラを起点とした画像データの処理 / Android
- バグ : Android Studio 2.2.2 で、spinnerMode を dialog に設定すると app:spinnerMode となってしまいます
- ListView + カスタム ArrayAdapter + ViewSwitcher + Firebase API + Data Binding : 更新処理 / Android Studio
- Firebase storage に画像をアップロードする。1) ギャラリーから、2) 実行中の画面 / Android
- Firebase storage の画像を ファイルとしてダウンロードして ギャラリーに保存する( ImageView にも表示する ) / Android
- Firebase storage の画像の URL を取得して、通常と同様に Stream でダウンロードして ImageView に表示する / Android
- Firebase storage の画像をメモリに直接ダウンロードして ImageView に表示する / Android
- Android : Firebase の データを REST API の PUT コマンドで更新する
- Firebase API + Android Studio : Database のデータを Java に取得する方法は3通りあります。(orderByChild 使う場合は、getChildren ..
- Android : Data Binding + Firebase API で ListView にデータを表示する
- Firebase API + Android Studio : Database 処理の基本設定
- Android Studio 2.2 で新規プロジェクトを作成すると『Could not reserve enough space for 1572864KB object heap』というエラーが出..
- Firebase API + Android Studio : Database にデータを保存は単純で、DatabaseReference の setValue メソッドを使用します