Android studio работа с камерой

Практически все современные телефоны и планшеты снабжаются камерами, что позволяет фотографировать любимых котиков.

Программное включение приложения Камера

Вы можете программно запустить из своей программы системное приложение "Камера" (в этом случае вам не понадобятся дополнительные разрешения) через намерение.

А вообще у пользователя могут стоять разные приложения, способные фотографировать. Тогда у вас будет появляться диалоговое окно с выбором нужного приложения. Они все имеют в своём составе такую запись в манифесте (для общего развития):

У Гугла есть своя программа Google Камера. Запустим её, зная имя пакета.

При вызове метода getIntent() вместо new Intent() приложение запускалось сразу, иначе — выводилось диалоговое окно выбора программы из списка. Также нужно быть уверенным, что программа установлена, в примере нет кода проверки.

Делаем фотографии и сохраняем результат. Простой пример

Просто включить камеру не слишком интересно. Рассмотрим практичный пример, когда мы программно запустим приложение "Камера", а полученную фотографию сохраним в папке. Для начала сфокусируемся на основной задаче, а потом напишем более сложное приложение.

Используйте статическую константу MediaStore.ACTION_IMAGE_CAPTURE для создания намерения, которое потом нужно передать методу startActivityForResult(). Разместите на форме кнопку и ImageView, в который будем помещать полученный снимок. Этот код запускает стандартное приложение камеры. Полученное с камеры изображение можно обработать в методе onActivityResult():

Данный код запустит приложение, работающее с камерой, позволяя пользователю поменять настройки изображения, что освобождает вас от необходимости создавать своё собственное приложение для этих нужд. Вполне возможно, что у вас будет несколько приложений, умеющих делать фотографии, тогда сначала появится окно выбора программы.

При тестировании примера на своём телефоне я обнаружил небольшую проблему — когда снимок передавался обратно на моё приложение, то оно находилось в альбомном режиме, а потом возвращалось в портретный режим. При этом полученный снимок терялся. Поэтому перед нажатием кнопки я поворачивал телефон в альбомный режим, чтобы пример работал корректно. Поэтому вам надо предусмотреть подобное поведение, например, запретить приложению реагировать на поворот и таким образом избежать перезапуска Activity. У некоторых телефонов такой проблемы нет.

По умолчанию фотография возвращается в виде объекта Bitmap, содержащего миниатюру. Этот объект находится в параметре data, передаваемом в метод onActivityResult(). Чтобы получить миниатюру в виде объекта Bitmap, нужно вызвать метод getParcelableExtra() из намерения, передав ему строковое значение data. В примере использовался упрощённый вариант, ниже показан пример другого варианта кода.

Если вы укажете исходящий путь URI с помощью параметра MediaStore.EXTRA_OUTPUT в запущенном намерении, полноразмерное изображение, снятое камерой, сохранится в заданном месте. В таком случае в метод onActivityResult() не будет передана миниатюра, а итоговое намерение продемонстрирует значение null.

В следующем примере показано, как при создании снимка получать миниатюру или полноценное изображение, используя намерение. Изображение будет сохранено во внешнем хранилище под именем test.jpg.

Добавим разрешение на запись файла в хранилище.

В реальных приложениях для создания имён файлов используют текущую дату, чтобы обеспечить уникальность и не затереть существующую фотографию.

В Android 6.0 Marshmallow пример перестал работать из-за новых правил с разрешениями. Новый вариант представлен в соответствующей статье.

На этом неприятности не закончились. В Lollipop для Uri нужно использовать метод setClipData(), а в Nougat запретили и сам URI, заставляя переходить на FileProvider.

Делаем фотографии или видео и сохраняем результат. Улучшенный пример

Предположим, вы создали специальную службу, которая отслеживает бездомных котов и сотрудники вашей организации привозят им подарки, а также гладят их. Пользователи, которые скачали ваше приложение, должны сфотографировать кота, а затем информация о месте съёмки и другие параметры попадают к вам в центр для обработки. Фотографирование котов — это часть вашего приложения. Не обязательно придумывать велосипед и работать напрямую с функциями камеры. У вас уже есть системное приложение Камера, с помощью которого можно быстро сделать фотографию и получить результат обратно в приложение.

Сначала сделаем небольшие приготовления. Есть класс устройств, у которых нет камер, например, электронные ридеры. Чтобы пользователи этих устройств не скачивали зря ваше приложение, которое окажется для них бесполезным, пропишем в манифесте требование наличия камеры.

Оформим отдельную функцию для запуска намерения.

