From 351d9e52129b877a3ab962ea334c745ef168647a Mon Sep 17 00:00:00 2001 From: thomas kiljanczyk dev Date: Mon, 29 Dec 2025 17:32:39 +0100 Subject: [PATCH 1/2] #9 Feat: Add content padding to canvas scaling for better touch handle accessibility - Introduced `contentPadding` based on `touchPadding` to ensure crop handles at the edges remain within the interactive canvas bounds. - Updated `scaledSize` calculation and offset positioning to account for the new padding, centering the bitmap within the available padded space. --- .../cropkit/internal/CropStateManager.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) 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..9fb1c29 100644 --- a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt +++ b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt @@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlin.math.abs +import kotlin.math.ceil internal class CropStateManager( bitmap: Bitmap, @@ -301,18 +302,25 @@ internal class CropStateManager( val imageWidth = bitmap.width.toFloat() val imageHeight = bitmap.height.toFloat() + // Add content padding equal to touchPadding so handles at edges + // always have their full touch area within the canvas bounds + val contentPadding = ceil(touchPadding.value) * density + val availableWidth = canvasSize.width - contentPadding * 2 + val availableHeight = canvasSize.height - contentPadding * 2 + val scaledSize = MathUtils.calculateScaledSize( srcWidth = imageWidth, srcHeight = imageHeight, - dstWidth = canvasSize.width, - dstHeight = canvasSize.height, + dstWidth = availableWidth, + dstHeight = availableHeight, contentScale = contentScale ) val newBitmap = bitmap.scale(scaledSize.width.toInt(), scaledSize.height.toInt()) - val offsetX = (canvasSize.width - scaledSize.width) / 2f - val offsetY = (canvasSize.height - scaledSize.height) / 2f + // Center within available space, then add padding offset + val offsetX = contentPadding + (availableWidth - scaledSize.width) / 2f + val offsetY = contentPadding + (availableHeight - scaledSize.height) / 2f val aspectRatio = when (cropShape) { is CropShape.FreeForm -> null From c7507a60af9df3964f540ff2cc996e211a92775b Mon Sep 17 00:00:00 2001 From: thomas kiljanczyk dev Date: Mon, 29 Dec 2025 17:35:23 +0100 Subject: [PATCH 2/2] #9 Remove unneeded ceil from touchPadding in CropStateManager.setState --- .../java/com/tanishranjan/cropkit/internal/CropStateManager.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 9fb1c29..503ccf4 100644 --- a/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt +++ b/cropkit/src/main/java/com/tanishranjan/cropkit/internal/CropStateManager.kt @@ -23,7 +23,6 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlin.math.abs -import kotlin.math.ceil internal class CropStateManager( bitmap: Bitmap, @@ -304,7 +303,7 @@ internal class CropStateManager( // Add content padding equal to touchPadding so handles at edges // always have their full touch area within the canvas bounds - val contentPadding = ceil(touchPadding.value) * density + val contentPadding = touchPadding.value * density val availableWidth = canvasSize.width - contentPadding * 2 val availableHeight = canvasSize.height - contentPadding * 2