Cómo configurar la orientación de la cámara Android correctamente?

Quiero establecer la orientación de la cámara de acuerdo con la orientación del dispositivo en Android, pero nada parece estar funcionando. He intentado girar la superficie, así como los parámetros de la cámara, pero la vista previa de la cámara en el modo de retrato siempre viene al revés. Tendría que girar 90 grados en sentido horario para que sea correcto. Aquí está el código que estoy usando ahora que funciona sólo en modo horizontal.

SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); camera = null; } @Override public void surfaceCreated(SurfaceHolder holder) { initCamera(); } private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.2; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { Log.d(TAG, "Checking size " + size.width + "w " + size.height + "h"); 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); } } // Cannot find the one match the aspect ratio, ignore the // requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Camera.Parameters parameters = camera.getParameters(); List<Size> sizes = parameters.getSupportedPreviewSizes(); Size optimalSize = getOptimalPreviewSize(sizes, width, height); Log.d(TAG, "Surface size is " + width + "w " + height + "h"); Log.d(TAG, "Optimal size is " + optimalSize.width + "w " + optimalSize.height + "h"); parameters.setPreviewSize(optimalSize.width, optimalSize.height); // parameters.setPreviewSize(width, height); camera.setParameters(parameters); camera.startPreview(); } }; 

De otro miembro y mi problema:

El problema de rotación de la cámara depende de los diferentes dispositivos y de ciertas versiones.

Versión 1.6: para solucionar el problema de rotación, y es bueno para la mayoría de los dispositivos

 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { p.set("orientation", "portrait"); p.set("rotation",90); } if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { p.set("orientation", "landscape"); p.set("rotation", 90); } 

Versión 2.1: dependen de tipo de dispositivos, por ejemplo, Can not arreglar el problema con XPeria X10, pero es bueno para X8, y Mini

 Camera.Parameters parameters = camera.getParameters(); parameters.set("orientation", "portrait"); camera.setParameters(parameters); 

Versión 2.2: no es para todos los dispositivos

 camera.setDisplayOrientation(90); 

http://code.google.com/p/android/issues/detail?id=1193#c42

Desde el Javadocs para setDisplayOrientation(int) (Requiere API nivel 9):

  public static void setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) { android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.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 == 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); } 

Esta solución funcionará para todas las versiones de Android. Puede utilizar la reflexión en Java para que funcione para todos los dispositivos Android:

Básicamente debe crear un contenedor de reflexión para llamar a Android 2.2 setDisplayOrientation, en lugar de llamar al método específico.

El método:

  protected void setDisplayOrientation(Camera camera, int angle){ Method downPolymorphic; try { downPolymorphic = camera.getClass().getMethod("setDisplayOrientation", new Class[] { int.class }); if (downPolymorphic != null) downPolymorphic.invoke(camera, new Object[] { angle }); } catch (Exception e1) { } } 

Y en lugar de usar camera.setDisplayOrientation (x) use setDisplayOrientation (camera, x) :

  if (Integer.parseInt(Build.VERSION.SDK) >= 8) setDisplayOrientation(mCamera, 90); else { if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { p.set("orientation", "portrait"); p.set("rotation", 90); } if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { p.set("orientation", "landscape"); p.set("rotation", 90); } } 

