From 230d917a5a6c12647a67359416aaadab3b88ec7c Mon Sep 17 00:00:00 2001 From: thomas kiljanczyk dev Date: Mon, 29 Dec 2025 16:33:08 +0100 Subject: [PATCH 1/3] #7 Maintain a reference to the original bitmap in `CropState` to ensure cropping operations are performed on the source image data rather than a potentially modified or scaled version. - Added `originalBitmap` property to `CropState`. - Updated `CropStateManager` to initialize `CropState` with the bitmap as both the display and original bitmap. - Modified the `crop()` function to use `originalBitmap` for the cropping operation. --- .../main/java/com/tanishranjan/cropkit/internal/CropState.kt | 1 + .../com/tanishranjan/cropkit/internal/CropStateManager.kt | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt index 8a8af54..8e4dff8 100644 --- a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt +++ b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt @@ -20,6 +20,7 @@ import com.tanishranjan.cropkit.HandlesRect * @param aspectRatio The aspect ratio of the crop rectangle. */ internal data class CropState( + val originalBitmap: Bitmap, val bitmap: Bitmap, val imageBitmap: ImageBitmap? = null, val cropRect: Rect = Rect.Zero, diff --git a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt index 47c1033..6a2b3b8 100644 --- a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt +++ b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt @@ -33,7 +33,7 @@ internal class CropStateManager( private val touchPadding: Dp ) { - private val _state = MutableStateFlow(CropState(bitmap)) + private val _state = MutableStateFlow(CropState(bitmap, bitmap)) val state = _state.asStateFlow() private val coroutineScope = CoroutineScope(Dispatchers.Main) private var dragMode: DragMode = DragMode.None @@ -49,9 +49,8 @@ internal class CropStateManager( } fun crop(): Bitmap { - val state = state.value - val bitmap = state.bitmap + val bitmap = state.originalBitmap val imageRect = state.imageRect val cropRect = state.cropRect From ad10444a0c58b8cc77657a25e4a728730417d975 Mon Sep 17 00:00:00 2001 From: thomas kiljanczyk dev Date: Mon, 29 Dec 2025 17:11:17 +0100 Subject: [PATCH 2/3] #7 improve the new crop logic to also work with image flipping and rotating --- .../java/com/tanishranjan/cropkit/internal/CropState.kt | 3 ++- .../tanishranjan/cropkit/internal/CropStateManager.kt | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt index 8e4dff8..2517c2a 100644 --- a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt +++ b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt @@ -10,6 +10,7 @@ import com.tanishranjan.cropkit.HandlesRect * Represents the state of the crop operation. * * @param bitmap The bitmap of the image. + * @param scaledBitmap The scaled bitmap of the image. * @param imageBitmap The image bitmap of the image. * @param cropRect The crop rectangle. * @param imageRect The image rectangle. @@ -20,8 +21,8 @@ import com.tanishranjan.cropkit.HandlesRect * @param aspectRatio The aspect ratio of the crop rectangle. */ internal data class CropState( - val originalBitmap: Bitmap, val bitmap: Bitmap, + val scaledBitmap: Bitmap, val imageBitmap: ImageBitmap? = null, val cropRect: Rect = Rect.Zero, val imageRect: Rect = Rect.Zero, diff --git a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt index 6a2b3b8..ead174d 100644 --- a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt +++ b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt @@ -50,7 +50,7 @@ internal class CropStateManager( fun crop(): Bitmap { val state = state.value - val bitmap = state.originalBitmap + val bitmap = state.bitmap val imageRect = state.imageRect val cropRect = state.cropRect @@ -308,7 +308,7 @@ internal class CropStateManager( contentScale = contentScale ) - val newBitmap = bitmap.scale(scaledSize.width.toInt(), scaledSize.height.toInt()) + val newScaledBitmap = bitmap.scale(scaledSize.width.toInt(), scaledSize.height.toInt()) val offsetX = (canvasSize.width - scaledSize.width) / 2f val offsetY = (canvasSize.height - scaledSize.height) / 2f @@ -349,12 +349,13 @@ internal class CropStateManager( _state.update { it.copy( canvasSize = canvasSize, - bitmap = newBitmap, + bitmap = bitmap, + scaledBitmap = newScaledBitmap, imageRect = Rect( Offset(offsetX, offsetY), Size(scaledSize.width, scaledSize.height) ), - imageBitmap = newBitmap.asImageBitmap(), + imageBitmap = newScaledBitmap.asImageBitmap(), cropRect = cropRect, handles = GestureUtils.getNewHandleMeasures(cropRect, handleRadiusPx), gridlinesActive = gridLinesVisibility == GridLinesVisibility.ALWAYS, From 8a6525e916c7c57bb1653f58af25742d01dec606 Mon Sep 17 00:00:00 2001 From: thomas kiljanczyk dev Date: Mon, 29 Dec 2025 23:52:10 +0100 Subject: [PATCH 3/3] #7 remove unneeded scaledBitmap property from the CropState --- .../java/com/tanishranjan/cropkit/internal/CropState.kt | 2 -- .../com/tanishranjan/cropkit/internal/CropStateManager.kt | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt index 2517c2a..8a8af54 100644 --- a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt +++ b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropState.kt @@ -10,7 +10,6 @@ import com.tanishranjan.cropkit.HandlesRect * Represents the state of the crop operation. * * @param bitmap The bitmap of the image. - * @param scaledBitmap The scaled bitmap of the image. * @param imageBitmap The image bitmap of the image. * @param cropRect The crop rectangle. * @param imageRect The image rectangle. @@ -22,7 +21,6 @@ import com.tanishranjan.cropkit.HandlesRect */ internal data class CropState( val bitmap: Bitmap, - val scaledBitmap: Bitmap, val imageBitmap: ImageBitmap? = null, val cropRect: Rect = Rect.Zero, val imageRect: Rect = Rect.Zero, diff --git a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt index ead174d..3522acd 100644 --- a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt +++ b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt @@ -33,7 +33,7 @@ internal class CropStateManager( private val touchPadding: Dp ) { - private val _state = MutableStateFlow(CropState(bitmap, bitmap)) + private val _state = MutableStateFlow(CropState(bitmap)) val state = _state.asStateFlow() private val coroutineScope = CoroutineScope(Dispatchers.Main) private var dragMode: DragMode = DragMode.None @@ -308,7 +308,7 @@ internal class CropStateManager( contentScale = contentScale ) - val newScaledBitmap = bitmap.scale(scaledSize.width.toInt(), scaledSize.height.toInt()) + val scaledBitmap = bitmap.scale(scaledSize.width.toInt(), scaledSize.height.toInt()) val offsetX = (canvasSize.width - scaledSize.width) / 2f val offsetY = (canvasSize.height - scaledSize.height) / 2f @@ -350,12 +350,11 @@ internal class CropStateManager( it.copy( canvasSize = canvasSize, bitmap = bitmap, - scaledBitmap = newScaledBitmap, imageRect = Rect( Offset(offsetX, offsetY), Size(scaledSize.width, scaledSize.height) ), - imageBitmap = newScaledBitmap.asImageBitmap(), + imageBitmap = scaledBitmap.asImageBitmap(), cropRect = cropRect, handles = GestureUtils.getNewHandleMeasures(cropRect, handleRadiusPx), gridlinesActive = gridLinesVisibility == GridLinesVisibility.ALWAYS,