J'ai une application qui capture des photos en utilisant le Camera
natif, puis les télécharge sur un serveur. Mon problème est que toutes les photos ont une valeur d'orientation EXIF de 0, et cela gâche l'affichage ailleurs.
Comment puis-je changer l'orientation EXIF? Je ne cherche pas un moyen de le corriger pour chaque circonstance, il suffit de le changer pour une valeur différente.
J'utilise un Samsung Galaxy Note 4
J'ai essayé cette solution qui définit l'orientation de l'appareil photo avant de prendre des photos: Setting Android Photo EXIF Orientation
Camera c = Camera.open();
c.setDisplayOrientation(90);
Camera.Parameters params = mCamera.getParameters();
params.setRotation(0); // tried 0, 90, 180
c.setParameters(params);
mais cela n'influence pas les données EXIF résultantes, c'est toujours toujours 0
J'ai également essayé ces solutions où l'image est pivotée après avoir été prise: valeur de balise d'orientation EXIF toujours 0 pour l'image prise avec l'application appareil photo portrait Android
et tandis que cela fait pivoter la photo, l'orientation EXIF est toujours toujours 0.
J'ai également essayé de définir les données EXIF directement: Comment enregistrer les données Exif après la compression bitmap dans Android
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
final File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, "");
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
fos.write(data);
fos.close();
//upload photo..
}
}
}
mais l'orientation EXIF est toujours 0 après le téléchargement.
J'ai également examiné ces solutions:
données Exif TAG_ORIENTATION toujours
Comment écrire des données exif sur une image dans Android?
Comment obtenir l'orientation correcte de l'image sélectionnée dans la galerie d'images par défaut
comment régler l'orientation de l'image de la caméra?
mais ils impliquent tous de corriger l'orientation en tournant, ce qui n'influence pas les données EXIF, ou en définissant directement les données EXIF qui ne semblent pas fonctionner.
Comment puis-je changer les données d'orientation EXIF du fichier de 0 à 3?
MISE À JOUR:
voici mon code de téléchargement:
Bitmap sBitmap = null;
final File sResizedFile = getOutputMediaFile(MEDIA_TYPE_IMAGE, "_2");
try {
sBitmap = BitmapFactory.decodeStream(new FileInputStream(pictureFile), null, options);
} catch (FileNotFoundException e) {
Log.e("App", "[MainActivity] unable to convert pictureFile to bitmap");
e.printStackTrace();
return;
}
// ... compute sw and sh int values
Bitmap sOut = Bitmap.createScaledBitmap(sBitmap, sw, sh, false);
Bitmap rotatedBitmap = rotateBitmap(sOut, 3);
FileOutputStream sfOut;
try {
sfOut = new FileOutputStream(sResizedFile);
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 70, sfOut);
sfOut.flush();
sfOut.close();
sBitmap.recycle();
sOut.recycle();
rotatedBitmap.recycle();
} catch (Exception e) {
Log.e("App", "[MainActivity] unable to save thumbnail");
e.printStackTrace();
return;
}
// upload small thumbnail
TransferObserver sObserver = transferUtility.upload(
"stills/small", /* The bucket to upload to */
filename + ".jpg", /* The key for the uploaded object */
sResizedFile /* The file where the data to upload exists */
);
Il s'avère que mon code a pu définir les données EXIF, mais il existe une différence entre la façon dont Android interprète ces données et la façon dont iOS et Chrome sur un Mac ( où je vérifiais le fichier résultant) l'interprète.
C'est le seul code nécessaire pour définir l'orientation EXIF:
ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
Cependant, la définition de 3
apparaît comme 0
sur iOS et l'image est de côté dans Chrome.
réglage 6
apparaît comme 3
sur iOS et l'image apparaît correctement dans Chrome.
Comme vous pouvez le voir, les informations EXIF ne sont pas fiables sur Android (en particulier les appareils Samsung).
Cependant, la base de données SQL du téléphone contenant les références à l'objet Media est fiable. Je proposerais de suivre cette voie.
Obtenir l'orientation de l'Uri:
private static int getOrientation(Context context, Uri photoUri) {
Cursor cursor = context.getContentResolver().query(photoUri,
new String[]{MediaStore.Images.ImageColumns.ORIENTATION}, null, null, null);
if (cursor.getCount() != 1) {
cursor.close();
return -1;
}
cursor.moveToFirst();
int orientation = cursor.getInt(0);
cursor.close();
cursor = null;
return orientation;
}
Ensuite, initialisez le Bitmap
tourné:
public static Bitmap rotateBitmap(Context context, Uri photoUri, Bitmap bitmap) {
int orientation = getOrientation(context, photoUri);
if (orientation <= 0) {
return bitmap;
}
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
return bitmap;
}
Si vous souhaitez modifier l'orientation de l'image, essayez l'extrait de code suivant:
public static boolean setOrientation(Context context, Uri fileUri, int orientation) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.ORIENTATION, orientation);
int rowsUpdated = context.getContentResolver().update(fileUri, values, null, null);
return rowsUpdated > 0;
}
Si vous définissez l'orientation de l'image, plus tard, elle sera constamment réglée à l'orientation correcte. Il est nécessaire d'utiliser ExifInterface
plus tard, car l'image est déjà correctement tournée.
Si cette méthode n'est pas satisfaisante, vous pouvez essayer cette méthode
Vous avez accepté votre propre réponse comme solution. Ma diatribe est juste une info latérale utile, de toute façon ...
Le "Cependant ..." dans votre réponse suggère que si vous connaissez maintenant la cause, vous n'avez pas de solution.
Il s'avère que mon code a pu définir les données EXIF, mais il y a une différence entre la façon dont Android interprète ces données et comment iOS ... les interprète.
Cela pourrait être un problème d'endianité. Vous pouvez essayer de changer manuellement le paramètre d'endianness d'Exif en ouvrant votre jpeg dans un éditeur hexadécimal et en trouvant ...
45 78 69 66
(rend le texte "Exif") suivi de deux zéro octets 00 00
.49 49
(fait du texte "II") ce qui signifie lire les données au format peu endian.4D 4D
(ou texte "MM"), alors le côté lecture considérera les données comme un gros endian.Testez cela dans iOS pour voir si les chiffres sont maintenant corrects.
et à ce sujet ...
Cependant, la définition de
3
apparaît comme0
sur iOS et l'image est de côté dans Chrome.
Réglage6
apparaît comme3
sur iOS et l'image apparaît correctement dans Chrome.
La seule chose que je peux ajouter, c'est que iOS Mac est Big Endian * et Android/PC est Little Endian. Essentiellement, Little Endian lit/écrit des octets de droite à gauche tandis que Big Endian est opposé.
En binaire: 011
signifie et 110
signifie 6. La différence entre 3 et 6 est simplement l'ordre de lecture de ces bits de uns et de zéros. Donc, un système qui se lit comme zero-one-one
obtient un résultat de mais l'autre système Endian lira un octet avec les mêmes bits que one-one-zero
et vous dire que le résultat est un 6. Je ne peux pas expliquer pourquoi "3 apparaît comme 0" sans fichier de test pour analyser les octets mais c'est un résultat étrange pour moi.
</end rant>
<sleep>
* note : Bien que les Mac soient Big Endian, une double vérification indique qu'iOS utilise le système Little Endian après tout. Vos chiffres suggèrent toujours un problème Big vs Little Endian.
Il existe une classe pour lire et mettre à jour ces informations d'images.
Pour mettre à jour les attributs que vous pouvez utiliser comme ceci
ExifInterface ef = new ExifInterface(filePath);
ef.setAttribute(MAKE_TAG, MAKE_TAG);
ef.setAttribute(ExifInterface.TAG_ORIENTATION, orientation+"");
ef.saveAttributes();
et pour lire, vous pouvez utiliser comme ça
ExifInterface exif = null;
try {
exif = new ExifInterface(absolutePath+path);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
J'espère que cela vous aidera
Référez-vous à ce projet GitHub https://github.com/pandiaraj44/Camera . Il a l'activité de caméra personnalisée où EXIF TAG_ORIENTATION a été gérée correctement. Vous pouvez cloner le projet et vérifier. Pour plus de détails sur le code, reportez-vous https://github.com/pandiaraj44/Camera/blob/master/app/src/main/Java/com/pansapp/cameraview/CameraFragment.Java