Me enfrenté al problema cuando estaba usando ZBar para escanear en pestañas. Cuestión de orientación de la cámara. El uso de código a continuación, pude resolver el problema. Este no es el fragmento de código completo, por favor, tome sólo la ayuda de esto.

  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (isPreviewRunning) { mCamera.stopPreview(); } setCameraDisplayOrientation(mCamera); previewCamera(); } public void previewCamera() { try { // Hard code camera surface rotation 90 degs to match Activity view // in portrait mCamera.setPreviewDisplay(mHolder); mCamera.setPreviewCallback(previewCallback); mCamera.startPreview(); mCamera.autoFocus(autoFocusCallback); isPreviewRunning = true; } catch (Exception e) { Log.d("DBG", "Error starting camera preview: " + e.getMessage()); } } public void setCameraDisplayOrientation(android.hardware.Camera camera) { Camera.Parameters parameters = camera.getParameters(); android.hardware.Camera.CameraInfo camInfo = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(getBackFacingCameraId(), camInfo); Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); int rotation = display.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 (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { result = (camInfo.orientation + degrees) % 360; result = (360 - result) % 360; // compensate the mirror } else { // back-facing result = (camInfo.orientation - degrees + 360) % 360; } camera.setDisplayOrientation(result); } private int getBackFacingCameraId() { int cameraId = -1; // Search for the front facing camera int numberOfCameras = Camera.getNumberOfCameras(); for (int i = 0; i < numberOfCameras; i++) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) { cameraId = i; break; } } return cameraId; } 

Finalmente arreglé esto usando la aplicación de cámara de Google. Obtiene la orientación del teléfono mediante el uso de un sensor y, a continuación, establece la etiqueta EXIF ​​de manera adecuada. El JPEG que sale de la cámara no está orientado automáticamente.

Además, la vista previa de la cámara funciona correctamente sólo en el modo horizontal. Si necesita que su diseño de actividad esté orientado en vertical, tendrá que hacerlo manualmente usando el valor del sensor de orientación.

Este problema se resolvió hace mucho tiempo pero me encontré con algunas dificultades para poner todas las piezas juntas, así que aquí está mi solución final, espero que esto ayude a otros:

 public void startPreview() { try { Log.i(TAG, "starting preview: " + started); // .... Camera.CameraInfo camInfo = new Camera.CameraInfo(); Camera.getCameraInfo(cameraIndex, camInfo); int cameraRotationOffset = camInfo.orientation; // ... Camera.Parameters parameters = camera.getParameters(); List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); Camera.Size previewSize = null; float closestRatio = Float.MAX_VALUE; int targetPreviewWidth = isLandscape() ? getWidth() : getHeight(); int targetPreviewHeight = isLandscape() ? getHeight() : getWidth(); float targetRatio = targetPreviewWidth / (float) targetPreviewHeight; Log.v(TAG, "target size: " + targetPreviewWidth + " / " + targetPreviewHeight + " ratio:" + targetRatio); for (Camera.Size candidateSize : previewSizes) { float whRatio = candidateSize.width / (float) candidateSize.height; if (previewSize == null || Math.abs(targetRatio - whRatio) < Math.abs(targetRatio - closestRatio)) { closestRatio = whRatio; previewSize = candidateSize; } } int rotation = 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 displayRotation; if (isFrontFacingCam) { displayRotation = (cameraRotationOffset + degrees) % 360; displayRotation = (360 - displayRotation) % 360; // compensate // the // mirror } else { // back-facing displayRotation = (cameraRotationOffset - degrees + 360) % 360; } Log.v(TAG, "rotation cam / phone = displayRotation: " + cameraRotationOffset + " / " + degrees + " = " + displayRotation); this.camera.setDisplayOrientation(displayRotation); int rotate; if (isFrontFacingCam) { rotate = (360 + cameraRotationOffset + degrees) % 360; } else { rotate = (360 + cameraRotationOffset - degrees) % 360; } Log.v(TAG, "screenshot rotation: " + cameraRotationOffset + " / " + degrees + " = " + rotate); Log.v(TAG, "preview size: " + previewSize.width + " / " + previewSize.height); parameters.setPreviewSize(previewSize.width, previewSize.height); parameters.setRotation(rotate); camera.setParameters(parameters); camera.setPreviewDisplay(mHolder); camera.startPreview(); Log.d(TAG, "preview started"); started = true; } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } 

Echa un vistazo a esta solución

  public static void setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) { android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.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 == 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); } 
  • PhoneGap / Android - Bloqueo de la orientación al retrato
  • Cómo utilizar ExifInterface con una secuencia o un URI
  • Android configuración de la orientación de la actividad por código
  • Android Guardar imagen Exif Información goes Wrong in Marshmallow 6.0.1
  • Android: deshabilita las rotaciones de 90 °, pero permite rotaciones de 180 °
  • Habilitar la rotación de la pantalla android
  • Problema con la orientación de la imagen de Android en Motorola Droid
  • Android WebView: cómo gestionar los cambios de orientación
  • Los metadatos Exif no proporcionan orientación para las imágenes de unidades de Google
  • ¿Cómo puedo obtener la orientación actual de la pantalla?
  • Diferencia entre SCREEN_ORIENTATION_USER y SCREEN_ORIENTATION_SENSOR
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.