Метод resolveActivity() поможет проверить активности, способное сделать фотографию. Если подходящего приложения не найдётся, то мы можем сделать кнопку для съёмки недоступной.

Полученное с камеры изображение можно обработать в методе onActivityResult().

Системное приложение Камера кодирует фото в возвращаемом намерении, которое поступает в метод onActivityResult() в виде небольшого Bitmap в ключе data. Следующий код получает изображение и выводит его в ImageView.

Полученное миниатюрное изображение из "data" вполне годится для использования в качестве аватара в контактах. Если мы хотим получить полноразмерное изображение, то напишем дополнительный код для другой кнопки.

Чтобы приложение Камера сохраняло полноразмерные фотографии, нам нужно сообщить ему имя файла для сохранения и его полный путь.

В Android 2.2 и выше (API 8) есть специальный метод, чтобы получить стандартный путь для фотографий:

Указанная папка будет хранить фотографии даже после удаления приложения. Методы getExternalFilesDir() и getFilesDir() работают с папками приложения, поэтому фотографии будут удалены во время деинсталяции. Иногда такой подход может пригодиться, если фотки специфичны для приложения и нет необходимости сохранять их в общей папке.

Необходимо позаботиться об уникальности имени файла, чтобы избежать конфликтов:

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

Если у нас есть место для сохранения изображения, то сообщите путь приложению камеры через намерение:

В документации приведён пример с использованием FileProvider, который является самым правильными и работоспособным для последних версий Android. Но при попытке строгого следования тексту приложение у меня крашилось. Поэтому я внёс поправки и расскажу действительно правильный вариант

Итак, прописываем разрешение WRITE_EXTERNAL_STORAGE. Но не прописывайте разрешение android.permission.CAMERA! Также добавьте использование камеры. Внутри секции application добавьте блок provider.

Дальше код для активности, который содержит кнопку и ImageView.

В папке res/xml создаём файл file_paths.xml. Вместо ru.alexanderklimov.photo используйте имя вашего пакета.

Теперь всё должно заработать.

Уведомляем приложение Галерея

Можно сделать фотографию доступной для системы при помощи Media Provider.

Следующий пример демонстрирует метод вызова системного медиа-сканера, чтобы добавить вашу фотографию в базу данных Media Provider, что сделает её видимой в приложении Галерея и других приложениях.

Декодирование масштабированого изображения

Работа с большими изображениями может вызвать проблемы на устройстве с ограниченным объемом памяти. Если ваше приложение вызывает нехватку памяти после вывода нескольких изображений, вы можете значительно уменьшить объем занимаемой памяти, использовав во время распаковки JPEG-файлов в память масштабирование, которое учитывает размеры вашего View для просмотра картинок:

Кроме того, в учебном примере рассматривается вывод видео в элемент VideoView. Изучайте код самостоятельно.

Снимаем и кадрируем

Рассмотрим ещё один пример, когда мы запустим приложение Камера, а также включим режим кадрирования. Обратите внимание, что основная часть кода остаётся прежней. Я специально даю разные примеры с незначительными изменениями, чтобы вы могли выбрать подходящие приёмы для вашей задачи. Также рекомендую проверять работу с камерой на реальных устройствах, так как многие производители заменяют стандартные методы съёмки своими прошивками и драйверами. В частности, намерение с кадрированием является проблемной, и в интернете многие жалуются на отсутствие поддержки этого способа.

Создадим простенький макет из кнопки для запуска камеры и ImageView для вывода кадрированного изображения.

Для большей красоты сделаем задний фон у ImageView с закруглёнными углами и обводкой. Для этого в атрибуте android:background мы прописали специальный стиль. Создайте папку res/drawable, а в ней файл background.xml следующего содержания:

Этот шаг не является обязательным и его можно пропустить.

При нажатии кнопки запускаем приложение Камера и ожидаем результата.

После того, как пользователь сделал нужный кадр, программа Камера возвращает результат обратно в наше приложение. Результат обрабатывается в методе onActivityResult():

Получив полноразмерное изображение, мы пытаемся откадрировать его. Для этого создадим метод performCrop(), который запускает специальное намерение, предназначенное для этих целей. В успешном случае результат снова возвращается в наше приложение, но уже с другим кодом PIC_CROP. Теперь мы имеем нужное изображение, которое можно вывести на экран.

При кадрировании мы указываем желаемые размеры (код метода ниже). Если указать слишком больше размеры (больше 400), то результат не возвращается. Попробуйте добавить ещё два параметра:

