Skip to content

Commit 040a76a

Browse files
add CropAgent to ImageCropper
ImageCropper composable can crop to shapes using CropAgent
1 parent 93b7051 commit 040a76a

File tree

2 files changed

+64
-29
lines changed

2 files changed

+64
-29
lines changed

app/src/main/java/com/smarttoolfactory/composecropper/demo/ImageCropDemo.kt

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ package com.smarttoolfactory.composecropper.demo
44

55
import androidx.compose.foundation.Image
66
import androidx.compose.foundation.background
7-
import androidx.compose.foundation.layout.*
8-
import androidx.compose.foundation.rememberScrollState
7+
import androidx.compose.foundation.layout.Box
8+
import androidx.compose.foundation.layout.Column
9+
import androidx.compose.foundation.layout.fillMaxSize
10+
import androidx.compose.foundation.layout.fillMaxWidth
911
import androidx.compose.foundation.shape.RoundedCornerShape
10-
import androidx.compose.foundation.verticalScroll
1112
import androidx.compose.material.*
1213
import androidx.compose.material.icons.Icons
1314
import androidx.compose.material.icons.filled.Brush
@@ -31,7 +32,6 @@ import com.smarttoolfactory.composecropper.ImageSelectionButton
3132
import com.smarttoolfactory.composecropper.R
3233
import com.smarttoolfactory.composecropper.preferences.CropStyleSelectionMenu
3334
import com.smarttoolfactory.composecropper.preferences.PropertySelectionSheet
34-
3535
import com.smarttoolfactory.cropper.ImageCropper
3636
import com.smarttoolfactory.cropper.settings.CropDefaults
3737
import com.smarttoolfactory.cropper.settings.CropProperties
@@ -122,31 +122,32 @@ private fun MainContent(
122122
var imageBitmap by remember { mutableStateOf(imageBitmapLarge) }
123123
var croppedImage by remember { mutableStateOf<ImageBitmap?>(null) }
124124

125-
val modifier = Modifier
126-
.background(Color.LightGray)
127-
.fillMaxWidth()
128-
.aspectRatio(3 / 4f)
129125

130126
var crop by remember { mutableStateOf(false) }
131127
var showDialog by remember { mutableStateOf(false) }
128+
var isCropping by remember { mutableStateOf(false) }
132129

133-
134-
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
135-
Column(
136-
modifier = Modifier
137-
.fillMaxSize()
138-
.verticalScroll(rememberScrollState())
139-
) {
130+
Box(
131+
modifier = Modifier
132+
.fillMaxSize()
133+
.background(Color.DarkGray),
134+
contentAlignment = Alignment.Center
135+
) {
136+
Column(modifier = Modifier.fillMaxSize()) {
140137

141138
ImageCropper(
142-
modifier = modifier,
139+
modifier = Modifier.fillMaxWidth().weight(1f),
143140
imageBitmap = imageBitmap,
144141
contentDescription = "Image Cropper",
145142
cropStyle = cropStyle,
146143
cropProperties = cropProperties,
147144
crop = crop,
145+
onCropStart = {
146+
isCropping = true
147+
}
148148
) {
149149
croppedImage = it
150+
isCropping = false
150151
crop = false
151152
showDialog = true
152153
}
@@ -190,6 +191,10 @@ private fun MainContent(
190191
)
191192
}
192193
)
194+
195+
if (isCropping) {
196+
CircularProgressIndicator()
197+
}
193198
}
194199

195200
if (showDialog) {

cropper/src/main/java/com/smarttoolfactory/cropper/Cropper.kt renamed to cropper/src/main/java/com/smarttoolfactory/cropper/ImageCropper.kt

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.smarttoolfactory.cropper
22

3-
import android.graphics.Bitmap
43
import androidx.compose.foundation.layout.Box
54
import androidx.compose.foundation.layout.size
65
import androidx.compose.material.Text
@@ -11,19 +10,27 @@ import androidx.compose.ui.Alignment
1110
import androidx.compose.ui.Modifier
1211
import androidx.compose.ui.draw.clipToBounds
1312
import androidx.compose.ui.geometry.Rect
14-
import androidx.compose.ui.graphics.*
13+
import androidx.compose.ui.graphics.Color
14+
import androidx.compose.ui.graphics.FilterQuality
15+
import androidx.compose.ui.graphics.ImageBitmap
16+
import androidx.compose.ui.graphics.Shape
1517
import androidx.compose.ui.graphics.drawscope.DrawScope
1618
import androidx.compose.ui.platform.LocalDensity
19+
import androidx.compose.ui.platform.LocalLayoutDirection
1720
import androidx.compose.ui.unit.Dp
1821
import androidx.compose.ui.unit.IntSize
1922
import androidx.compose.ui.unit.sp
23+
import com.smarttoolfactory.cropper.crop.CropAgent
2024
import com.smarttoolfactory.cropper.image.ImageWithConstraints
2125
import com.smarttoolfactory.cropper.image.getScaledImageBitmap
2226
import com.smarttoolfactory.cropper.settings.CropDefaults
2327
import com.smarttoolfactory.cropper.settings.CropProperties
2428
import com.smarttoolfactory.cropper.settings.CropStyle
2529
import com.smarttoolfactory.cropper.settings.CropType
2630
import com.smarttoolfactory.cropper.state.rememberCropState
31+
import kotlinx.coroutines.Dispatchers
32+
import kotlinx.coroutines.delay
33+
import kotlinx.coroutines.flow.*
2734

2835
@Composable
2936
fun ImageCropper(
@@ -34,6 +41,7 @@ fun ImageCropper(
3441
cropProperties: CropProperties = CropDefaults.properties(),
3542
filterQuality: FilterQuality = DrawScope.DefaultFilterQuality,
3643
crop: Boolean = false,
44+
onCropStart: () -> Unit,
3745
onCropSuccess: (ImageBitmap) -> Unit
3846
) {
3947

@@ -57,6 +65,10 @@ fun ImageCropper(
5765
contentScale = cropProperties.contentScale,
5866
)
5967

68+
val cropAgent = remember {
69+
CropAgent()
70+
}
71+
6072
// Container Dimensions
6173
val containerWidthPx = constraints.maxWidth
6274
val containerHeightPx = constraints.maxHeight
@@ -81,6 +93,7 @@ fun ImageCropper(
8193

8294
val cropType = cropProperties.cropType
8395
val contentScale = cropProperties.contentScale
96+
val shape = cropProperties.cropShape.shape
8497

8598
// these keys are for resetting cropper when image width/height, contentScale or
8699
// overlay aspect ratio changes
@@ -124,17 +137,31 @@ fun ImageCropper(
124137
val pan = cropState.pan
125138
val zoom = cropState.zoom
126139

140+
val density = LocalDensity.current
141+
val layoutDirection = LocalLayoutDirection.current
142+
127143
LaunchedEffect(crop) {
128144
if (crop) {
129-
val croppedBitmap = Bitmap.createBitmap(
130-
scaledImageBitmap.asAndroidBitmap(),
131-
rectCrop.left.toInt(),
132-
rectCrop.top.toInt(),
133-
rectCrop.width.toInt(),
134-
rectCrop.height.toInt()
135-
).asImageBitmap()
136-
137-
onCropSuccess(croppedBitmap)
145+
flow {
146+
emit(
147+
cropAgent.crop(
148+
scaledImageBitmap,
149+
rectCrop,
150+
shape,
151+
layoutDirection,
152+
density
153+
)
154+
)
155+
}
156+
.flowOn(Dispatchers.Default)
157+
.onStart {
158+
onCropStart()
159+
delay(400)
160+
}
161+
.onEach {
162+
onCropSuccess(it)
163+
}
164+
.launchIn(this)
138165
}
139166
}
140167

@@ -146,14 +173,15 @@ fun ImageCropper(
146173
)
147174

148175
Box {
149-
CropperImpl(
176+
ImageCropperImpl(
150177
modifier = imageModifier,
151178
imageBitmap = scaledImageBitmap,
152179
containerWidth = containerWidth,
153180
containerHeight = containerHeight,
154181
imageWidthPx = imageWidthPx,
155182
imageHeightPx = imageHeightPx,
156183
cropType = cropType,
184+
shape = shape,
157185
handleSize = cropProperties.handleSize,
158186
cropStyle = cropStyle,
159187
rectOverlay = cropState.overlayRect
@@ -176,14 +204,15 @@ fun ImageCropper(
176204
}
177205

178206
@Composable
179-
private fun CropperImpl(
207+
private fun ImageCropperImpl(
180208
modifier: Modifier,
181209
imageBitmap: ImageBitmap,
182210
containerWidth: Dp,
183211
containerHeight: Dp,
184212
imageWidthPx: Int,
185213
imageHeightPx: Int,
186214
cropType: CropType,
215+
shape: Shape,
187216
handleSize: Dp,
188217
cropStyle: CropStyle,
189218
rectOverlay: Rect
@@ -213,6 +242,7 @@ private fun CropperImpl(
213242
modifier = Modifier.size(containerWidth, containerHeight),
214243
drawOverlay = drawOverlay,
215244
rect = rectOverlay,
245+
shape = shape,
216246
drawGrid = drawGrid,
217247
overlayColor = overlayColor,
218248
handleColor = handleColor,

0 commit comments

Comments
 (0)