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

Резюме: сделайте снимок с использованием намерения камеры и отобразите фотографию с правильной ориентацией (работает, надеюсь, на все устройства)

Кажется, это самая простая вещь в мире: сделайте снимок в своем приложении для Android, используя активность камеры по умолчанию. Тем не менее, есть много ошибок, которые покрываются несколькими сообщениями в StackOverflow и в Интернете, поскольку, например, Null Intents передаются обратно, ориентация изображения не правильная или OutOfMemoryErrors.

Я ищу решение, которое позволяет мне

  • запустите действие камеры с помощью намерения камеры,
  • получить Uri фотографии и
  • получить правильную ориентацию фотографии.

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

4b9b3361

Ответ 1

ОБНОВЛЕНИЕ: 2 января 2014 года: Я очень старался избегать реализации различных стратегий на основе производителя устройства. К сожалению, я не обошел это. Просматривая сотни сообщений и беседуя с несколькими разработчиками, никто не нашел решение, которое работает на всех устройствах без использования специального кода производителя.

После того, как я разместил свое решение здесь на StackOverflow, некоторые разработчики попросили меня опубликовать мой код на github. Итак, вот он: AndroidCameraUtil on github

Код был успешно протестирован на самых разных устройствах с Android API-Level >= 8. Полный список см. в файле Readme на github.

CameraIntentHelperActivity предоставляет основную функциональность, которая также более подробно описана ниже.

Вызов активности камеры по умолчанию:

  • для устройств Samsung и Sony: я вызываю действие камеры с вызовом метода startActivityForResult. Я устанавливаю константу CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE. Я НЕ устанавливаю никаких других намерений.
  • для всех других устройств: я вызываю действие камеры с вызовом метода startActivityForResult, как и ранее. Однако на этот раз я дополнительно установил намерение дополнительного MediaStore.EXTRA_OUTPUT и предоставил URI, где я хочу, чтобы изображение было сохранено.

В обоих случаях я помню время начала работы камеры.


Результат работы камеры:

  • Mediastore: Во-первых, я пытаюсь прочитать фотографию, снятую с MediaStore. Используя mangedQuery в контенте MediaStore, я извлекаю последнее взятое изображение, а также его свойство ориентации и его метку времени. Если я найду изображение, и оно не было принято до того, как было вызвано намерение камеры, это изображение, которое я искал. В противном случае я отклоняю результат и пробую один из следующих способов.
  • Intent extra: Во-вторых, я пытаюсь получить изображение Uri from intent.getData() возвращаемого намерения. Если это тоже не удастся, я продолжаю с шага 3.
  • По умолчанию фото Uri: Если все вышеперечисленные шаги не работают, я использую изображение Uri, которое я передал в действие камеры.

В этот момент я получил фотографию Uri и ее ориентацию, которые я передал в свою UploadPhotoActivity.


Обработка изображений

Пожалуйста, внимательно ознакомьтесь с моим классом BitmapHelper. Он основан на коде, подробно описанном в в этом учебнике.

Кроме того, метод shrinkBitmap также поворачивает изображение, если требуется, на основе информации о ориентации, извлеченной ранее.


Надеюсь, это поможет некоторым из вас.

Ответ 2

Я тестировал этот код с помощью Sony Xperia Go, Samsung Galaxy SII, Samsung Galaxy SIII mini и Samsung Galaxy Y, который работал на всех устройствах.

Но на LG E400 (2.3.6) он не работал, и вы получаете двойные снимки в галерее. Поэтому я добавил файл manufacturer.contains( "lge" ) в void startCameraIntent(), и он исправил проблему.

if(!(manufacturer.contains("samsung")) && !(manufacturer.contains("sony")) && !(manufacturer.contains("lge"))) {
    String filename = System.currentTimeMillis() + ".jpg";
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, filename);
    cameraPicUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPicUri);
}

Ответ 3

На галактике S3 с CM 10.1 я получаю исключение nullpointer в BitmapHelper:

bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);

впоследствии моя функция UploadPhotoActivity завершится неудачей:

    try {
        photo = BitmapHelper.readBitmap(this, cameraPicUri);
        if (photo != null) {
            photo = BitmapHelper.shrinkBitmap(photo, 600, rotateXDegrees);
            thumbnail = BitmapHelper.shrinkBitmap(photo, 100);
            ImageView imageView = (ImageView) findViewById(R.id.sustainable_action_photo);
            imageView.setImageBitmap(photo);                
        } else {
            Log.e(TAG,"IMAGE ERROR 1");
        }
    } catch (Exception e) {
            Log.e(TAG,"IMAGE ERROR 2");
        e.printStackTrace();
    }

во втором журнале (ОШИБКА ИЗОБРАЖЕНИЯ 2). После нескольких попыток моя камера сломалась, и я получил "Не могу подключиться к камере" -error.

Протестировал его на связке 7 и отлично работает.

Изменить: сузилось до этого:

fileDescriptor = context.getContentResolver(). openAssetFileDescriptor (selectedImage, "r" );

Хотя selectedImage содержит это:

Файл:///storage/emulated/0/DCIM/Camera/IMG_20131023_183343.jpg

ФайлDescriptor возвращает исключение FileNotFoundException. Я проверил файловую систему, и изображение не сохраняется в этом месте. CameraPicUri в TakePhotoActivity указывает на несуществующий образ. Я в настоящее время проверяю, где все идет не так.

Edit2: Я понял ошибку: поскольку устройство является Samsung и сообщает App, что это устройство Samsung, применяются ваши конкретные исправления для вашего Samsung. Однако Cyanogenmod не нуждается в этих исправлениях, и, в конце концов, код ломается. Как только вы удалите

(manufacturer.contains( "samsung" )) &&

Это работает. Поскольку это пользовательский ПЗУ, вы не могли планировать это, конечно. Я пытаюсь найти способ определить, работает ли устройство cyanogenmod, а затем включить его в свой код.

Спасибо за хорошее исправление камеры!

Edit3: Я исправил его для запуска на Cyanogenmod на Galaxy S3, изменив код на это: Ну, теперь это иногда работает, иногда это не так. Странно.

if (getPackageManager(). hasSystemFeature ( "com.cyanogenmod.android" ) || (! (производитель .contains( "samsung" )) & &! (manufacturer.contains( "sony" )) & &! (manufacturer.contains( "lge" ))))

Ответ 4

Я испытываю некоторые проблемы при использовании этого с Sony Xperia Z5.

Я добавил это, и это стало намного лучше.

if (buildType.contains("sony")&& buildDevice.contains("e5823")) {
                setPreDefinedCameraUri = true;}

Но в 4 раза из 22 он перезапустил камеру и один раз перезапустил ее два раза. Я перезапустил приложение из-за каждого теста. Есть ли способ обойти это или я принимаю этот результат?

Дело в том, что если камера перезапустится, я могу дважды нажать кнопку "Назад" и стрела, изображение будет в моем изображении и сохранено