All notable changes to ImagePickerKMP will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
-
CameraScaleTypeenum — configurable camera preview scale type (Android)- New
CameraScaleTypeenum:FILL_CENTER,FILL_START,FILL_END,FIT_CENTER,FIT_START,FIT_END - Controls how the camera preview is scaled inside its viewport on Android
FILL_*values fill the viewport entirely, cropping the camera feed to fitFIT_*values letterbox the preview so the entire camera feed is visible — viewfinder framing matches the captured image exactly- Currently applied on Android only; iOS uses the system camera UI where preview and capture framing already match
- New
CameraCaptureConfig.cameraScaleType: CameraScaleType— defaults toCameraScaleType.FILL_CENTER(preserves previous behavior)
- New
-
PermissionAndConfirmationConfig.confirmationImageContentScale— configurable post-capture confirmation image scale- New
confirmationImageContentScale: ContentScaleparameter inPermissionAndConfirmationConfig - Controls how the captured photo is scaled in the post-capture confirmation preview screen (Android)
- Accepts any Compose
ContentScalevalue:Crop,Fit,FillWidth,FillHeight,FillBounds,Inside,None - Defaults to
ContentScale.Crop(preserves previous behavior)
- New
- All Spanish-language inline comments across the codebase translated to English
- New
PhotoResult.absolutePathextension for direct file system path accessPhotoResult.absolutePath: String?— returns the absolute file system path as a String (platform-specific implementation)- Platform implementations:
- Android: Uses ContentResolver to resolve content:// URIs to actual file paths
- iOS: Uses URL.path to extract the file system path
- Desktop/Web: Direct path extraction from file:// URIs
- Enables direct file system access without manual URI parsing
- Complements the existing
toPath()extension for kotlinx-io compatibility
- Minor internal improvements and optimizations
- Android — Camera preview now displays correctly on Android 7–11 (API 24–30)
- Root cause:
PreviewViewwas hardcoded toImplementationMode.PERFORMANCE(SurfaceView), which does not render inside Jetpack Compose on Android ≤ API 30, resulting in a black/blank camera preview - Solution:
PreviewViewnow usesImplementationMode.COMPATIBLE(TextureView) on Android ≤ API 30, ensuring correct rendering on all supported Android versions - Changed files:
HighPerformanceConfig.requiresCompatibilityMode()now returnstrueforSDK_INT <= 30(was onlySDK_INT == 29)CameraCapturePreview.ktnow conditionally setsimplementationModebased on Android versionsetLayerType(LAYER_TYPE_HARDWARE)is no longer applied on Android ≤ API 30, eliminating the conflict with TextureView- Camera initialization delay in
CameraController.ktnow applies to Android 7–11 (was only Android 10), preventing surface-not-ready errors on older devices
- Root cause:
- New
PhotoResult.toPath()extension for cross-platform file operationsPhotoResult.toPath(): Path?— converts the photo's URI to akotlinx.io.files.Pathfor cross-platform file operations (Android, iOS, Desktop, Web)- Enables cross-platform file manipulation using kotlinx-io APIs
- Returns
nullif conversion fails - Requires
kotlinx-iodependency
- Updated Kotlin to
2.3.20 - Updated Compose Multiplatform to
1.10.3 - Updated Android Gradle Plugin to
8.13.2 - Minor stability improvements
- Improved documentation for available
PhotoResultextensions - Fixed examples in README for file path usage
rememberImagePickerKMP— unified Compose state-holder API- New top-level composable function
rememberImagePickerKMP(config)that returns anImagePickerKMPState - Replaces the manual
showCamera/showGalleryboolean pattern with a single remembered state object. NoRender()call needed — the picker self-manages whenlaunchCamera()orlaunchGallery()is invoked ImagePickerKMPState.launchCamera(cameraCaptureConfig?, enableCrop?, onDismiss?, onError?)— opens the camera picker. All parameters are optional per-launch overrides of the global configImagePickerKMPState.launchGallery(allowMultiple?, mimeTypes?, selectionLimit?, enableCrop?, includeExif?, redactGpsData?, mimeTypeMismatchMessage?, cameraCaptureConfig?, onDismiss?, onError?)— opens the gallery picker with per-launch overridesImagePickerKMPState.result: ImagePickerResult— observable reactive state;Idle | Loading | Success | Dismissed | ErrorImagePickerKMPState.reset()— resets result back toIdleand closes any active pickerImagePickerKMPConfigdata class — single configuration object for all defaults (camera, gallery, crop, UI, permissions)ImagePickerResultsealed hierarchy for exhaustive result handling.Successexposesphotos: List<PhotoResult>andfirst: PhotoResult?- All existing
ImagePickerLauncher/GalleryPickerLauncherAPIs remain fully supported
- New top-level composable function
ImagePickerLauncher— marked@Deprecated(level = WARNING). The function still compiles and runs normally, but the compiler emits a migration warning pointing torememberImagePickerKMP. Will be removed in a future major release.- Migration: Replace
ImagePickerLauncher(config = ImagePickerConfig(...))withval picker = rememberImagePickerKMP(...)+picker.launchCamera()
- Migration: Replace
GalleryPickerLauncher— marked@Deprecated(level = WARNING)for the same reason.- Migration: Replace
GalleryPickerLauncher(...)withval picker = rememberImagePickerKMP(...)+picker.launchGallery()
- Migration: Replace
Note — architectural decision:
rememberImagePickerKMPitself callsImagePickerLauncher/GalleryPickerLauncherinternally (they are the platform-specific rendering layer). The call site inside the library is annotated with@Suppress("DEPRECATION")so end-users of the new API see no warnings. Users of the legacy API directly still see the migration warning.
- Android —
ImagePickerLaunchernow rendered inside a full-screenDialog: fixes camera preview not visible when the composable is placed outside aBox(Modifier.fillMaxSize())container. The newDialogwrapper handles dismissal via back press and does not dismiss on outside click.
- BREAKING: Minimum Kotlin version is now 2.3.20
- This library is compiled with Kotlin 2.3.20. Kotlin's KMP ABI is not backward compatible across major Kotlin versions.
- Projects using Kotlin < 2.3.x will fail to compile with an error like
ABI version X.Y.Z is incompatible with current Kotlin compiler. - Migration: Update your project's Kotlin version to
2.3.20or higher. - If you need to stay on Kotlin 2.1.x, use the previous release of this library.
-
Kotlin upgraded from
2.1.21→2.3.20 -
Compose Multiplatform upgraded from
1.9.1→1.10.3(requires Kotlin 2.3.x) -
Compose Compiler plugin upgraded from
2.0.21→2.3.20(must match Kotlin version exactly) -
Ktor upgraded from
3.0.2→3.4.1(built with Kotlin 2.3.x, requires Kotlin 2.3.x consumer) -
Lifecycle Runtime Compose upgraded from
2.9.0→2.10.0 -
Activity Compose upgraded from
1.11.0→1.13.0 -
AndroidX Compose UI upgraded from
1.9.4→1.10.5 -
CameraX (
camera-core,camera-camera2,camera-lifecycle,camera-view) upgraded from1.5.1→1.5.3 -
ZXing Core upgraded from
3.5.3→3.5.4 -
Android Gradle Plugin upgraded from
8.13.0→8.13.2 -
Deprecated
ByteArray.encodeBase64()(Ktor util) replaced withBase64.Default.encode()from Kotlin stdlib -
Fixed Cropped Image Metadata (Android): Resolved issue where
GalleryPhotoResultafter cropping returned incorrect metadatafileNamenow reflects the cropped image file name instead of originalfileSizenow contains the actual cropped image size in bytes instead of originalmimeTypenow correctly shows "image/png" for cropped images instead of original format- Affects both
GalleryPickerLauncherand custom confirmation views with crop enabled - Only
exifdata is preserved from original image (as expected)
- BREAKING:
fileSizenow returns bytes instead of KB:PhotoResult.fileSizeandGalleryPhotoResult.fileSizenow return the exact file size in bytes instead of KB- Better Precision: Eliminates rounding errors that occurred with KB conversion
- S3 Compatibility: Fixes issues with S3 pre-signed URLs that require exact Content-Length in bytes
- API Compatibility: Useful for any service that requires precise byte values
- Migration Guide: To get KB from bytes, divide by 1024:
val fileSizeKB = (result.fileSize ?: 0) / 1024.0 - Updated Documentation: All examples and documentation updated to reflect byte-based sizes
- Resolved manifest merge conflict with host apps using FileProvider
-
** Automatic Image Compression**: Complete compression system for both camera and gallery
- Configurable Compression Levels: LOW (95% quality, 2560px), MEDIUM (75% quality, 1920px), HIGH (50% quality, 1280px)
- Multi-format Support: JPEG, PNG, HEIC, HEIF, WebP, GIF, BMP compression
- Async Processing: Non-blocking UI with Kotlin Coroutines integration
- Smart Optimization: Combines dimension scaling + quality compression
- Memory Efficient: Automatic bitmap recycling and cleanup
- Unified API: Same compression logic for camera capture and gallery selection
- Cross-platform: Works on both Android and iOS
- Performance Optimized: Background processing with proper thread management
-
** Automatic Context Management**: The
applyCropfunction now automatically handles Android context management- @Composable Integration: The function is now
@Composableand usesLocalContext.currentinternally - Simplified API: Developers no longer need to manually provide Android context
- Cross-platform Consistency: Same API signature for both Android and iOS implementations
- @Composable Integration: The function is now
-
** Smart Gallery vs File Explorer Picker (Android)**: Automatic detection system that determines which type of picker to open
- Automatic MIME Type Detection: Library analyzes requested MIME types and chooses appropriate picker
- Images Only (
image/*): UsesIntent.ACTION_PICK+MediaStoreto open Android's native gallery - PDFs (
application/pdf): UsesActivityResultContracts.GetContent()for file explorer access - Mixed Types: Automatically uses file explorer for maximum compatibility
- Images Only (
- New Custom Contracts:
PickImageFromGallery: Gallery-specific contract using MediaStorePickMultipleImagesFromGallery: Multiple image gallery picker
- Flexible Configuration:
AndroidGalleryConfigallows manual override when needed - Backward Compatibility: All existing code continues working without changes
- Automatic MIME Type Detection: Library analyzes requested MIME types and chooses appropriate picker
-
** AndroidGalleryConfig Configuration**: New configuration class to control Android picker behavior
forceGalleryOnly: Boolean: Forces gallery vs file explorer usagelocalOnly: Boolean: Include only local images (no cloud storage)- Convenience methods:
forMimeTypes()andforMimeTypeStrings()for automatic configuration
-
** Smart MIME Type Logic**: File processor now better handles picker type determination
- Automatic MIME type analysis to determine optimal picker strategy
- Better user experience with more appropriate pickers for each content type
- Consistent handling between single and multiple selection
-
** Optimized Android User Experience**:
- For Images: Users see native photo gallery directly
- For Documents: Users access file explorer for full navigation
- Predictable Behavior: Interface that opens matches expected content type
-
** Enhanced File Processing**:
GalleryFileProcessornow better handles different file types- Improved PDF support in processing pipeline
- Better MIME type detection and handling
- More robust metadata processing
- Updated
CameraCaptureConfigwith newcompressionLevel: CompressionLevel?parameter - Enhanced
GalleryPickerLauncherto support compression throughcameraCaptureConfig - Improved image processing pipeline with unified compression architecture
- Updated documentation with comprehensive compression examples and guides
- Made
applyCropfunction @Composable: Function signature updated to remove manual context parameter requirement - Enhanced crop aspect ratio calculations: Improved handling of vertical aspect ratios (like 9:16) with better space management
- Fixed inverted compression logic (HIGH compression now produces smaller files as expected)
- Corrected image scaling algorithm for consistent quality across compression levels
- Resolved CompressionConfig test failures by excluding IMAGE_ALL wildcard from supported formats
- ** Fixed iOS Crop Coordinate Calculations**: Resolved image cropping issues on iOS where cropped images appeared incorrectly centered
- Consistent Cross-platform Behavior: iOS now uses the same coordinate calculation logic as Android
- Accurate Image Positioning: Fixed
displayedImageSizeandimageOffsetcalculations for proper image scaling and centering - Corrected Crop Rectangle Mapping: Implemented proper
adjustedCropRectcalculation with accurate scaling factors
- ** Fixed Layout Z-Index Conflicts**: Resolved issues where crop controls appeared in wrong layer order
- Removed Problematic zIndex: Eliminated
zIndexmodifiers that caused crop area to appear below header controls - Improved Component Stacking: Natural layout flow now handles component layering correctly
- Better 9:16 Aspect Ratio Support: Crop rectangle now properly fits within available canvas space for vertical aspect ratios
- Removed Problematic zIndex: Eliminated
- ** Fixed Zoom Overlay Issues**: Resolved problem where zoomed images appeared above crop header controls
- Added Bounds Clipping: Implemented
clipToBounds()to contain zoomed content within designated area - Maintained UI Hierarchy: Zoom functionality now respects layout boundaries and doesn't interfere with header controls
- Enhanced User Experience: Crop controls remain accessible and visible during zoom operations
- Added Bounds Clipping: Implemented
- ** Gallery vs File Explorer Issue**: Fixed issue where
GalleryPickerLauncheropened downloads folder instead of gallery on Android- Implemented custom contracts that guarantee gallery usage for images
- User experience is now consistent and predictable
- Developers don't need to make changes to existing code
- Custom Permission Dialog Composables: New
customDeniedDialogandcustomSettingsDialogparameters inPermissionAndConfirmationConfigcustomDeniedDialog: Custom composable for when permission is denied (allows retry)customSettingsDialog: Custom composable for when permission is permanently denied (opens settings)
- Complete UI Control: Full customization of permission dialogs with your own composables
- Cross-platform Support: Custom permission dialogs work on both Android and iOS
- Enhanced Developer Experience: Easy-to-use API for permission dialog customization
- Updated
PermissionAndConfirmationConfigdata class with new optional parameters - Enhanced permission handling flow to support custom composable dialogs
- Improved documentation with comprehensive examples of custom permission dialogs
- Permission dialog flow now properly handles custom composables on both platforms
- Custom permission dialogs
- Custom confirmation views
- High-quality photo capture option
- Memory optimization improvements
- Better error handling and recovery
- Gallery selection support for Android and iOS
- Customizable dialog texts for iOS and Android
- Accessibility improvements: contentDescription and configurable button sizes
- JPEG compression quality configuration for image processing
- Logger interface for configurable logging
- Unit test for PhotoResult
- Linter and static analysis (ktlint, detekt) configuration
- Example and documentation for internationalization
- CI and coverage badges in README
- Internationalization (i18n) support: Complete multi-language system with type-safe string resources
- Automatic language detection: Strings adapt to device language automatically
- Support for English, Spanish, and French: Ready-to-use translations for all three languages
- Extensible language system: Easy to add new languages without external dependencies
- Automatic translations: Permission dialogs and UI texts are now automatically translated by default
- Front camera orientation correction: Automatic correction of front camera image orientation to fix mirrored/rotated photos
- Automatic gallery permission handling:
GalleryPickerLaunchernow manages gallery permissions automatically on both Android and iOS, no manual request needed. - Custom gallery permission dialog (Android): Added a dedicated, localizable dialog for gallery permissions, separate from the camera dialog.
- Multi-image selection on iOS: Implemented using
PHPickerViewController(iOS 14+), replacing the old single-image picker. - New instrumented and unit tests: Added and re-enabled tests to cover new permission flows and multi-image selection.
- Improved localization: New strings and translations for gallery permission dialogs.
- Configurable selection limit for gallery picker: Added
selectionLimitparameter toGalleryConfigto control the maximum number of images that can be selected in the gallery picker. The limit is enforced at compile time with a maximum value of 30 images to prevent performance issues and crashes when selecting too many images on iOS.
- Improved permission handling flow
- Enhanced UI components
- Better cross-platform compatibility
- Preview image in confirmation now uses FIT_CENTER to avoid zoom on gallery images
- Enhanced image processing with automatic orientation correction for front camera photos
- iOS gallery permission flow: Now requests permission directly via the system dialog, with no pre-permission custom dialog, matching native iOS behavior.
- Refactored permission logic: Gallery and camera permission handling is now more consistent and cross-platform.
- Gallery selection limit: Changed from unlimited selection (0) to configurable limit with maximum of 30 images to prevent performance issues and crashes on iOS when selecting too many images.
- iOS permission denial flow
- Android camera initialization issues
- Memory leaks in photo processing
- Permission dialog display issues
- Disparador (capture button) always centered, gallery button does not push it
- Front camera photos appearing mirrored or incorrectly oriented
- Dialog text errors: Gallery permission dialog no longer shows camera texts.
- Multi-image selection bugs: Fixed performance issues and crashes when selecting many images on iOS.
- Threading and casting errors: Resolved concurrency and type conversion issues in image selection.
- iOS gallery performance issues: Fixed crashes and performance degradation when selecting more than 30 images by implementing a configurable selection limit with compile-time validation.
- Thoroughly updated all Markdown documentation files to ensure all usage examples of
ImagePickerLauncher,GalleryPickerLauncher, and related components reflect the current, real API. - Replaced all outdated examples using the old API (with top-level callbacks and handlers) with the correct pattern: all configuration and handlers are now shown nested inside
config = ImagePickerConfig(...), with custom handlers further nested as required. - Ensured all documentation in both English and Spanish is fully synchronized and accurate.
- All examples and guides updated to reflect new automatic permission handling and multi-image selection on iOS.
- Added notes on platform differences for permission and selection behavior (Android vs iOS).
- First Official Release of ImagePickerKMP
- Cross-platform camera integration for Android and iOS
- High-quality photo capture with preview and confirmation
- Smart permission handling for both platforms
- Customizable UI components with Compose Multiplatform
- Comprehensive error handling and user feedback
- Photo result data class with metadata
- Capture preferences (FAST, BALANCED, HIGH_QUALITY)
- Gallery selection support for both platforms
- Internationalization (i18n) with English, Spanish, and French
- Front camera orientation correction to fix mirrored photos
- Memory optimization and performance improvements
- Extensive documentation and examples
- CI/CD pipeline with automated testing and deployment
- Code coverage and quality assurance
- Android Support: Full camera integration using CameraX with modern UI
- iOS Support: Native camera integration using AVFoundation
- Permission Management: Smart permission handling with custom dialogs
- Photo Capture: High-quality photo capture with automatic orientation correction
- Error Handling: Comprehensive error handling with specific exception types
- Customization: Extensive customization options for UI and behavior
- Internationalization: Multi-language support with automatic detection
- Testing: Complete test suite with unit and UI tests
- Documentation: Comprehensive guides and API reference
- Minimum SDK: Android API 21+, iOS 12.0+
- Kotlin Version: 1.9+
- Compose Multiplatform: Full support with Material components
- Dependencies: Optimized external dependencies
- Code Coverage: >40% with comprehensive testing
- CI/CD: Automated build, test, and deployment pipeline
- Beta release for testing
- Core camera functionality
- Basic permission handling
- Photo capture and preview
- Error handling framework
- iOS permission flow incomplete
- Memory optimization needed
- Limited customization options
- Alpha release
- Basic camera integration
- Permission request handling
- Photo capture functionality
- Android only
- Basic UI
- Limited error handling
- Initial development release
- Project structure setup
- Basic camera functionality
- Permission handling
- Release Date: January 15, 2024
- Status: Stable
- Key Features:
- Cross-platform camera integration
- Smart permission handling
- High-quality photo capture
- Comprehensive error handling
- Customizable UI components
- Release Date: January 10, 2024
- Status: Beta
- Key Features:
- Core functionality complete
- Basic permission handling
- Photo capture and preview
- Error handling framework
- Release Date: January 5, 2024
- Status: Alpha
- Key Features:
- Basic camera integration
- Permission request handling
- Photo capture functionality
- Release Date: January 1, 2024
- Status: Development
- Key Features:
- Project structure setup
- Basic camera functionality
- Permission handling
- Updated permission handling API
- Changed error handling structure
- Modified photo result data class
-
Update Dependencies
// Old implementation("io.github.ismoy:imagepickerkmp:0.9.0") // New implementation("io.github.ismoy:imagepickerkmp:1.0.22")
-
Update Permission Handling
// Old RequestCameraPermission( onPermissionGranted = { /* ... */ }, onPermissionDenied = { /* ... */ } ) // New RequestCameraPermission( onPermissionPermanentlyDenied = { /* ... */ }, onResult = { granted -> /* ... */ } )
-
Update Error Handling
// Old onError = { error -> // Handle generic error } // New onError = { exception -> when (exception) { is CameraPermissionException -> { /* ... */ } is PhotoCaptureException -> { /* ... */ } else -> { /* ... */ } } }
- Added iOS support
- Updated API structure
- Changed permission handling
-
Update Platform Support
// Old (Android only) ImagePickerLauncher( context = LocalContext.current, // ... ) // New (Cross-platform) ImagePickerLauncher( context = LocalContext.current, // null for iOS // ... )
-
Update Permission Handling
// Old requestCameraPermission() // New RequestCameraPermission( onPermissionGranted = { /* ... */ }, onPermissionDenied = { /* ... */ } )
- No deprecated features in current version
- Deprecated features will be removed in the next major version
- Users will be notified 6 months before removal
- Migration guides will be provided
| Version | Android API | iOS Version | Kotlin Version | Compose Version |
|---|---|---|---|---|
| 1.0.1 | 21+ | 12.0+ | 1.8+ | 1.4+ |
| 0.9.0 | 21+ | 12.0+ | 1.8+ | 1.4+ |
| 0.8.0 | 21+ | N/A | 1.8+ | 1.4+ |
| 0.7.0 | 21+ | N/A | 1.8+ | 1.4+ |
-
Issue: Memory usage high with large photos
- Status: Fixed in next release
- Workaround: Use image compression
-
Issue: iOS permission dialog sometimes doesn't show
- Status: Fixed in next release
- Workaround: Use custom permission handler
- Issue: Camera initialization slow on some devices
- Status: Fixed in 1.0.1
- Workaround: Use FAST capture preference
- Issue: Permission handling incomplete
- Status: Fixed in 0.9.0
- Workaround: Manual permission handling
-
Features:
- Custom UI themes
- Video capture support
- Image filters and effects
- Batch photo capture
- Features:
- AR camera integration
- Real-time filters
- Social media sharing
- Cloud storage integration
- Advanced editing tools
- Features:
- Complete UI redesign
- Advanced customization
- Plugin system
- Performance optimizations
- Extended platform support
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
# Clone the repository
git clone https://github.com/ismoy/ImagePickerKMP.git
# Navigate to project directory
cd ImagePickerKMP
# Build the project
./gradlew build
# Run tests
./gradlew test- Version Bump: Update version in
build.gradle.kts - Changelog: Update this changelog
- Tests: Run all tests
- Documentation: Update documentation
- Release: Create GitHub release
- Publish: Publish to Maven Central
- Documentation: README.md
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: belizairesmoy72@gmail.com
When reporting issues, please include:
- Version number
- Platform (Android/iOS)
- Device information
- Steps to reproduce
- Expected vs actual behavior
- Logs (if applicable)
For feature requests, please:
- Check existing issues first
- Provide detailed description
- Include use case examples
- Consider implementation complexity
Note: This changelog is maintained by the ImagePickerKMP team. For questions or suggestions, please contact us.