Результат работы приложения, когда запускается намерение кадрирования и итоговый результат. Желательно тренироваться на кошках.

Показать код (щелкните мышкой)

Запуск камеры в нужном режиме

Обнаружил, что появилось новое намерение, позволяющее включить камеру в нужном режиме: фотосъёмка или видео.

— получаем фото и видео, используя системное приложение

Открываем серию уроков по работе с камерой. И начнем с самого простого. Если вам в приложении необходимо сделать снимок или снять видео, вовсе необязательно для этого создавать отдельное Activity и работать в нем с объектом Camera. Можно использовать уже существующее в системе приложение.

Для этого ваше приложение должно отправить Intent с action = MediaStore.ACTION_IMAGE_CAPTURE (фото) или MediaStore.ACTION_VIDEO_CAPTURE (видео) и ждать ответ. Т.е. надо использовать методы startActivityForResult и onActivityResult.

Также, в этот Intent вы можете поместить желаемый путь к файлу и туда будет сохранен результат работы камеры. Для этого в Intent необходимо добавить Uri с ключом MediaStore.EXTRA_OUTPUT.

Напишем простое приложение, демонстрирующее эти возможности.

Project name: P1311_CameraIntent
Build Target: Android 2.3.3
Application name: CameraIntent
Package name: ru.startandroid.develop.p1311cameraintent
Create Activity: MainActivity

Добавим строки в strings.xml:

На экране только кнопки для получения фото и видео, и ImageView, в котором будем отображать полученное фото.

В onCreate мы вызываем свой метод createDirectory, который в папке Pictures создаст папку для наших файлов и поместит соответствующий объект File в переменную directory.

В onClickPhoto и onClickVideo создаем Intent с соответствующим action, добавляем в этот Intent желаемый путь к файлу и отправляем методом startActivityForResult.

В onActivityResult мы ловим результат от приложения камеры. Код громоздкий, т.к. там куча проверок на null. Для фото и для видео я пытаюсь вытащить путь к получившемуся файлу, используя Intent.getData. Кроме этого, для фото я еще пытаюсь вытащить Bitmap с получившимся изображением.

Метод generateFileUri генерирует путь к файлу. Для этого он берет путь из directory, определяет префикс и расширение в зависимости от типа (фото или видео) и использует системное время, как основную часть имени файла. Далее все это конвертируется в Uri и возвращается как результат метода.

Осталось дописать в манифест пару настроек.

— право на запись на SD карту

— ваше приложение в маркете будет видно только устройствам с камерой

Сохраняем все и запускаем приложение.

Жмем Photo – открывается системное приложение камеры. Делаем фото и подтверждаем, что нас устраивает полученный снимок. Нас возвращают в наше приложение.

fileName = /storage/emulated/0/Pictures/MyFolder/photo_1376465721626.jpg
Intent is null

В ответе мы не получили ничего, Intent = null. Но мы указывали путь, куда надо сохранить фото. Идем в папку Pictures/MyFolder и ищем свой файл, он должен там быть.

Попробуем получить видео. Жмем кнопку Video, снимаем ролик и подтверждаем, что он нас устраивает.

fileName = /storage/emulated/0/Pictures/MyFolder/video_1376466182087.mp4
Video uri: file:///storage/emulated/0/Pictures/MyFolder/video_1376466182087.mp4

В случае с видео Intent не null. И его метод getData вернул нам инфу о пути к файлу. Идем в папку и ищем свой файл.

Теперь давайте не будем явно указывать путь для сохранения, и посмотрим, как поведет себя приложение камеры.

Закомментируем соответствующие строки кода:

Сохраняем, запускаем приложение.

Жмем Photo, делаем снимок и подтверждаем его, открывается наше приложение и ImageView показывает только что сделанное фото.

Photo uri: null
bitmap 120 x 160

getData вернул null, хотя хелп обещал, что там будет путь к файлу. Зато в Intent мы получили Bitmap. Но, как видим, размер его оставляет желать лучшего. Получается, что вообще нет доступа к полноценному сделанному фото. Оно у меня даже не создалось в папке, куда камера по дефолту фоты сохраняет.

Скорее всего, это зависит от версии Android и системного приложения камеры. И у вас вполне может быть другое поведение системы.

Попробуем с видео. Жмем Video, снимаем и подтверждаем ролик.

Video uri: content://media/external/video/media/8018

С видео все ок. Камера сохранила видео в папку по умолчанию, и в Intent вернула нам Uri.

