android orientation exif image-capture

android - Las imágenes tomadas con ACTION_IMAGE_CAPTURE siempre devuelven 1 para ExifInterface.TAG_ORIENTATION en algunos dispositivos más nuevos



image-capture (5)

Tuve el problema de orientación al trabajar con la actividad ACTION_IMAGE_CAPTURE . He usado TAG_ORIENTATION para rotar la imagen en consecuencia. Pero ahora descubrimos que en algunos dispositivos más nuevos esto no funciona. De hecho, devuelve 1 para todas las orientaciones.

Aquí está la lista de dispositivos en que observamos esto;

  • Samsung Infuse 4G (2.3.3)
  • Samsung Galaxy SII X (2.3.5)
  • Sony Xperia Arc (2.3.3)

Lo interesante es que una vez que esta imagen es la galería, se muestra correctamente y, si la selecciono, TAG_ORIENTATION se llena correctamente. De alguna manera, el OS llena esta información correctamente, pero no en ActivityResult .

¿Cuál es la forma más confiable de calcular la orientación? Alguien en otra pregunta sugirió comparar la altura y el ancho, pero al obtener estos, se cambian correctamente en función de la orientación (otro misterio)

EDITAR: Parece que esto podría estar conectado a otro error donde el sistema operativo duplica la imagen tomada en la galería (se supone que solo debe guardar la imagen en la URL especificada por nosotros), el hecho es que esta imagen en la galería tiene la información ORIENTATION mientras el que está en la ubicación especificada no.

Este es el error; http://code.google.com/p/android/issues/detail?id=19268

EDIT-2: He archivado un nuevo error con Android. Estoy bastante seguro de que esto es un error del sistema operativo relacionado con el error mencionado. http://code.google.com/p/android/issues/detail?id=22822


Bien chicos, parece que este error para Android no se solucionará por un tiempo. Aunque encontré una forma de implementar ExifInformation para que ambos dispositivos (los que tienen la etiqueta Exif adecuada y también las etiquetas exif incorrectas funcionen juntos) ...

Así que el problema está en algunos dispositivos (más nuevos), hay un error que hace que la foto se guarde en la carpeta de la aplicación sin las etiquetas exif correctas, mientras que una imagen girada correctamente se guarda en la carpeta predeterminada de Android (aunque no debería ser así). .

Ahora lo que hago es registrar el tiempo en el que estoy iniciando la aplicación de la cámara desde mi aplicación. Luego del resultado de la actividad, consulto al proveedor de medios para ver si se guardaron algunas imágenes después de esta marca de tiempo que guardé. Eso significa que, muy probablemente, el SO guardó la imagen rotada correctamente en la carpeta predeterminada y, por supuesto, puso una entrada en el almacén de medios y podemos usar la información de rotación de esta fila. Ahora, para asegurarnos de que estamos viendo la imagen correcta, comparo el tamaño de este archivo con el que tengo acceso (guardado en mi propia carpeta de aplicaciones);

