Pull to refresh

Работа с камерой во Flutter

Reading time5 min
Views15K

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



Между ними – заметная разница, и использовать их стоит по ситуации:


  • camera позволяет взаимодействовать с доступными устройству камерами из вашего приложения и выводить изображение в виджет. Хорошо подходит под задачи, когда надо "кастомизировать" работу камеры под приложение.
  • image-picker запускает приложение камеры и возвращает объект типа File (изображение или видеофайл, выбранный пользователем) в ваше приложение. Также image-picker дает возможность выбора файла из имеющихся на устройстве, при этом, как и в случае камеры, запускается отдельное приложение, после чего в ваше приложение возвращается выбранный объект.



Здесь можно посмотреть исходники.




camera


1. Добавляем плагин в наш проект по инструкции


Дополнительные настройки для ОС
iOS
Добавьте следующие строки в ios/Runner/Info.plist:


<key>NSCameraUsageDescription</key>
<string>Access to Camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>Access to Microphone</string>

Android
Убедить, что минимальная версия Android sdk в файле android/app/build.gradle 21.


minSdkVersion 21

Все необходимые разрешения будут запрошены при запуске приложения


Работа на эмуляторах
В случае IOS мы не можем проверить работу камеры на эмуляторе, нужно "живое" устройство.
Android генерирует некий mock (см. изображение ниже), который заменяет то, что видит объектив камеры.


Стандартная заглушка


Если вы не хотите смотреть на стандартную заглушку

В настройках эмулятора выбираем Advanced Settings и для задней камеры ставим VirtualScene.

Перезапускаем эмулятор. Теперь камера "показывает" виртуальную комнату, по которой можно передвигать с помощью мыши и wasd.

Спасибо Tonn_Tamerlan за наводку.


2. Переходим к коду. Сначала получаем все доступные камеры с помощью функции availableCameras.


final cameras = await availableCameras();

Данная функция вернет массив описаний (List<CameraDescription>) доступных камер, где каждый элемент будет содержать имя камеры (это может быть просто индекс), тип (задняя, фронтальная, внешняя) и угол, на который надо повернуть фотографию, чтобы она отображалась в своей ориентации.


Для управления камерой нам нужен объект-контроллер типа CameraController, для определения которого надо указать одно из полученных описаний камеры и разрешение (низкое, среднее, высокое).


void _setCameraController(CameraDescription cameraDescription) async {
     _controller = CameraController(cameraDescription, ResolutionPreset.medium);
     ...
     await _controller.initialize();
     ...
     if (mounted) {
       setState(() {});
     }
}

Далее инициализируем контроллер и после того, как убедимся, что виджет "жив", обновляем состояние этого виджета. (текст функции)


Передаем инициализированный контроллер в виджет CameraPreview


     AspectRatio(
         aspectRatio: _controller.value.aspectRatio,
         child: CameraPreview(_controller))

В основе CameraPreview лежит виджет Texture, отвечающий за отображение картинки с камеры. Его размеры определяются родителем, поэтому хорошо подход виджет AspectRatio, определяющий размер дочернего элемента в определенном соотношении сторон. Соотношение мы получаем из контроллера _controller.value.aspectRatio. В результате в интерфейсе получаем картинку в интерфейсе


Вид приложения после инициализации контроллера


3. Теперь мы можем сделать фотоснимок или снять видео.
а. Делаем фотографию (текст функции) с помощью метода takePicture(String path). Он делает снимок и сохраняет по указанному пути.


Future<void> _takePhoto(BuildContext context) async {
     ...
     await _controller.takePicture(filePath);
     ...
}

Чтобы получить путь нам необходим официальный плагин path_provider и его метод getApplicationDocumentsDirectory, который вернет приватную директорию. Далее определяем имя директории по вкусу, если надо создаем ее, и выбираем имя файла:


    final Directory extDir = await getApplicationDocumentsDirectory();
    final String dirPath = '${extDir.path}/Pictures/flutter_camera';
    await Directory(dirPath).create(recursive: true);
    final String filePath = '$dirPath/${_getTimestamp()}.jpg';

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


if (!_controller.value.isInitialized) {
     return null;
}
...
if (_controller.value.isTakingPicture) {
    return null;
}

Снимок сделан, у нас есть путь к нему, хорошо бы посмотреть. С помощью стандартного виджета Image, объекта File и пути к файлу выводим картинку на экран.


Image.file(File(filePath))

Вывод полученного снимка


б. При записи видео (текст функции) нам понадобятся две функции: startVideoRecording(String filePath) и stopVideoRecording().


Future<void> _startVideoRecording() async {
     ...
     await _controller.startVideoRecording(filePath);
    ...
}
Future<void> _stopVideoRecording(BuildContext context) async {
    ...
    await _controller.stopVideoRecording();
    ...
}

startVideoRecording пишет видео и сохраняет по указанному пути (полученному по такому же принципу, как и с фотографией), stopVideoRecording же просто завершает процесс записи. Перед началом записи следует убедиться, что съемка уже не идет.


if (_controller.value.isRecordingVideo) {
     return null;
}

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


Запись и проигрывание в интерфейсе




image-picker


1. Добавляем плагин в наш проект по инструкции


Дополнительные настройки для ОС
iOS
Добавьте следующие строки в ios/Runner/Info.plist:


<key>NSCameraUsageDescription</key>
<string>Access to Camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>Access to Microphone</string> 
<key>NSPhotoLibraryUsageDescription</key>
<string>Access to PhotoLibrary</string>

Работа на эмуляторах
В IOS мы не можем проверить работу камеры на эмуляторе, нужно "живое" устройство.


2. image-picker использует стандартное приложение для создания фото/видео или просмотра файлов. Для запуска нужного приложения необходимо воспользоваться функцией pickImage для фото или pickVideo и указать параметр source (источник).


...
final File video = await ImagePicker.pickVideo(source: ImageSource.camera);
final File photo = await ImagePicker.pickImage(source: ImageSource.gallery);
// для pickImage можно еще указать максимальные показатели ширины и высоты, иначе изображение вернется в оригинальном размере
...

Галерея и камера



Выбранный файл получает наше приложение, но если ничего не было выбрано, то вернется null. Для показа картинки и видео используем те же подходы, что и в случае плагина camera. Для изображений виджет Image — в этот раз не надо оборачивать в File, так как мы изначально получили объект этого типа.


Image.file(photo)

Для видео плагин video_player. Весь код, связанный с проигрыванием видео, вынесен в отдельный файл.




Заключение


Как вы успели заметить, image-picker заметно проще в использовании и прекрасно подходит в тех случаях, когда просто надо передать изображение или видео приложению. camera же предоставляет нам все необходимые возможности для кастомизации работы пользователя с камерой в вашем приложении.
Спасибо, что прочитали!

Tags:
Hubs:
Total votes 7: ↑7 and ↓0+7
Comments5

Articles