Кроме желаемого пути для видео вы можете указать еще некоторые параметры в intent:

MediaStore.EXTRA_DURATION_LIMIT – лимит продолжительности видео в секундах

MediaStore.EXTRA_SIZE_LIMIT – лимит размера получившегося видео в байтах

На следующем уроке:

— используем объект Camera для получения изображения с камеры
— подгоняем изображение под размеры экрана
— учитываем поворот устройства

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Большинство телефонов на Android сейчас уже имеют по крайней мере одну камеру. Это позволяет разработчиками добавлять в приложения возможность создания фотографий. Самый простой способ работы с камерой заключается в использовании приложения, которое уже есть в составе операционной системы Android. Кроме того в составе Android Framework есть набор API для непосредственной работы с камерой. Это предоставляет разработчику большую гибкость в использовании камеры, но требует написания большего количества кода.

В этой статье мы разберемся как делать фотографии на Android, используя встроенное приложение для работы с камерой.

Если ваше приложение использует камеру, вам необходимо указать это в файле манифеста. Это делается с помощью тегов

Если работа с камерой — это обязательная часть вашего приложения, необходимо установить свойство android:required равным true. В этом случае приложение будет отображаться в Google Play только для тех телефонов, которые имеет камеру.

Если работа с камерой — это всего лишь дополнительная функция приложения, без которой оно нормально работает, устанавливайте свойство android:required равным false. Приложение будет отображаться в Google Play для всех телефонов, но в этом случае нужно проверять наличие камеры в коде приложения. Это делается с помощью метода hasSystemFeature(PackageManager.FEATURE_CAMERA).

Android позволяет передать выполнение различных действий другим приложениям с помощью intent объектов. Таким образом мы можем делать фотографии, используя внешнее приложение. Данный процесс включает в себя три этапа: создание определенного intent объекта, запуск новой Activity, обработка полученных результатов в текущей Activity.

Ниже вы видите пример кода:

Обратите внимание, с помощью метода resolveActivity() мы проверяем наличие приложения для работы с камерой. Если intent не может быть обработан каким-нибудь внешним приложением, то вызов метода startActivityForResult() приведет к аварии вашего приложения.

Для обработки результата работы приложения камеры, в Activity вашего приложения нужно переопределить метод onActivityResult(). Ему будет передаваться intent, к которому прикреплен Bundle объект, который в свою очередь содержит ссылку на bitmap объект. Ссылку можно получить с помощью метода get() и ключа "data". Ниже вы видите пример кода.

Миниатюра изображения, получаемая таким способом, подходит только для иконки. Для получения полноразмерного изображения требуется немного больше кода.

Приложение камеры сохраняет полноразмерную фотографию, если вы предоставляете ему ссылку на файл.

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

Разрешение на запись одновременно позволяет производить и чтение.

Если вы хотите, чтобы фотографии были доступны только с помощью вашего приложения, то для получения директории используйте метод getExternalFilesDir(). На Android 4.3 и ниже, для записи в эту директорию также требуется разрешение WRITE_EXTERNAL_STORAGE. Начиная с Android 4.4, разрешение уже не требуется, поскольку директория больше не доступна другим приложениям. Исходя из этого, можно объявить разрешение так:

Обратите внимание, при удалении вашего приложения, директория, возвращаемая методом getExternalFilesDir(), будет тоже удалена.

Когда вы определите директорию для фотографии, вам нужно создать файл с уникальным именем и, возможно, сохранить путь к нему. Ниже приведен пример метода, который выполняет эту процедуру, используя текущую дату и время.

Этот метод создает файл для фотографии и запускает приложение камеры с помощью интента.

Созданную фотографию можно сделать общедоступной с помощью системного Media Provider.

Но обратите внимание! Если вы сохранили фотографию в директорию полученную с помощью метода getExternalFilesDir(), медиа сканер не сможет получить к ней доступ, потому что фотография будет в приватной директории вашего приложения.

Следующий метод демонстрирует как вызывать медиа сканер для того, чтобы добавить вашу фотографию в базу данных и сделать ее доступной в стандартном Android приложении "галерея".

Работа с несколькими полноразмерными изображениями может быть сложной задачей в условиях ограниченной памяти. Но вы можете значительно уменьшить количество используемой памяти, преобразовав JPEG к соответствующему размеру View компонента. Следующий пример демонстрирует эту технику.

Тестовый проект можно скачать на GitHub.
По материалам документации.
Вольный перевод — Pavel Bobkov.

Оцените статью
Ремонт оргтехники
Добавить комментарий