Controlar la cámara para tomar fotos en el retrato no rota las imágenes finales

Intento controlar la cámara Android para tomar fotos en una aplicación de retratos, pero cuando guardo la imagen, está en el paisaje. He rotado la imagen 90 grados con el método setCameraDisplayOrientation() , pero no funciona.

Luego encontré esta publicación, pero TAG_ORIENTATION es 0 (indefinido). Si capturo este valor y aplico un valor de rotación, tampoco funciona.

¿Cómo puedo tomar una foto en retrato y guardarla con una buena orientación?

  /** 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()); } } 

El problema es cuando guardé la imagen que no hice bien.

 @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); } 

El método setCameraDisplayOrientation () le permite cambiar cómo se muestra la vista previa sin afectar la forma en que se graba la imagen ( fuente ).

Para cambiar la imagen grabada real, necesita configurar el parámetro de rotación de la cámara . Lo haces así:

 //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); 

Su solución es una especie de solución ya que modifica la imagen DESPUÉS de que ya fue grabada. Esta solución es más limpia y no requiere todas estas declaraciones ‘if’ antes de guardar la imagen.

Puede usar el método a continuación para generar una vista previa correcta cuando usa la cámara frontal.

Este código va al método SurfaceChanged de la vista previa de tu cámara

 @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); } 

Este código se puede poner en una clase estática

  /** * 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; } 

Puede rotar la imagen de esta manera. Esto se usa solo cuando se toma la imagen y estamos a punto de guardar la imagen

 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); } 

El método que se usará para tomar la fotografía

  @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); } 

El bitmapImage contiene la imagen correcta.

este debería funcionar, ExifInterface no funciona con todos los fabricantes, por lo tanto, utilice CameraInfo en su lugar, simplemente deje que la cámara capture la imagen con su rotación predeterminada y luego gire los datos del resultado en PictureCallback

 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); } 

Encuentro la respuesta poderosa para ti, acabo de encontrar el mismo problema y lo resuelvo sin guardar el archivo. La solución es registrar un OrientationEventListener para obtener la orientación cada vez que cambie. http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html aquí dan los detalles. Mi código es el siguiente:

 private CameraOrientationListener myOrientationListener; private int rotation; protected void onCreate(Bundle savedInstanceState) { setListeners(); rotation = setCameraDisplayOrientation(CameraActivity.this, Camera.getNumberOfCameras()-1, mCamera); } public void setListeners(){ myOrientationListener = new CameraOrientationListener(this); if(myOrientationListener.canDetectOrientation()) myOrientationListener.enable(); } public static int setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) { CameraInfo info = new CameraInfo(); Camera.getCameraInfo(cameraId, info); int rotation = activity.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 == 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); return result; } /* * record the rotation when take photo */ public void takePhoto(){ myOrientationListener.rememberOrientation(); rotation += myOrientationListener.getRememberedOrientation(); rotation = rotation % 360; mCamera.takePicture(null, null, mPicture); } class CameraOrientationListener extends OrientationEventListener { private int currentNormalizedOrientation; private int rememberedNormalizedOrientation; public CameraOrientationListener(Context context) { super(context, SensorManager.SENSOR_DELAY_NORMAL); } @Override public void onOrientationChanged(int orientation) { // TODO Auto-generated method stub if (orientation != ORIENTATION_UNKNOWN) { currentNormalizedOrientation = normalize(orientation); } } private int normalize(int degrees) { if (degrees > 315 || degrees <= 45) { return 0; } if (degrees > 45 && degrees <= 135) { return 90; } if (degrees > 135 && degrees <= 225) { return 180; } if (degrees > 225 && degrees <= 315) { return 270; } throw new RuntimeException("The physics as we know them are no more. Watch out for anomalies."); } public void rememberOrientation() { rememberedNormalizedOrientation = currentNormalizedOrientation; } public int getRememberedOrientation() { return rememberedNormalizedOrientation; } } 

Espero eso ayude:)

Este es el mejor método para usar (mencionado a continuación) cuando su diseño se arregla en modo retrato.

 @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(); } } 

Utilizará OrientEventListener e implementará este método de callback. onOrientationChanged se invoca siempre que haya un cambio de orientación, por lo que se establecerá la rotación de la cámara y la imagen se girará cuando la guarde.

  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; } 

Fuente aquí

No tengo el representante para dejar un comentario, así que tengo que dejar otra respuesta, aunque la respuesta de Nvhausid es increíble y merece el crédito. Simple, elegante y funciona tanto para cámaras frontales como posteriores en un dispositivo Samsung donde Exif y Media Cursor no lo hacen.

Lo único que me faltaba la respuesta era manejar la imagen reflejada de la cámara frente al usuario.

Aquí está el código cambia para eso:

 Bitmap bitmap = rotate(realImage, info.orientation, info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT); 

Y el nuevo método de rotación:

 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); } 

Usé la nueva cámara2 api para obtener la orientación del sensor y luego rotarla en consecuencia:

  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(); } } 

Luego, con la ayuda del parámetro cameraOrientation, giré mi cámaraFoto:

  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(); } }