사진 촬영
이미지를 캡처하고 저장합니다.
사진 촬영은(는) CoddyKit의 무료 Android Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 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를 사용하는 것입니다. ContentValues로 파일(이름, MIME 유형, 폴더)을 설명하면 시스템이 공유 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를 저장할 위치를 지정하려면 콘텐츠 리졸버, 대상 컬렉션 URI 및 ContentValues로 OutputFileOptions를 만듭니다.
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를 제공합니다. 이 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로 출력을 설명합니다. OutputFileOptions, 실행기,OnImageSavedCallback을 사용해takePicture()를 호출합니다.- 성공하면
savedUri를 읽고, 오류가 발생하면ImageCaptureException을 처리합니다.
다음에는 VideoCapture 사용 사례로 동영상을 녹화하겠습니다.
자주 묻는 질문
“사진 촬영” 강의는 무료인가요?
네 — “사진 촬영” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Android Academy 강의 전체를 잠금 해제할 수 있습니다. Android Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“사진 촬영”에서 뭘 배우나요?
이미지를 캡처하고 저장합니다. 브라우저에서 직접 실행하는 실습 코드로 Android Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Android Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Android Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“사진 촬영” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Android Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Android Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.