Camera setDisplayOrientation () en el modo de retrato rompe la relación de aspecto
Estoy intentando que las previsualizaciones de la cámara funcionen correctamente en el modo vertical, donde la actividad en sí se le permite cambiar la orientación normalmente (es decir, no se bloquea en el paisaje).
El uso de setDisplayOrientation()
rompe seriamente el comportamiento de las previsualizaciones, sin embargo.
- Camera.setPreviewDisplay () lanza Exception
- Camerainfo.orientation da una respuesta equivocada
- android mudo sonido de obturador de la cámara?
- Cámara Android setJpegQuality ignorado
- Manera correcta de calcular el mejor tamaño de vista previa de la cámara
Esto puede ser demostrado por el propio ApiDemos de Google. La primera imagen se basa en CameraPreview
de la edición android-17
del proyecto de ejemplo de ApiDemos
, donde el único cambio que hice fue eliminar android:orientation="landscape"
de la entrada de esta actividad en el manifiesto. La siguiente imagen es una captura de pantalla de lo que aparece en la pantalla de un Nexus 4, con Android 4.2, con la cámara apuntando a un papel de 8,5 ":
Lo que no es obvio de esa vista previa es que se gira 90 grados. Los pies vestidos de calcetín que ves en la extrema derecha de la imagen estaban realmente debajo del cuadrado.
La solución para esto, al menos para el modo horizontal, es usar setDisplayOrientation()
. Pero, si modifica la clase interna Preview
de CameraPreview
para que mCamera.setDisplayOrientation(90);
, usted consigue esto:
En particular, el cuadrado ya no es cuadrado.
Esto utiliza el mismo tamaño de SurfaceView
que antes. He reproducido este escenario con algún otro código, fuera de ApiDemos
, y obtengo el mismo comportamiento con TextureView
en ese código.
Pensé brevemente que el problema podría ser que getSupportedPreviewSizes()
podría devolver valores diferentes basados en setDisplayOrientation()
, pero una prueba rápida sugiere que este no es el caso.
Alguien tiene alguna idea de cómo obtener setDisplayOrientation()
para trabajar en modo retrato sin destruir la relación de aspecto de las imágenes empujadas a la vista previa?
¡Gracias!
- Cómo obtener los datos RGB sin procesar de la cámara Android
- Android - Cómo recortar la previsualización de la cámara con TextureView
- Phonegap / Cordova cámara plugin - cómo obtener la fecha de la foto / hora?
- Cómo obtener id de la cámara frente a frente con Camera2?
- ¿Cómo se relacionan las devoluciones de llamada de SurfaceHolder con el ciclo de vida de la actividad?
- Uso de la cámara LED Flash con OpenCV en Android
- Cámara en modo Burst en Android, que puede tomar varias imágenes
- androide muestran rectángulo en la cámara
OK, creo que me di cuenta de esto. Había algunas piezas en el rompecabezas proverbial, y le agradezco @ kcoppock por la visión que me ayudó a resolver algo de esto.
En primer lugar, debe tener en cuenta la orientación al determinar qué tamaño de vista previa elegir. Por ejemplo, el getOptimalPreviewSize()
de CameraPreview
de ApiDemos
es ajeno a la orientación, simplemente porque su versión de esa aplicación tiene la orientación bloqueada en el paisaje. Si desea dejar flotar la orientación, debe invertir la relación de aspecto de destino para que coincida. Por lo tanto, donde getOptimalPreviewSize()
tiene:
double targetRatio=(double)width / height;
también necesitas:
if (displayOrientation == 90 || displayOrientation == 270) { targetRatio=(double)height / width; }
donde displayOrientation
es un valor de 0 a 360, que estoy determinando a partir de unas 100 líneas de algún código seriamente feo, por lo que estoy envolviendo todo esto en un componente reutilizable que publicaré en breve. Ese código se basa en el setDisplayOrientation()
JavaDocs y esta respuesta StackOverflow .
(BTW, si usted está leyendo esto después del 1 de julio 2013, y usted no ve un acoplamiento en esta respuesta a ese componente, publicar un comentario para recordarme, como lo olvidé)
En segundo lugar, debe tener en cuenta esa orientación de pantalla al controlar la relación de aspecto del SurfaceView
/ TextureView
que está utilizando. La actividad de ApiDemos
de ApiDemos
tiene su propio Preview
ViewGroup
que maneja la relación de aspecto, y allí es necesario invertir la relación de aspecto para usar en el retrato:
if (displayOrientation == 90 || displayOrientation == 270) { previewWidth=mPreviewSize.height; previewHeight=mPreviewSize.width; } else { previewWidth=mPreviewSize.width; previewHeight=mPreviewSize.height; }
donde displayOrientation
es el mismo valor ( 90
y 270
son retrato y retro-retrato respectivamente, y tenga en cuenta que no he intentado conseguir retroceso-retrato o reverso-paisaje para trabajar, por lo que puede ser más ajustes requeridos).
En tercer lugar – y uno que me parece irritante – debe iniciar la vista previa antes de llamar a setPictureSize()
en el Camera.Parameters
. De lo contrario, es como si la relación de aspecto de la imagen se aplica a los marcos de vista previa, atornillar las cosas.
Así que solía tener código similar al siguiente:
Camera.Parameters parameters=camera.getParameters(); Camera.Size pictureSize=getHost().getPictureSize(parameters); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); parameters.setPictureSize(pictureSize.width, pictureSize.height); parameters.setPictureFormat(ImageFormat.JPEG); camera.setParameters(parameters); camera.startPreview();
y eso está mal. Lo que realmente necesita es:
Camera.Parameters parameters=camera.getParameters(); Camera.Size pictureSize=getHost().getPictureSize(parameters); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); camera.setParameters(parameters); camera.startPreview(); parameters=camera.getParameters(); parameters.setPictureSize(pictureSize.width, pictureSize.height); parameters.setPictureFormat(ImageFormat.JPEG); camera.setParameters(parameters);
Sin ese cambio, obtendría una relación de aspecto estirada, incluso en el paisaje. Esto no fue un problema para CameraPreview
de ApiDemos
, ya que no estaban tomando fotos, y por eso nunca llamaron setPictureSize()
.
Pero, hasta ahora, en un Nexus 4, ahora tengo proporciones de aspecto cuadrado para el retrato y el paisaje, con una orientación flotante (es decir, no bloqueado al paisaje).
Voy a tratar de recordar para corregir esta pregunta si me encuentro con otros hacks requeridos por otros dispositivos, además de vincular a mi CameraView
/ CameraFragment
componentes cuando se liberan.
ACTUALIZACIÓN # 1
Bueno, por supuesto, no podría ser casi tan simple. Todos los derechos reservados
La solución para el problema donde setPictureSize()
atornilla la relación de aspecto funciona … hasta que usted toma una imagen. En ese momento, la vista previa cambia a la relación de aspecto incorrecta.
Una posibilidad sería limitar las imágenes a las que tienen la misma relación de aspecto (o muy cerca) con la vista previa, por lo que el hipo no existe. No me gusta esa respuesta, ya que el usuario debe ser capaz de obtener el tamaño de imagen que la cámara ofrece.
Puede limitar el alcance del daño mediante:
- Sólo actualizar el tamaño de la imagen, etc de la
Camera.Parameters
antes de tomar la foto - Revertir a la
Camera.Parameters
antes de tomar fotografías.Parameters después de tomar la foto
Esto todavía presenta la relación de aspecto incorrecta durante los momentos mientras se toma la fotografía. La solución a largo plazo para este – creo – será reemplazar temporalmente la vista previa de la cámara con una imagen fija (el último marco de vista previa) mientras se toma la foto. Lo intentaré eventualmente.
UPDATE # 2 : v0.0.1 de mi CWAC-Cámara de la biblioteca está ahora disponible, incorporando el citado código.
Ok chicos, me estaba volviendo loco las últimas dos semanas sobre este problema f * * *. tan bien, pocas cosas que saber:
- A veces solo obtienes bordes negros , si la barra de acción o botones suaves son visibles, lo más posible en algunos dispositivos, mi consejo: * no te preocupes * o te volverás loco, o cortar vistas previas, ambas no buenas …
los cambios de @CommonsWare son simplemente perfectos, pero no se pueden aplicar directamente a la vista de cámara desde las muestras API Level 8 (enlace a continuación), así que aquí está el diff :
para la relación de aspecto correcta en retrato hacer:
los métodos son los mismos, sólo aplique diff
public void setCamera(Camera camera, boolean portrait) { mCamera = camera; this.portrait = portrait; if (mCamera != null) { mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes(); requestLayout(); } } public void switchCamera(Camera camera, boolean portrait) throws IOException { setCamera(camera, portrait); camera.setPreviewDisplay(mHolder); Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); requestLayout(); camera.setParameters(parameters); }
en:
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) {…}
cambio:
int previewWidth = width; int previewHeight = height; if (mPreviewSize != null) { previewWidth = mPreviewSize.width; previewHeight = mPreviewSize.height; }
a:
if (portrait && mPreviewSize != null) { previewWidth = mPreviewSize.height; previewHeight = mPreviewSize.width; } else if (mPreviewSize != null){ previewWidth = mPreviewSize.width; previewHeight = mPreviewSize.height; }
en:
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {…}
cambio:
double targetRatio = (double) w / h;
a:
double targetRatio = 1; if (portrait) { targetRatio= (double) w / h; }
finalmente comenzando la cámara para el modo de retrato con algo como:
try { mCamera = openFrontFacingCameraGingerbread(); if (portraitMode) { mCamera.setDisplayOrientation(90); } preview.setCamera(mCamera, portraitMode); } catch (Exception e) { e.printStackTrace(); handleCameraUnavailable(); }
WUUHUUUU! Para mí, finalmente, ni problemas en la vista previa, y no hay problemas en el ahorro de imágenes. Debido a que mi ubicación de actividad está bloqueada, obtengo la orientación de la pantalla a través de OrientationChangedListener para guardar imágenes con la orientación correcta.
usando algo como:
http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html
Pero se prevé y se guardan correctamente.
Espero poder ayudar a mucha gente con eso, no es el código original de API Nivel 8 :
https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java donde se aplicaron los cambios.
Por favor, cambie la orientación de la cámara en su código y debe setDisplayorientation()
not getDisplayOrientation()
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) { camera.setDisplayOrientation(0); }
- ¿Cómo eliminar el certificado instalado por el usuario mediante programación?
- Common Header en diferentes actividades utilizando BaseActivity en android