web-dev-qa-db-fra.com

Android EXIF ​​data toujours 0, comment le changer?

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 */
);
23
Cbas

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.

10
Cbas

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

19
R. Zagórski

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 ...

  • Les octets 45 78 69 66 (rend le texte "Exif") suivi de deux zéro octets 00 00.
  • Alors ça devrait être 49 49 (fait du texte "II") ce qui signifie lire les données au format peu endian.
  • Si vous le remplacez par 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églage 6 apparaît comme 3 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.

10
VC.One

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

3
Jitty Aandyan

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

3
Pandiarajan