Данные Android EXIF всегда 0, как их изменить?

у меня есть приложение, которое захватывает фотографии с помощью уроженца Camera и затем загружает их на сервер. Моя проблема в том, что все фотографии имеют значение ориентации EXIF 0, и это портит дисплей в другом месте.

как я могу изменить ориентацию EXIF? Я не ищу способ исправить это для каждого обстоятельства, просто измените его на другое значение.

Я использую Samsung Galaxy Note 4

Я пробовал это решение, которое устанавливает камеру ориентация перед фотографированием:настройка ориентации Android Photo EXIF

Camera c = Camera.open();
c.setDisplayOrientation(90);

Camera.Parameters params = mCamera.getParameters();
params.setRotation(0); // tried 0, 90, 180
c.setParameters(params);

но это не влияет на результирующие данные EXIF, его все еще всегда 0

Я также пробовал эти решения, где изображение поворачивается после того, как оно принято:значение тега ориентации EXIF всегда 0 для изображения, сделанного с помощью приложения портретной камеры android

и пока это вращает фотографию, ориентация EXIF по-прежнему всегда равна 0.

Я тоже попробовал установить данные EXIF напрямую:как сохранить данные Exif после сжатия растрового изображения в 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..
        }
    }
}

но ориентация EXIF по-прежнему равна 0 после загрузки.

Я тоже посмотрел на эти решения:

Exif data TAG_ORIENTATION всегда 0

как записать данные exif в изображение в Android?

как получить правильную ориентацию изображения, выбранного по умолчанию Галерея изображений

как установить ориентацию изображения камеры?

но все они включают в себя корректировку ориентации путем вращения, что не влияет на данные EXIF, или установку данных EXIF напрямую, что, похоже, не работает.

как изменить данные ориентации EXIF файла с 0 на 3?

обновление:

вот мой код загрузки:

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

5 ответов


как вы можете видеть, информация EXIF не является надежной на Android (особенно на устройствах Samsung).

однако база данных SQL телефона, содержащая ссылки на медиа-объект, является надежной. Я бы предложил пойти этим путем.

получение ориентации от 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;
}

затем инициализировать повернуты Bitmap:

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

если вы хотите изменить ориентацию изображения, попробуйте следующий фрагмент:

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

если вы установите ориентацию изображения, позже она будет постоянно устанавливаться на правильную ориентацию. Существует необходимость использовать ExifInterface позже, потому что изображение уже повернуто надлежащим образом.

если этот метод не является удовлетворительным, то вы можете попробовать этот метод


оказывается, мой код смог установить данные EXIF, но есть расхождение между тем, как Android интерпретирует эти данные и как iOS и Chrome на Mac (где я проверял результирующий файл) интерпретирует его.

Это единственный код, необходимый для установки ориентации EXIF:

ExifInterface exif = new ExifInterface(pictureFile.toString());
exif.setAttribute(ExifInterface.TAG_ORIENTATION, "3");
exif.saveAttributes();
установка 3 показывает 0 на iOS и изображение боком в Chrome.

задание 6 показывает 3 на iOS и изображение выглядит прямо в Хром.


вы приняли свой собственный ответ, как решение. Моя тирада-просто полезная побочная информация...

на (делает текст "II"), что означает чтение данных в формате little endian.

  • если вы замените его с 4D 4D (или текст "мм") затем сторона чтения рассмотрим данные как big endian.
  • проверьте это в iOS, чтобы узнать, теперь цифры верны.

    и относительно этого...

    установка 3 показывает0 на iOS и изображение сбоку в Хром.
    Настройка 6 показывает 3 на iOS и изображение выглядит прямо в Chrome.

    единственное, что я могу добавить это iOS Mac это Большой Endian* и Android / PC является Рода. По существу Маленький Эндиан читает / записывает байты справа налево, в то время как большой Эндиан противоположен.

    в двоичном виде : 011 означает 3 и 110 означает 6. Разница между 3 и 6-это просто порядок чтения этих битов единиц и нулей. Итак, система, которая читается как zero-one-one получает результат 3 но другой системы с обратным порядком байтов будет читать байт с таким же биты как one-one-zero и скажу вам, результат -6. Я не могу объяснить почему "3 отображается как 0" без тестового файла для анализа байтов, но это странный результат для меня.

    </end rant>
    <sleep>

    *Примечание: в то время как Mac-большие Endian, двойная проверка говорит, что iOS использует маленькую систему Endian в конце концов. Ваши цифры по-прежнему предполагают большую и маленькую проблему Endian.


    обратитесь к этому проекту GitHubhttps://github.com/pandiaraj44/Camera. Он имеет пользовательскую активность камеры, где EXIF TAG_ORIENTATION был обработан правильно. Вы можете клонировать проект и проверить. Для деталей кода пожалуйста см. https://github.com/pandiaraj44/Camera/blob/master/app/src/main/java/com/pansapp/cameraview/CameraFragment.java


    существует один класс для чтения и обновления этой информации изображений.

    чтобы обновить атрибуты, которые вы можете использовать, как это

    ExifInterface ef = new ExifInterface(filePath);
                ef.setAttribute(MAKE_TAG, MAKE_TAG);
                ef.setAttribute(ExifInterface.TAG_ORIENTATION, orientation+"");
                ef.saveAttributes();
    

    и для чтения вы можете использовать такой

     ExifInterface exif = null;
            try {
                exif = new ExifInterface(absolutePath+path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED);
    

    Я надеюсь, что это поможет вам