Изображения, сделанные с помощью ACTION_IMAGE_CAPTURE, всегда возвращают 1 для ExifInterface.TAG_ORIENTATION на некоторых устройствах Gingerbread - PullRequest
40 голосов
/ 09 декабря 2011

У меня возникла проблема с ориентацией при работе с ACTION_IMAGE_CAPTURE активностью.Я использовал TAG_ORIENTATION, чтобы соответственно повернуть картинку.Но теперь мы обнаружили, что на некоторых новых устройствах это не работает.Фактически он возвращает 1 для всех ориентаций.

Вот список устройств, на которых мы наблюдали это;

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

Интересно то, что как только это изображение является галереей, оно отображается правильно, и если я его выберу, TAG_ORIENTATION заполняется правильно.Таким образом, OS правильно заполняет эту информацию, но не в ActivityResult.

Какой самый надежный способ определить ориентацию?Кто-то по другому вопросу предложил сравнить высоту и ширину, но при их получении они правильно переключаются в зависимости от ориентации (еще одна загадка)в галерее (предполагается, что изображение будет сохранено только в указанном нами URL-адресе), дело в том, что это изображение в галерее содержит информацию ORIENTATION, а изображение в указанном месте - нет.

Этоэто ошибка;http://code.google.com/p/android/issues/detail?id=19268

EDIT-2: Я отправил новую ошибку с Android.Я уверен, что это ошибка ОС, связанная с вышеупомянутой ошибкой.http://code.google.com/p/android/issues/detail?id=22822

Ответы [ 5 ]

53 голосов
/ 14 января 2012

Хорошо, ребята, похоже, что эта ошибка для Android не будет исправлена ​​некоторое время. Хотя я нашел способ реализовать ExifInformation так, чтобы оба устройства (те, которые имеют правильный тег Exif, а также неправильные теги exif работали вместе) ..

Таким образом, проблема возникает на некоторых (более новых) устройствах, есть ошибка, из-за которой сделанный снимок сохраняется в папке вашего приложения без надлежащих тегов exif, а правильно повернутое изображение сохраняется в папке по умолчанию для Android (хотя это не должно происходить). быть) ..

Теперь я записываю время запуска приложения камеры из моего приложения. Затем по результатам активности я запрашиваю медиа-провайдера, чтобы посмотреть, были ли какие-либо изображения сохранены после этой временной метки, которую я сохранил. Это означает, что, скорее всего, ОС сохранила правильно повернутое изображение в папке по умолчанию и, конечно, поместила запись в хранилище мультимедиа, и мы можем использовать информацию о повороте из этой строки. Теперь, чтобы убедиться, что мы смотрим на правильное изображение, я сравниваю размер этого файла с тем, к которому у меня есть доступ (сохранен в моей папке приложения);

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

Теперь, если вращение в этой точке все еще равно -1, то это означает, что это один из телефонов с правильной информацией о вращении. На этом этапе мы можем использовать обычную ориентацию exif для файла, который возвращается нашему onActivityResult

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

Вы можете легко узнать, как найти exif-ориентации, например, ответ на этот вопрос Проблема ориентации камеры в Android

Также обратите внимание, что ExifInterface поддерживается только после Api уровня 5. Поэтому, если вы хотите поддерживать телефоны до 2.0, то вы можете использовать эту удобную библиотеку, которую я нашел для любезности Java Drew Noakes; http://www.drewnoakes.com/code/exif/

Удачи в повороте изображения!

РЕДАКТИРОВАТЬ: Потому что его спросили, намерение, которое я использовал и как я начал, было так

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);
7 голосов
/ 26 октября 2013

Действительно проблемная ошибка! Я не уверен, что мне нравится предложенный обходной путь, так что вот еще:)

Ключ должен использовать EXTRA_OUTPUT и запрашивать его, когда изображение было снято! Очевидно, это работает, только если вы позволите себе указать имя файла.

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;
}
7 голосов
/ 27 августа 2012

вы тоже можете пойти по этому пути:

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);
    }
2 голосов
/ 16 октября 2014

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

Источник.

0 голосов
/ 29 марта 2017

Мое решение для этого. Проверено на мобильном телефоне LG G2. Я заметил, что когда я использую камеру и делаю новый снимок, все работает отлично. ExifInterface возвращает правильную ориентацию. Так что это должно быть что-то в пути, потому что мой путь был нулевым в этой строке кода:

exif = new ExifInterface(path);

но когда я использовал абсолютный путь, мое приложение зависало. Но решение в этом методе ниже, потому что это зависит от вашей версии SDK. Еще одно замечание: я использовал абсолютный путь только для выбора изображения галереи, потому что, если я использовал его для камеры, мое приложение зависало. Я новичок в программировании и просто потерял 2 дня, чтобы решить эту проблему. Надеюсь, это кому-нибудь поможет.

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

Итак, я получаю свой ExifInterface в методе 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()));
    }
}

и мой метод показа изображения выглядит следующим образом

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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...