Les images prises avec ACTION_IMAGE_CAPTURE renvoient toujours 1 pour ExifInterface.TAG_ORIENTATION sur certains périphériques plus récents

J'ai eu le problème d'orientation lorsque j'ai travaillé avec l'activité ACTION_IMAGE_CAPTURE . J'ai utilisé la TAG_ORIENTATION pour que je tourne l'image en conséquence. Mais maintenant, nous avons constaté que sur certains appareils nouveaux, cela ne fonctionne pas. En fait, il renvoie 1 pour toutes les orientations.

Voici la liste des appareils sur lesquels nous avons observé;

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

Une chose intéressante est que, une fois que cette image est la galerie, elle apparaît correctement et si je la sélectionne, la TAG_ORIENTATION est remplie correctement. Donc, de toute façon, l' OS remplit correctement cette information, mais pas sur ActivityResult .

Quelle est la façon la plus fiable de trouver l'orientation? Quelqu'un sur une autre question suggère de comparer la hauteur et la largeur, mais lors de leur obtention, ils sont correctement basés sur l'orientation (un autre mystère)

EDIT: Il semble que cela puisse être connecté à un autre bug où l'OS double l'image prise dans la galerie (il est seulement censé enregistrer l'image dans l'URL spécifiée par nous), la chose est que cette image dans la galerie a les informations ORIENTATION pendant Celui dans l'emplacement spécifié ne le fait pas.

C'est le bogue; Http://code.google.com/p/android/issues/detail?id=19268

EDIT-2: J'ai déposé un nouveau bug avec Android. Je suis assez sûr que ce soit un bug du système d'exploitation lié au bug précité. Http://code.google.com/p/android/issues/detail?id=22822

5 Solutions collect form web for “Les images prises avec ACTION_IMAGE_CAPTURE renvoient toujours 1 pour ExifInterface.TAG_ORIENTATION sur certains périphériques plus récents”

Ok gars, il semble que ce bogue pour Android ne sera pas réparé pendant un certain temps. Bien que j'ai trouvé un moyen de mettre en œuvre l'ExifInformation afin que les deux appareils (ceux avec une étiquette Exif appropriée, et aussi des étiquettes exif incorrectes fonctionnent ensemble).

Donc, le problème concerne certains périphériques (plus récents), il y a un bug qui rend l'image enregistrée dans le dossier de votre application sans les étiquettes exif appropriées alors qu'une image correctement tournée est enregistrée dans le dossier par défaut d'Android (même si cela ne devrait pas l'être). .

Maintenant, ce que je fais, je enregistre le moment où je démarre l'application de la caméra de mon application. Ensuite, lors du résultat de l'activité, j'interroge le Media Provider pour voir si des images ont été sauvegardées après cette horodatage que j'ai enregistrée. Cela signifie que, très probablement, le système d'exploitation a enregistré l'image correctement tournée dans le dossier par défaut et bien sûr, mettez une entrée dans le magasin multimédia et nous pouvons utiliser les informations de rotation de cette ligne. Maintenant, pour nous assurer que nous regardons la bonne image, je compare la taille de ce fichier à celui auquel j'ai accès (enregistré dans mon propre dossier d'application);

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

Maintenant, si la rotation à ce point est toujours -1, cela signifie que c'est l'un des téléphones avec des informations de rotation appropriées. À ce stade, nous pouvons utiliser l'orientation régulière exif sur le fichier qui est retourné à notre OnActivityResult

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

Vous pouvez facilement trouver comment trouver des orientations exif comme la réponse dans cette question problème d'orientation caméra en Android

Notez également que ExifInterface n'est pris en charge qu'après Api niveau 5 .. Donc, si vous souhaitez prendre en charge les téléphones avant 2.0, vous pouvez utiliser cette bibliothèque pratique que j'ai trouvée pour java grâce à Drew Noakes; http://www.drewnoakes.com/code/exif/

Bonne chance avec votre image en rotation!

EDIT: Parce qu'il a été demandé, l'intention que j'ai utilisée et la façon dont j'ai commencé était comme ça

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

Vous pouvez aller de cette façon aussi:

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

En effet, un bug problématique! Je ne suis pas sûr d'avoir aimé la solution de contournement proposée, alors voici un autre 🙂

La clé est d'utiliser EXTRA_OUTPUT et de l'interroger lorsque l'image a été capturée! Évidemment, cela ne fonctionne que si vous vous permettez de spécifier le nom de fichier.

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

Ce que j'ai appris récemment, c'est que si vous redimensionnez l'image, il perd généralement ses informations EXIF. Vous souhaitez donc donner au nouveau fichier les anciennes informations EXIF.

La source.

Ma solution pour cela. Testé sur LG G2 mobile. J'ai remarqué que lorsque j'utilise la caméra et je prends une nouvelle photo, tout fonctionne bien. ExifInterface retourne l'orientation à droite. Il doit donc s'agir de quelque chose sur le chemin car mon chemin était nul dans cette ligne de code:

 exif = new ExifInterface(path); 

Mais quand j'ai utilisé le chemin absolu de ma capture d'application. Mais la solution se trouve dans cette méthode ci-dessous, car cela dépend de votre version sdk. Une note de plus à mentionner que j'ai utilisé le chemin absolu uniquement pour sélectionner l'image de la galerie, car si je l'utilisais pour la caméra, ma application s'est écrasée. Je suis nouveau dans la programmation et j'ai perdu 2 jours pour résoudre ce problème. J'espère que cela aidera quelqu'un.

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

Donc, je reçois mon ExifInterface dans la méthode OnActivityResult

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

Et ma méthode d'image de spectacle ressemble à celle-ci

 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(); } } 
coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.