Android Academy · Урок

Съёмка фотографий

Снимайте и сохраняйте изображения

Урок 3 из 413 шагов

«Съёмка фотографий» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Обзор CameraX
  2. Отображение предварительного просмотра с камеры
  3. Съёмка фотографий
  4. Запись видео
← Назад к Android Academy