Reputation: 197
I have searched everywhere but didn't got a single documentation about cropping images in Jetpack Compose
How to crop Image in Jetpack Compose?
Upvotes: 14
Views: 13775
Reputation: 67218
I built one for Jetpack Compose that can crop with static, dynamic overlays with animations and custom shapes and many customization options.
It's production ready now, but still some features in progress and in to-do If you would like to test it out, help with issues, here is the link
https://github.com/SmartToolFactory/Compose-Cropper
@Composable
private fun MainContent(
cropProperties: CropProperties,
cropStyle: CropStyle,
onSelectionPageMenuClicked: (SelectionPage) -> Unit
) {
val imageBitmapLarge = ImageBitmap.imageResource(
LocalContext.current.resources,
R.drawable.landscape1
)
var imageBitmap by remember { mutableStateOf(imageBitmapLarge) }
var croppedImage by remember { mutableStateOf<ImageBitmap?>(null) }
var crop by remember { mutableStateOf(false) }
var showDialog by remember { mutableStateOf(false) }
var isCropping by remember { mutableStateOf(false) }
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.DarkGray),
contentAlignment = Alignment.Center
) {
Column(modifier = Modifier.fillMaxSize()) {
ImageCropper(
modifier = Modifier.fillMaxWidth().weight(1f),
imageBitmap = imageBitmap,
contentDescription = "Image Cropper",
cropStyle = cropStyle,
cropProperties = cropProperties,
crop = crop,
onCropStart = {
isCropping = true
}
) {
croppedImage = it
isCropping = false
crop = false
showDialog = true
}
}
BottomAppBar(
modifier = Modifier.align(Alignment.BottomStart),
actions = {
IconButton(
onClick = {
onSelectionPageMenuClicked(SelectionPage.Properties)
}
) {
Icon(
Icons.Filled.Settings,
contentDescription = "Settings",
)
}
IconButton(
onClick = {
onSelectionPageMenuClicked(SelectionPage.Style)
}
) {
Icon(Icons.Filled.Brush, contentDescription = "Style")
}
IconButton(
onClick = { crop = true }) {
Icon(Icons.Filled.Crop, contentDescription = "Crop Image")
}
},
floatingActionButton = {
ImageSelectionButton(
elevation = FloatingActionButtonDefaults.elevation(defaultElevation = 0.dp),
onImageSelected = { bitmap: ImageBitmap ->
imageBitmap = bitmap
}
)
}
)
if (isCropping) {
CircularProgressIndicator()
}
}
if (showDialog) {
croppedImage?.let {
ShowCroppedImageDialog(imageBitmap = it) {
showDialog = !showDialog
croppedImage = null
}
}
}
}
Upvotes: 11
Reputation: 616
You can actually just use those older Android libraries no problem.
I used this one: https://github.com/CanHub/Android-Image-Cropper
Project build.gradle:
allprojects {
repositories {
google()
mavenCentral()
maven(url = "https://jitpack.io")
}
}
App build.gradle:
implementation("com.github.CanHub:Android-Image-Cropper:4.0.0")
Usage (CropImageContract is provided by the above):
@Composable
fun ImageSelectorAndCropper() {
var imageUri by remember {
mutableStateOf<Uri?>(null)
}
val context = LocalContext.current
val bitmap = remember {
mutableStateOf<Bitmap?>(null)
}
val imageCropLauncher = rememberLauncherForActivityResult(CropImageContract()) { result ->
if (result.isSuccessful) {
// use the cropped image
imageUri = result.uriContent
} else {
// an error occurred cropping
val exception = result.error
}
}
val imagePickerLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()) { uri: Uri? ->
val cropOptions = CropImageContractOptions(uri, CropImageOptions())
imageCropLauncher.launch(cropOptions)
}
if (imageUri != null) {
if (Build.VERSION.SDK_INT < 28) {
bitmap.value = MediaStore.Images.Media.getBitmap(context.contentResolver, imageUri)
} else {
val source = ImageDecoder.createSource(context.contentResolver, imageUri!!)
bitmap.value = ImageDecoder.decodeBitmap(source)
}
Button(onClick = { imagePickerLauncher.launch("image/*") }) {
Text("Pick image to crop")
}
}
}
Edit:
I also had to add this to the manifest so that the CropActivity picks up a theme
<activity android:name="com.canhub.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat"/>
Upvotes: 12