Съёмка фотографий
Снимайте и сохраняйте изображения
«Съёмка фотографий» — бесплатный урок Android Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Android Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Android Academy содержит 4 уроков всего.
Съёмка фотографии
После появления предварительного просмотра следующий шаг — сделать фотографию. CameRX обрабатывает это с помощью сценария использования ImageCapture.
Вы привяжете ImageCapture вместе с предварительным просмотром, затем вызовете takePicture() при нажатии пользователем кнопки затвора и сохраните результат в галерею устройства.
Создание сценария использования ImageCapture
ImageCapture настраивается с помощью строителя. Один из полезных параметров — режим съёмки, который задаёт компромисс между задержкой и качеством:
CAPTURE_MODE_MINIMIZE_LATENCY— быстрая съёмка.CAPTURE_MODE_MAXIMIZE_QUALITY— наилучшее качество изображения, но немного меньшая скорость.
val imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()Привязка Preview и ImageCapture
Можно одновременно привязать несколько сценариев использования. Передайте preview и imageCapture в bindToLifecycle, чтобы камера одновременно показывала изображение в реальном времени и была готова сделать фотографию.
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
lifecycleOwner,
CameraSelector.DEFAULT_BACK_CAMERA,
preview,
imageCapture
)Куда сохранять: MediaStore
Современный способ сохранения фотографий, совместимый с изолированным хранилищем, — использовать MediaStore. Опишите файл (имя, тип MIME, папку) с помощью ContentValues и позвольте системе разместить его в общей коллекции Pictures.
На Android 10 и более поздних версиях это работает без устаревшего разрешения WRITE_EXTERNAL_STORAGE.
val name = "photo_${System.currentTimeMillis()}"
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/MyApp")
}Параметры вывода
Чтобы указать CameraX, куда записывать файл JPEG, создайте OutputFileOptions на основе поставщика содержимого, URI целевой коллекции и объекта ContentValues.
val outputOptions = ImageCapture.OutputFileOptions
.Builder(
context.contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
)
.build()Вызов takePicture()
Теперь запустите съёмку. takePicture() принимает параметры вывода, объект Executor и обратный вызов. CameRX асинхронно сообщает об успешном выполнении или ошибке.
Используйте ContextCompat.getMainExecutor(context), чтобы обратный вызов выполнялся в главном потоке.
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(context),
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val savedUri = output.savedUri
// Photo saved! Show a confirmation.
}
override fun onError(exc: ImageCaptureException) {
// Handle the failure.
}
}
)Обработка результата
При успешном выполнении OutputFileResults.savedUri содержит URI сохранённого изображения. Вы можете отобразить его (с помощью Coil), поделиться им или показать Snackbar с подтверждением сохранения.
При ошибке ImageCaptureException сообщает, что пошло не так, — запишите сведения об ошибке в журнал и уведомите пользователя.
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val uri = output.savedUri ?: return
Toast.makeText(context, "Saved: $uri", Toast.LENGTH_SHORT).show()
}Подключение кнопки затвора
В Compose разместите кнопку затвора поверх области предварительного просмотра с помощью Box. Поднимите ссылку на ImageCapture на уровень выше, чтобы onClick кнопки мог вызвать takePhoto.
Box(modifier = Modifier.fillMaxSize()) {
CameraPreview(imageCapture = imageCapture)
IconButton(
onClick = { takePhoto(context, imageCapture) },
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(32.dp)
) {
Icon(Icons.Default.PhotoCamera, contentDescription = "Take photo")
}
}Выделение takePhoto()
Чтобы компонуемый элемент оставался чистым, вынесите логику захвата в вспомогательную функцию. Она принимает контекст и вариант использования ImageCapture, создаёт параметры вывода и вызывает takePicture.
fun takePhoto(context: Context, imageCapture: ImageCapture) {
val values = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "IMG_${System.currentTimeMillis()}")
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
}
val options = ImageCapture.OutputFileOptions.Builder(
context.contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values
).build()
imageCapture.takePicture(
options,
ContextCompat.getMainExecutor(context),
object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(o: ImageCapture.OutputFileResults) {}
override fun onError(e: ImageCaptureException) {}
}
)
}Вспышка и поворот
Два последних штриха:
- Вспышка: установите для
imageCapture.flashModeзначениеFLASH_MODE_ON,OFFилиAUTO. - Поворот: CameRX использует целевой угол поворота, чтобы правильно сориентировать сохранённый JPEG; обновляйте его, чтобы ориентация оставалась точной.
imageCapture.flashMode = ImageCapture.FLASH_MODE_AUTO
// Update target rotation when the device rotates:
imageCapture.targetRotation = display.rotationСобираем всё вместе
Полный процесс работы с фотографией выглядит так: создайте ImageCapture → свяжите его с предварительным просмотром → при нажатии затвора создайте OutputFileOptions и вызовите takePicture → обработайте onImageSaved / onError.
Так всего за несколько строк вы получите полностью готовую камеру с сохранением фотографий в галерею.
Быстрая проверка
Убедитесь, что понимаете процесс захвата фотографий.
Итоги
Теперь вы умеете делать и сохранять фотографии с помощью CameRX:
- Создайте вариант использования
ImageCaptureи свяжите его с предварительным просмотром. - Опишите вывод с помощью
ContentValuesиMediaStoreдля изолированного хранилища. - Вызовите
takePicture(), передавOutputFileOptions, исполнитель иOnImageSavedCallback. - При успешном выполнении прочитайте
savedUri; при ошибке обработайтеImageCaptureException.
Далее вы научитесь записывать видео с помощью варианта использования VideoCapture.
Изучай Kotlin с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 36
- Уроки
- 152
Часто задаваемые вопросы
Урок «Съёмка фотографий» бесплатный?
Да — полный текст урока «Съёмка фотографий» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Android Academy, подпишись на CoddyKit PRO. Курс Android Academy содержит 4 уроков всего.
Чему я научусь в уроке «Съёмка фотографий»?
Снимайте и сохраняйте изображения Ты практикуешь Android Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Android Academy?
Предыдущий опыт не требуется. Android Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Съёмка фотографий»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Android Academy?
Да. Каждый урок Android Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.