Este documento también está disponible en inglés: API_REFERENCE.md
Documentación completa de la API para la librería ImagePickerKMP.
- Componente principal
- Clases de estado y resultado
- Configuración
- Clases de datos
- Enums
- Funciones de extensión
- Permisos de cámara
- Utilidades
- Excepciones
API principal idiomática de Compose. Un único state holder — sin booleanos manuales, sin necesidad de llamar Render().
@Composable
fun rememberImagePickerKMP(
config: ImagePickerKMPConfig = ImagePickerKMPConfig()
): ImagePickerKMPStateconfig: ImagePickerKMPConfig- Configuración global aplicada a cada lanzamiento salvo que se sobreescriba por llamada. Por defecto usa valores de plataforma.
@Composable
fun MyScreen() {
val picker = rememberImagePickerKMP()
Button(onClick = { picker.launchCamera() }) { Text("Cámara") }
Button(onClick = { picker.launchGallery(allowMultiple = true) }) { Text("Galería") }
when (val result = picker.result) {
is ImagePickerResult.Success -> {
result.photos.forEach { photo ->
println("URI: ${photo.uri}")
}
}
is ImagePickerResult.Error -> {
Text("Error: ${result.exception.message}")
}
is ImagePickerResult.Dismissed -> { /* usuario canceló */ }
ImagePickerResult.Loading -> { /* cargando */ }
ImagePickerResult.Idle -> { /* sin acción */ }
}
}@Composable
fun AdvancedScreen() {
val picker = rememberImagePickerKMP(
config = ImagePickerKMPConfig(
cameraCaptureConfig = CameraCaptureConfig(
preference = CapturePhotoPreference.QUALITY,
compressionLevel = CompressionLevel.MEDIUM,
includeExif = true
),
galleryConfig = GalleryConfig(
allowMultiple = true,
selectionLimit = 10,
mimeTypes = listOf(MimeType.IMAGE_JPEG, MimeType.IMAGE_PNG)
),
cropConfig = CropConfig(enabled = true, squareCrop = true),
uiConfig = UiConfig(buttonColor = Color.Blue),
permissionAndConfirmationConfig = PermissionAndConfirmationConfig(
skipConfirmation = true
)
)
)
Column {
Button(onClick = { picker.launchCamera() }) {
Text("Tomar foto")
}
Button(onClick = { picker.launchGallery() }) {
Text("Seleccionar de galería")
}
}
when (val result = picker.result) {
is ImagePickerResult.Success -> {
result.photos.forEach { photo ->
println("Foto: ${photo.uri}, Tamaño: ${photo.fileSize} bytes")
photo.exif?.let { exif ->
println("Cámara: ${exif.cameraModel}")
println("Fecha: ${exif.dateTaken}")
}
}
}
is ImagePickerResult.Error -> {
println("Error: ${result.exception.message}")
}
else -> {}
}
}Cualquier parámetro pasado directamente a launchCamera() o launchGallery() sobreescribe la configuración global solo para esa invocación, sin mutar la configuración recordada.
@Composable
fun PerLaunchOverrideExample() {
val picker = rememberImagePickerKMP(
config = ImagePickerKMPConfig(
cameraCaptureConfig = CameraCaptureConfig(
compressionLevel = CompressionLevel.MEDIUM
)
)
)
// Usa la configuración global (compresión MEDIUM)
Button(onClick = { picker.launchCamera() }) {
Text("Foto normal")
}
// Sobreescribe solo para esta llamada (compresión HIGH)
Button(onClick = {
picker.launchCamera(
cameraCaptureConfig = CameraCaptureConfig(
compressionLevel = CompressionLevel.HIGH
)
)
}) {
Text("Foto comprimida")
}
// Galería con sobreescritura
Button(onClick = {
picker.launchGallery(
allowMultiple = true,
selectionLimit = 5,
includeExif = true
)
}) {
Text("Seleccionar múltiples")
}
}State holder retornado por rememberImagePickerKMP. Expone el resultado como estado observable reactivo y los métodos de lanzamiento.
@Stable
class ImagePickerKMPState {
val result: ImagePickerResult
val isCropActive: Boolean
fun launchCamera(
cameraCaptureConfig: CameraCaptureConfig? = null,
onDismiss: (() -> Unit)? = null,
onError: ((Exception) -> Unit)? = null
)
fun launchGallery(
allowMultiple: Boolean? = null,
mimeTypes: List<MimeType>? = null,
selectionLimit: Int? = null,
includeExif: Boolean? = null,
redactGpsData: Boolean? = null,
mimeTypeMismatchMessage: String? = null,
cameraCaptureConfig: CameraCaptureConfig? = null,
onDismiss: (() -> Unit)? = null,
onError: ((Exception) -> Unit)? = null
)
fun reset()
}Lanza el picker de cámara. Todos los parámetros son opcionales y sobreescriben los valores de la configuración global para esa invocación.
cameraCaptureConfig- Configuración de cámara por lanzamiento.null= usa el global.onDismiss- Callback cuando el usuario cierra sin capturar.null= transiciona aDismissed.onError- Callback si ocurre un error.null= transiciona aError.
Lanza el picker de galería. Todos los parámetros son opcionales.
allowMultiple- Permite selección múltiple.null= usagalleryConfig.allowMultiple.mimeTypes- Tipos MIME aceptados.null= usagalleryConfig.mimeTypes.selectionLimit- Máximo de archivos seleccionables.null= usagalleryConfig.selectionLimit.includeExif- Extrae metadatos EXIF.null= usagalleryConfig.includeExif.redactGpsData- Elimina coordenadas GPS del EXIF.null= usagalleryConfig.redactGpsData.mimeTypeMismatchMessage- Mensaje personalizado para tipos no compatibles.cameraCaptureConfig- Configuración de cámara para botón integrado de cámara en galería.onDismiss- Callback cuando el usuario cierra sin seleccionar.null= transiciona aDismissed.onError- Callback si ocurre un error.null= transiciona aError.
Reinicia el estado a Idle y permite iniciar una nueva sesión.
Representa el estado reactivo del resultado del picker.
sealed class ImagePickerResult {
data object Idle : ImagePickerResult()
data object Loading : ImagePickerResult()
data class Success(val photos: List<PhotoResult>) : ImagePickerResult() {
val first: PhotoResult? get() = photos.firstOrNull()
}
data object Dismissed : ImagePickerResult()
data class Error(val exception: Exception) : ImagePickerResult()
}| Estado | Descripción |
|---|---|
Idle |
Sin acción. Estado inicial. |
Loading |
El picker está activo esperando interacción del usuario. |
Success |
Captura/selección exitosa. Contiene lista de PhotoResult. |
Dismissed |
El usuario canceló sin seleccionar/capturar. |
Error |
Ocurrió un error durante la operación. |
Configuración global para rememberImagePickerKMP.
data class ImagePickerKMPConfig(
val cameraCaptureConfig: CameraCaptureConfig = CameraCaptureConfig(),
val galleryConfig: GalleryConfig = GalleryConfig(),
val cropConfig: CropConfig = CropConfig(),
val uiConfig: UiConfig = UiConfig(),
val permissionAndConfirmationConfig: PermissionAndConfirmationConfig = PermissionAndConfirmationConfig()
)| Propiedad | Tipo | Descripción |
|---|---|---|
cameraCaptureConfig |
CameraCaptureConfig |
Comportamiento de la cámara (compresión, EXIF, tamaño botón, etc.) |
galleryConfig |
GalleryConfig |
Comportamiento de la galería (selección múltiple, MIME types, etc.) |
cropConfig |
CropConfig |
Activar y ajustar la UI de recorte |
uiConfig |
UiConfig |
Colores e iconos personalizados para la UI de la cámara |
permissionAndConfirmationConfig |
PermissionAndConfirmationConfig |
Diálogos personalizados para permisos y confirmación |
| Tipo de opción | Dónde configurar |
|---|---|
Diálogos personalizados (@Composable) |
permissionAndConfirmationConfig en este config |
| Colores / iconos de la UI de la cámara | uiConfig en este config |
| Comportamiento de cámara/galería por pantalla | parámetros de launchCamera() / launchGallery() |
| Config fina de cámara (compresión, EXIF, etc.) | cameraCaptureConfig en este config |
Configuración para la captura de cámara.
data class CameraCaptureConfig(
val preference: CapturePhotoPreference = CapturePhotoPreference.BALANCED,
val captureButtonSize: Dp = 72.dp,
val compressionLevel: CompressionLevel? = CompressionLevel.MEDIUM,
val includeExif: Boolean = false,
val redactGpsData: Boolean = true,
val uiConfig: UiConfig = UiConfig(),
val cameraCallbacks: CameraCallbacks = CameraCallbacks(),
val permissionAndConfirmationConfig: PermissionAndConfirmationConfig = PermissionAndConfirmationConfig(),
val cropConfig: CropConfig = CropConfig(),
val cameraScaleType: CameraScaleType = CameraScaleType.FILL_CENTER
)preference- Preferencia de calidad de captura (FAST,BALANCED,QUALITY). Por defecto:BALANCED.captureButtonSize- Tamaño del botón de captura. Por defecto:72.dp.compressionLevel- Nivel de compresión automática (null= sin compresión). Por defecto:MEDIUM.includeExif- Extraer metadatos EXIF incluyendo GPS, modelo de cámara, timestamps. Por defecto:false.redactGpsData- Elimina coordenadas GPS del EXIF antes de entregar. Por defecto:true.uiConfig- Personalización visual de la UI de cámara.cameraCallbacks- Callbacks del ciclo de vida de la cámara.permissionAndConfirmationConfig- Diálogos de permisos y confirmación.cropConfig- Configuración del recorte interactivo tras captura.cameraScaleType- Cómo se escala la vista previa en el viewport (FILL_CENTERoFIT_CENTER). Solo Android.
Configuración para la selección de galería.
data class GalleryConfig(
val allowMultiple: Boolean = false,
val mimeTypes: List<MimeType> = listOf(MimeType.IMAGE_ALL),
val selectionLimit: Int = 30,
val includeExif: Boolean = false,
val redactGpsData: Boolean = true,
val mimeTypeMismatchMessage: String? = null
)allowMultiple- Permite selección múltiple. Por defecto:false.mimeTypes- Tipos MIME aceptados para filtrar archivos. Por defecto:IMAGE_ALL.selectionLimit- Máximo de archivos seleccionables (cuandoallowMultiple = true). Por defecto:30.includeExif- Extraer metadatos EXIF de imágenes seleccionadas. Por defecto:false.redactGpsData- Elimina coordenadas GPS del EXIF. Por defecto:true.mimeTypeMismatchMessage- Mensaje personalizado cuando un archivo no coincide con los tipos permitidos.
Configuración para la UI interactiva de recorte de imagen.
data class CropConfig(
val enabled: Boolean = false,
val aspectRatioLocked: Boolean = false,
val circularCrop: Boolean = true,
val squareCrop: Boolean = true,
val freeformCrop: Boolean = false
)enabled- Muestra la UI de recorte. Por defecto:false.aspectRatioLocked- Mantiene aspect ratio fijo. Por defecto:false.circularCrop- Ofrece opción de recorte circular. Por defecto:true.squareCrop- Ofrece opción de recorte cuadrado (1:1). Por defecto:true.freeformCrop- Permite recorte libre sin restricciones. Por defecto:false.
Configuración para el estilo visual de la UI de cámara.
data class UiConfig(
val buttonColor: Color? = null,
val iconColor: Color? = null,
val buttonSize: Dp? = null,
val flashIcon: ImageVector? = null,
val switchCameraIcon: ImageVector? = null,
val galleryIcon: ImageVector? = null
)buttonColor- Color de los botones de acción principales.iconColor- Color de los iconos en la UI de cámara.buttonSize- Tamaño del botón de captura principal.flashIcon- Icono personalizado para el toggle de flash.switchCameraIcon- Icono personalizado para cambio de cámara frontal/trasera.galleryIcon- Icono personalizado para acceso a galería.
Callbacks del ciclo de vida de la cámara.
data class CameraCallbacks(
val onCameraReady: (() -> Unit)? = null,
val onCameraSwitch: (() -> Unit)? = null,
val onPermissionError: ((Exception) -> Unit)? = null,
val onGalleryOpened: (() -> Unit)? = null
)onCameraReady- Se llama cuando la vista previa de cámara está inicializada y lista para capturar.onCameraSwitch- Se llama después de cambiar entre cámara frontal y trasera.onPermissionError- Se llama cuando el permiso de cámara es denegado o no está disponible.onGalleryOpened- Se llama cuando el usuario navega de la cámara al picker de galería.
Configuración para diálogos de permisos y pantalla de confirmación post-captura.
data class PermissionAndConfirmationConfig(
val customPermissionHandler: ((PermissionConfig) -> Unit)? = null,
val customConfirmationView: (@Composable (PhotoResult, (PhotoResult) -> Unit, () -> Unit) -> Unit)? = null,
val customDeniedDialog: (@Composable (onRetry: () -> Unit, onDismiss: () -> Unit) -> Unit)? = null,
val customSettingsDialog: (@Composable (onOpenSettings: () -> Unit, onDismiss: () -> Unit) -> Unit)? = null,
val skipConfirmation: Boolean = false,
val cancelButtonTextIOS: String? = "Cancel",
val onCancelPermissionConfigIOS: (() -> Unit)? = null,
val confirmationImageContentScale: ContentScale = ContentScale.Crop
)customPermissionHandler- Manejador personalizado invocado en lugar del diálogo de permisos por defecto.customConfirmationView- Composable personalizado que reemplaza la pantalla de confirmación. RecibePhotoResult, callback de confirmación y callback de reintentar.customDeniedDialog- Composable personalizado cuando el permiso es denegado. RecibeonRetryyonDismiss.customSettingsDialog- Composable personalizado para abrir configuración del sistema. RecibeonOpenSettingsyonDismiss.skipConfirmation- Si estrue, salta la pantalla de confirmación y entrega la foto directamente. Por defecto:false. Solo Android.cancelButtonTextIOS- Texto del botón cancelar en el alert de configuración de permisos en iOS.onCancelPermissionConfigIOS- Callback cuando el usuario toca cancelar en el alert de permisos en iOS.confirmationImageContentScale- Cómo se escala la imagen en la pantalla de confirmación.
val picker = rememberImagePickerKMP(
config = ImagePickerKMPConfig(
permissionAndConfirmationConfig = PermissionAndConfirmationConfig(
customConfirmationView = { photoResult, onConfirm, onRetry ->
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
// Tu UI de confirmación personalizada
AsyncImage(model = photoResult.uri, contentDescription = null)
Row {
Button(onClick = { onConfirm(photoResult) }) {
Text("Aceptar")
}
Button(onClick = onRetry) {
Text("Reintentar")
}
}
}
}
)
)
)val picker = rememberImagePickerKMP(
config = ImagePickerKMPConfig(
permissionAndConfirmationConfig = PermissionAndConfirmationConfig(
skipConfirmation = true
)
)
)Configuración para los diálogos de permisos de cámara.
data class CameraPermissionDialogConfig(
val titleDialogConfig: String,
val descriptionDialogConfig: String,
val btnDialogConfig: String,
val titleDialogDenied: String,
val descriptionDialogDenied: String,
val btnDialogDenied: String,
val customDeniedDialog: (@Composable (onRetry: () -> Unit, onDismiss: () -> Unit) -> Unit)? = null,
val customSettingsDialog: (@Composable (onOpenSettings: () -> Unit, onDismiss: () -> Unit) -> Unit)? = null,
val cancelButtonText: String? = "Cancel",
val onCancelPermissionConfigIOS: (() -> Unit)? = null
)titleDialogConfig- Título del diálogo de configuración de permisos.descriptionDialogConfig- Descripción del diálogo de configuración de permisos.btnDialogConfig- Texto del botón del diálogo de configuración.titleDialogDenied- Título cuando el permiso es denegado.descriptionDialogDenied- Descripción cuando el permiso es denegado.btnDialogDenied- Texto del botón cuando el permiso es denegado.customDeniedDialog- Diálogo composable personalizado cuando se deniega el permiso.customSettingsDialog- Diálogo composable personalizado para abrir configuración.cancelButtonText- Texto del botón cancelar (solo iOS).onCancelPermissionConfigIOS- Callback cuando el usuario cancela en iOS.
Representa el resultado de una captura de foto o selección de galería.
data class PhotoResult(
val uri: String,
val width: Int,
val height: Int,
val fileName: String? = null,
val fileSize: Long? = null,
val mimeType: String? = null,
val exif: ExifData? = null
)uri- URI de la imagen capturada/seleccionada.width- Ancho de la imagen en píxeles.height- Alto de la imagen en píxeles.fileName- Nombre del archivo (opcional).fileSize- Tamaño del archivo en bytes (opcional).mimeType- Tipo MIME de la imagen (opcional).exif- Metadatos EXIF extraídos (opcional, requiereincludeExif = true).
Contiene metadatos EXIF completos extraídos de imágenes. Disponible solo en Android e iOS.
data class ExifData(
val latitude: Double? = null,
val longitude: Double? = null,
val altitude: Double? = null,
val dateTaken: String? = null,
val dateTime: String? = null,
val digitizedTime: String? = null,
val originalTime: String? = null,
val cameraModel: String? = null,
val cameraManufacturer: String? = null,
val software: String? = null,
val owner: String? = null,
val orientation: String? = null,
val colorSpace: String? = null,
val whiteBalance: String? = null,
val flash: String? = null,
val focalLength: String? = null,
val aperture: String? = null,
val shutterSpeed: String? = null,
val iso: String? = null,
val imageWidth: Int? = null,
val imageHeight: Int? = null
)@Composable
fun ExifExample() {
val picker = rememberImagePickerKMP(
config = ImagePickerKMPConfig(
cameraCaptureConfig = CameraCaptureConfig(
includeExif = true,
redactGpsData = false // Permitir GPS (por defecto se elimina)
)
)
)
Button(onClick = { picker.launchCamera() }) {
Text("Capturar con EXIF")
}
when (val result = picker.result) {
is ImagePickerResult.Success -> {
result.first?.exif?.let { exif ->
println("GPS: ${exif.latitude}, ${exif.longitude}")
println("Cámara: ${exif.cameraModel} (${exif.cameraManufacturer})")
println("Fecha: ${exif.dateTaken}")
println("Config: ISO ${exif.iso}, f/${exif.aperture}")
println("Orientación: ${exif.orientation}")
}
}
else -> {}
}
}@Composable
fun GalleryExifExample() {
val picker = rememberImagePickerKMP(
config = ImagePickerKMPConfig(
galleryConfig = GalleryConfig(
allowMultiple = true,
includeExif = true
)
)
)
Button(onClick = { picker.launchGallery() }) {
Text("Seleccionar con EXIF")
}
when (val result = picker.result) {
is ImagePickerResult.Success -> {
result.photos.forEachIndexed { index, photo ->
println("Imagen $index:")
photo.exif?.let { exif ->
println(" Ubicación: ${exif.latitude}, ${exif.longitude}")
println(" Cámara: ${exif.cameraModel}")
println(" Fecha: ${exif.dateTaken}")
} ?: println(" Sin datos EXIF disponibles")
}
}
else -> {}
}
}| Plataforma | Soporte |
|---|---|
| Android | ✅ Completo vía androidx.exifinterface |
| iOS | ✅ Completo vía framework nativo ImageIO |
| Desktop/Web/Wasm | ❌ No soportado (devuelve null) |
Convierte el URI de la foto a un kotlinx.io.files.Path para operaciones de archivo multiplataforma.
fun PhotoResult.toPath(): Path?- Disponible desde: v1.0.38
- Retorna:
Path?—nullsi la conversión falla. - Requiere: dependencia
kotlinx-io.
Retorna la ruta absoluta del sistema de archivos como String.
val PhotoResult.absolutePath: String?- Disponible desde: v1.0.40
- Implementación por plataforma:
- Android: usa
ContentResolver - iOS: usa
URL.path - Desktop/Web: extracción directa de ruta
- Android: usa
@Composable
fun PathExample() {
val picker = rememberImagePickerKMP()
Button(onClick = { picker.launchCamera() }) {
Text("Capturar")
}
when (val result = picker.result) {
is ImagePickerResult.Success -> {
result.first?.let { photo ->
// Usando kotlinx.io Path (multiplataforma, v1.0.38+)
photo.toPath()?.let { path ->
println("Ruta del archivo: $path")
}
// Usando ruta absoluta String (v1.0.40+)
photo.absolutePath?.let { path ->
println("Ruta absoluta: $path")
}
}
}
else -> {}
}
}Composable para gestionar permisos de cámara de forma independiente.
@Composable
expect fun RequestCameraPermission(
dialogConfig: CameraPermissionDialogConfig,
onPermissionPermanentlyDenied: () -> Unit,
onResult: (Boolean) -> Unit,
customPermissionHandler: (() -> Unit)?
)dialogConfig- Configuración de los diálogos de permisos.onPermissionPermanentlyDenied- Callback cuando el permiso es denegado permanentemente.onResult- Callback con el resultado del permiso (true= concedido).customPermissionHandler- Manejador personalizado de permisos (opcional).
@Composable
fun ManejadorDePermisosPersonalizado() {
val dialogConfig = CameraPermissionDialogConfig(
titleDialogConfig = "Permiso de cámara requerido",
descriptionDialogConfig = "Por favor, habilita el acceso a la cámara en configuración",
btnDialogConfig = "Abrir configuración",
titleDialogDenied = "Permiso denegado",
descriptionDialogDenied = "Se requiere permiso de cámara",
btnDialogDenied = "Conceder permiso"
)
RequestCameraPermission(
dialogConfig = dialogConfig,
onPermissionPermanentlyDenied = {
println("Permiso denegado permanentemente")
},
onResult = { granted ->
println("Permiso concedido: $granted")
},
customPermissionHandler = null
)
}La funcionalidad de compresión optimiza automáticamente el tamaño de las imágenes manteniendo una calidad aceptable. Funciona tanto para captura de cámara como selección de galería, con niveles de compresión configurables y procesamiento asíncrono.
| Nivel | Calidad | Dimensión Máx | Caso de Uso |
|---|---|---|---|
LOW |
95% | 2560px | Compartir alta calidad, uso profesional |
MEDIUM |
75% | 1920px | Recomendado - Redes sociales, uso general |
HIGH |
50% | 1280px | Optimización de almacenamiento, miniaturas |
@Composable
fun CompressedCameraExample() {
val picker = rememberImagePickerKMP(
config = ImagePickerKMPConfig(
cameraCaptureConfig = CameraCaptureConfig(
compressionLevel = CompressionLevel.MEDIUM
)
)
)
Button(onClick = { picker.launchCamera() }) {
Text("Capturar con compresión")
}
when (val result = picker.result) {
is ImagePickerResult.Success -> {
result.first?.let { photo ->
val fileSizeKB = (photo.fileSize ?: 0) / 1024.0
println("Tamaño comprimido: ${String.format("%.2f", fileSizeKB)}KB")
println("Tamaño exacto: ${photo.fileSize} bytes")
}
}
else -> {}
}
}@Composable
fun CompressedGalleryExample() {
val picker = rememberImagePickerKMP(
config = ImagePickerKMPConfig(
galleryConfig = GalleryConfig(
allowMultiple = true,
mimeTypes = listOf(MimeType.IMAGE_JPEG, MimeType.IMAGE_PNG)
),
cameraCaptureConfig = CameraCaptureConfig(
compressionLevel = CompressionLevel.HIGH
)
)
)
Button(onClick = { picker.launchGallery() }) {
Text("Seleccionar con compresión")
}
when (val result = picker.result) {
is ImagePickerResult.Success -> {
result.photos.forEach { photo ->
val fileSizeKB = (photo.fileSize ?: 0) / 1024.0
println("Archivo: ${photo.fileName}")
println("Tamaño comprimido: ${String.format("%.2f", fileSizeKB)}KB")
}
}
else -> {}
}
}- Carga de Imagen: La imagen original se carga desde cámara/galería
- Escalado de Dimensiones: La imagen se redimensiona si es mayor que la dimensión máxima
- Compresión de Calidad: Se aplica compresión JPEG basada en el nivel
- Archivo Temporal: La imagen comprimida se guarda en caché de la app
- Entrega de Resultado: Se retorna nueva URI con la imagen comprimida
| Plataforma | Compresión Cámara | Compresión Galería | Procesamiento Asíncrono |
|---|---|---|---|
| Android | ✅ | ✅ | ✅ Coroutines |
| iOS | ✅ | ✅ | ✅ Coroutines |
- Uso de Memoria: Los bitmaps originales se reciclan después de la compresión.
- Tiempo de Procesamiento: Se ejecuta en hilos de fondo (Dispatchers.IO).
- Almacenamiento: Las imágenes comprimidas se almacenan en directorio caché de la app.
- Calidad: Balance inteligente entre tamaño de archivo y calidad visual.
Niveles de compresión para el procesamiento de imágenes.
enum class CompressionLevel {
LOW, // 95% calidad, 2560px máx — Alta calidad, archivos más grandes
MEDIUM, // 75% calidad, 1920px máx — Equilibrado (recomendado)
HIGH // 50% calidad, 1280px máx — Archivos pequeños, menor calidad
}Preferencias de captura de foto.
enum class CapturePhotoPreference {
FAST, // Captura rápida con menor calidad
BALANCED, // Balance entre velocidad y calidad
QUALITY // Máxima calidad (más lento)
}Tipos MIME soportados para filtrado de archivos.
Valores principales:
MimeType.IMAGE_ALL— Todos los formatos de imagen (image/*)MimeType.IMAGE_JPEG— Solo JPEGMimeType.IMAGE_PNG— Solo PNGMimeType.APPLICATION_PDF— Documentos PDF
Cómo se escala la vista previa de la cámara en el viewport.
enum class CameraScaleType {
FILL_CENTER, // Llena el viewport, recortando la imagen (por defecto)
FIT_CENTER // Letterbox — el encuadre coincide con la imagen capturada
}Recursos de cadenas utilizados en la librería (internacionalización automática).
enum class StringResource {
CAMERA_PERMISSION_REQUIRED,
CAMERA_PERMISSION_DESCRIPTION,
OPEN_SETTINGS,
CAMERA_PERMISSION_DENIED,
CAMERA_PERMISSION_DENIED_DESCRIPTION,
GRANT_PERMISSION,
CAMERA_PERMISSION_PERMANENTLY_DENIED,
IMAGE_CONFIRMATION_TITLE,
ACCEPT_BUTTON,
RETRY_BUTTON,
SELECT_OPTION_DIALOG_TITLE,
TAKE_PHOTO_OPTION,
SELECT_FROM_GALLERY_OPTION,
CANCEL_OPTION,
PREVIEW_IMAGE_DESCRIPTION,
HD_QUALITY_DESCRIPTION,
SD_QUALITY_DESCRIPTION,
INVALID_CONTEXT_ERROR,
PHOTO_CAPTURE_ERROR,
GALLERY_SELECTION_ERROR,
PERMISSION_ERROR,
GALLERY_PERMISSION_REQUIRED,
GALLERY_PERMISSION_DESCRIPTION,
GALLERY_PERMISSION_DENIED,
GALLERY_PERMISSION_DENIED_DESCRIPTION,
GALLERY_GRANT_PERMISSION,
GALLERY_BTN_SETTINGS
}Interfaz para registrar mensajes dentro de la librería.
interface ImagePickerLogger {
fun log(message: String)
}object DefaultLogger : ImagePickerLogger {
override fun log(message: String) {
println(message)
}
}class CustomLogger : ImagePickerLogger {
override fun log(message: String) {
Log.d("ImagePicker", message)
}
}Constantes para la interfaz de usuario.
object ImagePickerUiConstants {
const val ORIENTATION_ROTATE_90 = 90f
const val ORIENTATION_ROTATE_180 = 180f
const val ORIENTATION_ROTATE_270 = 270f
const val ORIENTATION_FLIP_HORIZONTAL_X = -1f
const val ORIENTATION_FLIP_HORIZONTAL_Y = 1f
const val ORIENTATION_FLIP_VERTICAL_X = 1f
const val ORIENTATION_FLIP_VERTICAL_Y = -1f
const val SYSTEM_VERSION_10 = 10.0
const val DELAY_TO_TAKE_PHOTO = 60L
const val SELECTION_LIMIT = 30L
}Excepción lanzada cuando ocurre un error durante la captura o procesamiento de fotos.
class PhotoCaptureException(message: String) : Exception(message)@Composable
fun ErrorHandlingExample() {
val picker = rememberImagePickerKMP()
Button(onClick = { picker.launchCamera() }) {
Text("Capturar")
}
when (val result = picker.result) {
is ImagePickerResult.Error -> {
when (result.exception) {
is PhotoCaptureException -> {
println("Error en captura: ${result.exception.message}")
}
is PermissionDeniedException -> {
println("Permiso denegado: ${result.exception.message}")
}
else -> {
println("Error desconocido: ${result.exception.message}")
}
}
}
else -> {}
}
}Excepción base para errores de la librería ImagePicker.
open class ImagePickerException(message: String) : Exception(message)Excepción lanzada cuando los permisos son denegados.
class PermissionDeniedException(message: String) : ImagePickerException(message)- Vista previa: El usuario ve la cámara en tiempo real.
- Control de flash: Botón para alternar entre Auto, On, Off.
- Cambio de cámara: Botón para alternar entre cámara trasera y frontal.
- Captura: Botón central para tomar la foto.
- Confirmación: Vista para aceptar o reintentar la foto (personalizable o desactivable).
- El sistema de permisos está gestionado automáticamente.
- Puedes personalizar completamente la UI de confirmación vía
PermissionAndConfirmationConfig. - Los textos están internacionalizados automáticamente según el idioma del dispositivo.
- El flash solo funciona en modos de calidad
BALANCEDoQUALITY. - El selector inteligente de Android elige automáticamente entre galería nativa y explorador de archivos según los tipos MIME configurados.
- Usa
redactGpsData = true(por defecto) para privacidad del usuario. - Usa
reset()para limpiar el estado y permitir nuevas capturas/selecciones.