int rotation =-1; long fileSize = new File(filePath).length(); Cursor mediaCursor = content.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[] {MediaStore.Images.ImageColumns.ORIENTATION, MediaStore.MediaColumns.SIZE }, MediaStore.MediaColumns.DATE_ADDED + ">=?", new String[]{String.valueOf(captureTime/1000 - 1)}, MediaStore.MediaColumns.DATE_ADDED + " desc"); if (mediaCursor != null && captureTime != 0 && mediaCursor.getCount() !=0 ) { while(mediaCursor.moveToNext()){ long size = mediaCursor.getLong(1); //Extra check to make sure that we are getting the orientation from the proper file if(size == fileSize){ rotation = mediaCursor.getInt(0); break; } } }

Ahora, si la rotación en este punto todavía es -1, significa que este es uno de los teléfonos con la información de rotación adecuada. En este punto, podemos usar la orientación exif regular en el archivo que se devuelve a nuestro onActivityResult

else if(rotation == -1){ rotation = getExifOrientationAttribute(filePath); }

Puede encontrar fácilmente cómo encontrar orientaciones exif como la respuesta en esta pregunta Problema de orientación de la cámara en Android

También tenga en cuenta que ExifInterface solo es compatible después del nivel 5 de Api. Por lo tanto, si desea admitir teléfonos anteriores a 2.0, puede utilizar esta útil biblioteca que he encontrado para Java cortesía de Drew Noakes; http://www.drewnoakes.com/code/exif/

¡Buena suerte con tu imagen girando!

EDITAR: Debido a que se me preguntó, la intención que he usado y cómo comencé fue así

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //mediaFile is where the image will be saved intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile)); startActivityForResult(intent, 1);


De hecho, un error problemático! No estoy seguro de que me guste la solución sugerida, así que aquí hay otra :)

¡La clave es usar EXTRA_OUTPUT y consultarla cuando la imagen ha sido capturada! Obviamente, esto solo funciona si te permites especificar el nombre del archivo.

protected void takePictureSequence() { try { ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.TITLE, UUID.randomUUID().toString() + ".jpg"); newPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, newPhotoUri); startActivityForResult(intent, ActivityResults.TAKE_NEW_PICTURE_RESULT); } catch (Exception e) { Toast.makeText(this, R.string.could_not_initalize_camera, Toast.LENGTH_LONG).show(); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == ActivityResults.TAKE_NEW_PICTURE_RESULT) { if (resultCode == RESULT_OK) { try { String[] projection = { MediaStore.Images.Media.DATA }; CursorLoader loader = new CursorLoader(this, newPhotoUri, projection, null, null, null); Cursor cursor = loader.loadInBackground(); int column_index_data = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); // Rotation is stored in an EXIF tag, and this tag seems to return 0 for URIs. // Hence, we retrieve it using an absolute path instead! int rotation = 0; String realPath = cursor.getString(column_index_data); if (realPath != null) { rotation = ImageHelper.getRotationForImage(realPath); } // Now we can load the bitmap from the Uri, using the correct rotation. } } catch (Exception e) { e.printStackTrace(); } } } public int getRotationForImage(String path) { int rotation = 0; try { ExifInterface exif = new ExifInterface(path); rotation = (int)exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)); } catch (IOException e) { e.printStackTrace(); } return rotation; }


Lo que aprendí recientemente es que si cambia el tamaño de la imagen, generalmente pierde su información EXIF. Entonces quiere darle al archivo nuevo la información EXIF ​​anterior.

Source.


Mi solución para esto Probado en el móvil LG G2. Noté que cuando uso la cámara y tomo una nueva imagen todo funciona bien. ExifInterface devuelve la orientación correcta. Entonces debe ser algo en el camino porque mi camino era nulo en esta línea de código:

exif = new ExifInterface(path);

pero cuando utilicé la ruta absoluta, mi aplicación se bloqueó. Pero la solución está en este método a continuación, porque depende de su versión sdk. Una nota más mencionar que utilicé la ruta absoluta solo para seleccionar la imagen de la galería porque si la utilicé para la cámara, mi aplicación se bloqueó. Soy nuevo en la programación y acabo de perder 2 días para resolver esto. Espero que ayude a alguien.

public String getRealPathFromURI(Uri uri) { if(Build.VERSION.SDK_INT >= 19){ String id = uri.getLastPathSegment().split(":")[1]; final String[] imageColumns = {MediaStore.Images.Media.DATA }; final String imageOrderBy = null; Uri tempUri = getUri(); Cursor imageCursor = getContentResolver().query(tempUri, imageColumns, MediaStore.Images.Media._ID + "="+id, null, imageOrderBy); if (imageCursor.moveToFirst()) { return imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA)); }else{ return null; } }else{ String[] projection = { MediaStore.MediaColumns.DATA }; Cursor cursor = getContentResolver().query(uri, projection, null, null, null); if (cursor != null) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } else return null; } }

Así que obtengo mi ExifInterface en el método de prueba de actividad

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == GALLERY_IMAGE_REQUEST && resultCode == RESULT_OK && data != null) { try { exif = new ExifInterface(getRealPathFromURI(data.getData())); } catch (IOException e) { e.printStackTrace(); } showImage(data.getData()); } else if (requestCode == CAMERA_IMAGE_REQUEST && resultCode == RESULT_OK) { try { exif = new ExifInterface(Uri.fromFile(getCameraFile()).getPath()); } catch (IOException e) { e.printStackTrace(); } showImage(Uri.fromFile(getCameraFile())); } }

y mi método de imagen de espectáculo se ve así

public void showImage(Uri uri) { if (uri != null) { try { Bitmap bitmap = scaleBitmapDown(MediaStore.Images.Media.getBitmap(getContentResolver(), uri), IMAGE_SIZE); int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); bitmap = rotateBitmap(bitmap, orientation); if (whatPlayer.equals("Player1")) { mImagePlayer1.setImageBitmap(bitmap); bitmapPlayer1 = bitmap; //*save picture in static variable so other activity can use this } if (whatPlayer.equals("Player2")) { mImagePlayer2.setImageBitmap(bitmap); bitmapPlayer2 = bitmap; } } catch (IOException e) { Log.d(TAG, "Image picking failed because " + e.getMessage()); Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show(); } } else { Log.d(TAG, "Image picker gave us a null image."); Toast.makeText(this, R.string.image_picker_error, Toast.LENGTH_LONG).show(); } }


usted puede ir de esta manera también:

Matrix matrix = new Matrix(); // rotate the Bitmap (there a problem with exif so we''ll query the mediaStore for orientation Cursor cursor = getApplicationContext().getContentResolver().query(selectedImage, new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null); if (cursor.getCount() == 1) { cursor.moveToFirst(); int orientation = cursor.getInt(0); matrix.preRotate(orientation); }