Androidカメラを制御してポートレートアプリで写真を撮ろうとしていますが、写真を保存すると、横向きになります。90グレードの画像を setCameraDisplayOrientation()
メソッドですが、機能しません。
そして、私はこれを見つけました post しかし、TAG_ORIENTATION
は0
(未定義)。この値をキャッチして回転値を適用すると、機能しません。
写真をポートレートで撮り、適切な向きで保存するにはどうすればよいですか?
/** Initializes the back/front camera */
private boolean initPhotoCamera() {
try {
camera = getCameraInstance(selected_camera);
Camera.Parameters parameters = camera.getParameters();
// parameters.setPreviewSize(width_video, height_video);
// parameters.set("orientation", "portrait");
// parameters.set("rotation", 1);
// camera.setParameters(parameters);
checkCameraFlash(parameters);
// camera.setDisplayOrientation( 0);
setCameraDisplayOrientation(selected_camera, camera);
surface_view.getHolder().setFixedSize(width_video, height_video);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width_video, height_video);
surface_view.setLayoutParams(lp);
camera.lock();
surface_holder = surface_view.getHolder();
surface_holder.addCallback(this);
surface_holder.setType(SurfaceHolder.SURFACE_TYPE_Push_BUFFERS);
setPreviewCamera();
} catch (Exception e) {
Log.v("RecordVideo", "Could not initialize the Camera");
return false;
}
return true;
}
public void setCameraDisplayOrientation(int cameraId, Camera camera) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
// mtx.postRotate(degree);
mtx.setRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
String timeStamp = Calendar.getInstance().getTime().toString();
output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg";
File pictureFile = new File(output_file_name);
if (pictureFile.exists()) {
pictureFile.delete();
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
Bitmap realImage = BitmapFactory.decodeFile(output_file_name);
ExifInterface exif=new ExifInterface(pictureFile.toString());
Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION));
if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){
realImage= rotate(realImage, 90);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){
realImage= rotate(realImage, 270);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){
realImage= rotate(realImage, 180);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){
realImage= rotate(realImage, 45);
}
boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
Log.d("Info", bo + "");
} catch (FileNotFoundException e) {
Log.d("Info", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("TAG", "Error accessing file: " + e.getMessage());
}
}
問題は、うまく保存できなかった画像を保存したときです。
@Override
public void onPictureTaken(byte[] data, Camera camera) {
String timeStamp = new SimpleDateFormat( "yyyyMMdd_HHmmss").format( new Date( ));
output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg";
File pictureFile = new File(output_file_name);
if (pictureFile.exists()) {
pictureFile.delete();
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
ExifInterface exif=new ExifInterface(pictureFile.toString());
Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION));
if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){
realImage= rotate(realImage, 90);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){
realImage= rotate(realImage, 270);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){
realImage= rotate(realImage, 180);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){
realImage= rotate(realImage, 90);
}
boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
((ImageView) findViewById(R.id.imageview)).setImageBitmap(realImage);
Log.d("Info", bo + "");
} catch (FileNotFoundException e) {
Log.d("Info", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("TAG", "Error accessing file: " + e.getMessage());
}
}
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
// mtx.postRotate(degree);
mtx.setRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
setCameraDisplayOrientation()メソッドを使用すると、previewの表示方法を変更できます画像の記録方法に影響を与えることなく( source )。
実際に記録された画像を変更するには、Cameraのrotationパラメーターを設定する必要があります。このようにします:
//STEP #1: Get rotation degrees
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break; //Natural orientation
case Surface.ROTATION_90: degrees = 90; break; //Landscape left
case Surface.ROTATION_180: degrees = 180; break;//Upside down
case Surface.ROTATION_270: degrees = 270; break;//Landscape right
}
int rotate = (info.orientation - degrees + 360) % 360;
//STEP #2: Set the 'rotation' parameter
Camera.Parameters params = mCamera.getParameters();
params.setRotation(rotate);
mCamera.setParameters(params);
既に記録された後にイメージを変更するため、ソリューションは一種の回避策です。このソリューションはよりクリーンで、画像を保存する前にこれらの「if」ステートメントをすべて必要としません。
フロントカメラを使用している場合、以下の方法を使用してプレビューを正しく生成できます。
このコードは、カメラプレビューのsurfaceChangedメソッドに入ります
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
int angleToRotate=CommonMethods.getRoatationAngle(mActivity, Camera.CameraInfo.CAMERA_FACING_FRONT);
mCamera.setDisplayOrientation(angleToRotate);
}
このコードは静的クラスに入れることができます
/**
* Get Rotation Angle
*
* @param mContext
* @param cameraId
* probably front cam
* @return angel to rotate
*/
public static int getRoatationAngle(Activity mContext, int cameraId) {
Android.hardware.Camera.CameraInfo info = new Android.hardware.Camera.CameraInfo();
Android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = mContext.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
この方法で画像を回転できます。これは、画像が撮影され、画像を保存するときにのみ使用されます
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.postRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
写真の撮影に使用される方法
@Override
public void onPictureTaken(byte[] data, Camera camera) {
int angleToRotate = getRoatationAngle(MainActivity.this, Camera.CameraInfo.CAMERA_FACING_FRONT);
// Solve image inverting problem
angleToRotate = angleToRotate + 180;
Bitmap orignalImage = BitmapFactory.decodeByteArray(data, 0, data.length);
Bitmap bitmapImage = rotate(orignalImage, angleToRotate);
}
bitmapImage
には正しい画像が含まれています。
これは動作するはずです。ExifInterfaceはすべてのメーカーで動作するわけではないため、代わりにCameraInfoを使用してください。
private PictureCallback mPicture = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File dir = new File(Constant.SDCARD_CACHE_PREFIX);
if (!dir.exists()) {
dir.mkdirs();
}
File pictureFile = new File(Constant.SDCARD_TAKE_PHOTO_CACHE_PREFIX);
try {
Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
Android.hardware.Camera.CameraInfo info = new Android.hardware.Camera.CameraInfo();
Android.hardware.Camera.getCameraInfo(mCurrentCameraId, info);
Bitmap bitmap = rotate(realImage, info.orientation);
FileOutputStream fos = new FileOutputStream(pictureFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
resultFileUri = Uri.fromFile(pictureFile);
startEffectFragment();
}
};
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.postRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
コメントを残す担当者がいないので、代わりに別の回答を残さなければなりませんが、Nvhausidの回答は素晴らしいものであり、功績に値します。シンプルでエレガントで、ExifとMedia Cursorが機能しないSamsungデバイスのフロントカメラとバックカメラの両方で機能します。
答えが私に欠けていた唯一のものは、ユーザーに面したカメラからの鏡像を処理することでした。
そのためのコード変更は次のとおりです。
Bitmap bitmap = rotate(realImage, info.orientation, info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT);
そして、新しいrotateメソッド:
public static Bitmap rotate(Bitmap bitmap, int degree, boolean mirror) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
if(mirror)mtx.setScale(1,-1);
mtx.postRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
これは、レイアウトがポートレートモードで固定されている場合に使用するのに最適な方法です(以下に記載)。
@Override
protected void onResume() {
super.onResume();
if (!openCamera(CameraInfo.CAMERA_FACING_BACK)) {
alertCameraDialog();
}
if (cOrientationEventListener == null) {
cOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
int lastOrientation = mOrientation;
if (orientation == ORIENTATION_UNKNOWN) return;
Camera.CameraInfo info =
new Android.hardware.Camera.CameraInfo();
Android.hardware.Camera.getCameraInfo(cameraId, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
Parameters params = camera.getParameters();
params.setRotation(rotation);
camera.setParameters(params);
}
};
}
if (cOrientationEventListener.canDetectOrientation()) {
cOrientationEventListener.enable();
}
}
OrientEventListenerを使用して、このコールバックメソッドを実装します。 onOrientationChangedは、向きが変更されるたびに呼び出されるため、カメラの回転が設定され、保存するときに画像が回転します。
private PictureCallback myPictureCallback_JPG = new PictureCallback()
{
@Override
public void onPictureTaken(byte[] arg0, Camera arg1) {
try {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
return;
}
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(arg0);
fos.close();
camera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
};
getOutputMediaFile
private static File getOutputMediaFile() {
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MyCameraApp");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
return mediaFile;
}
ソース ここ
新しいcamera2 APIを使用してセンサーの向きを取得し、それに応じて回転させます。
private void detectSensorOrientation()
{
CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
try
{
for (String cameraId : manager.getCameraIdList())
{
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
// We don't use a front facing camera in this sample.
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT)
{
continue;
}
cameraOrientaion = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
}
} catch (CameraAccessException e)
{
e.printStackTrace();
}
}
次に、cameraOrientationパラメーターを使用して、cameraPhotoを回転させました。
private void generateRotatedBitmap()
{
if (cameraOrientaion != 0)
{
Matrix matrix = new Matrix();
matrix.postRotate(cameraOrientaion);
rotatedPhoto =
Bitmap.createBitmap(cameraPhoto, 0, 0, cameraPhoto.getWidth(), cameraPhoto.getHeight(),
matrix, true);
cameraPhoto.recycle();
}
}