Подтвердить что ты не робот

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

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

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

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

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

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 для изображения, сделанного с помощью приложения для портфолио с вертикальной камерой

и пока это поворачивает фотографию, ориентация 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 ​​Orientation по-прежнему 0 после загрузки.

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

Данные Exif TAG_ORIENTATION всегда 0

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

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

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

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

Как я могу изменить данные ориентации EXIF ​​файла от 0 до 3?

UPDATE:

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

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

Ответ 1

Оказывается, мой код смог установить данные 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, и изображение выглядит правильно в Chrome.

Ответ 2

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

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

Получение ориентации из 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 позже, потому что изображение уже повернуто соответствующим образом.

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

Ответ 3

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

"Однако..." в вашем ответе подсказывает, что теперь вы знаете причину, у вас нет исправления.

Оказывается, мой код смог установить данные EXIF, но есть несоответствие между тем, как Android интерпретирует эти данные и как iOS... интерпретирует его.

Это может быть проблема с эндитантностью. Вы можете вручную изменить настройку endianness в Exif, открыв jpeg в шестнадцатеричном редакторе и обнаружив...

  • Байт 45 78 69 66 (делает текст "Exif" ), за которым следуют два нуля байта 00 00.
  • Тогда это должно быть 49 49 (делает текст "II" ), что означает чтение данных как минимальный формат.
  • Если вы замените его текстом 4D 4D (или "ММ" ), то сторона чтения будет рассматривать данные как большие endian.

Проверьте это в iOS, чтобы узнать, правильны ли числа.

4Km4H.png

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

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

Единственное, что я могу добавить, это то, что iOS Mac Big Endian *, а Android/ПК - Маленький Endian. По сути, Little Endian читает/записывает байты как справа налево, в то время как Big Endian противоположна.

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

</end rant>
<sleep>

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

Ответ 4

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

Ответ 5

Существует один класс для чтения и обновления данных изображений.

Чтобы обновить атрибуты, которые можно использовать следующим образом

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

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