Image Picker and Image Cropper -Compose Multiplatform

Manish Dabhi
Mobile Innovation Network
3 min readMay 31, 2024

A CMPImagePickNCrop is image picker & image cropping library for Compose Multiplatform for Android, iOS and Desktop.

Installation

Add the dependency to your `build.gradle.kts` file:

commonMain.dependencies {
implementation("network.chaintech:cmp-image-pick-n-crop:1.0.1")
}

Add Permissions in Android and iOS

  • Android : Include this at root level in your AndroidManifest.xml:
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
  • iOS : Add below key to the Info.plist in your xcode project:
<key>NSCameraUsageDescription</key><string>$(PRODUCT_NAME) camera description.</string>
<key>NSPhotoLibraryUsageDescription</key><string>$(PRODUCT_NAME)photos description.</string>

Method 1: Image Picker and Cropping an Image

In this method, we will allow users to pick an image from their device and then crop it.

Usage

@Composable
fun CMPImagePickNCropDialog(
imageCropper: ImageCropper = rememberImageCropper(),
openImagePicker: Boolean,
cropEnable: Boolean = true,
imagePickerDialogHandler: (Boolean) -> Unit,
selectedImageCallback: (ImageBitmap) -> Unit
)
  • imageCropper: Manages the image cropping logic (default is rememberImageCropper()).
  • openImagePicker: Controls whether the image picker dialog is open.
  • cropEnable: Enables or disables the image cropping feature (default is true).
  • imagePickerDialogHandler: Handles the opening and closing of the image picker dialog.
  • selectedImageCallback: Called when an image is selected and cropped, providing the cropped image.

Example

@Composable
internal fun App() = AppTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = Color.White
) {
val imageCropper = rememberImageCropper()
var selectedImage by remember { mutableStateOf<ImageBitmap?>(null) }
var openImagePicker by remember { mutableStateOf(value = false) }

CMPImagePickNCropDialog(
imageCropper = imageCropper,
openImagePicker = openImagePicker,
imagePickerDialogHandler = {
openImagePicker = it
},
selectedImageCallback = {
selectedImage = it
})

Column(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.safeContentPadding(),
horizontalAlignment = Alignment.CenterHorizontally
) {
selectedImage?.let {
Image(
bitmap = it,
contentDescription = null,
modifier = Modifier.weight(1f)
)
}
if (selectedImage == null)
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.weight(1f)
) {
Text("No image selected !", color = Color.Black)
}

Button(
onClick = {
openImagePicker = true
},
) { Text("Choose Image") }
}
}
}

Method 2: Image Cropping for Provided Image

In this method, we will focus on cropping an image that is already provided, without going through the image picking process.

Example

val selectedBitmap = remember { mutableStateOf<ImageBitmap?>(null) }
val imageCropper = rememberImageCropper()
CMPImageCropDialog(imageCropper = imageCropper)

Button(
modifier = Modifier
.weight(2F)
.padding(start = 12.dp, end = 12.dp),
onClick = {
coroutineScope.launch {
selectedBitmap.value?.let { bitmap ->
when (val result = imageCropper.cropImage(bmp = bitmap)) {
ImageCropResult.Cancelled -> {
// Handle cancellation if needed
}
is ImageCropError -> {
// Handle error if needed
}
is ImageCropResult.Success -> {
selectedBitmap.value = result.bitmap
}
}
}
}
}
) {
Text(text = "CropImage")
}

Final Demo

  • Android and iOS
  • Desktop

Conclusion

Integrating an Image Picker and image cropping library enhances functionality, streamlines processes, and improves user experience in your application.

Happy coding ❤

Connect with us 👇

--

--