Skip to content

Commit

Permalink
Added Draw Path Mode selection for background eraser by #1319
Browse files Browse the repository at this point in the history
  • Loading branch information
T8RIN committed Sep 14, 2024
1 parent ef4de44 commit ee56dd3
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ import ru.tech.imageresizershrinker.core.ui.widget.image.AutoFilePicker
import ru.tech.imageresizershrinker.core.ui.widget.image.ImageNotPickedWidget
import ru.tech.imageresizershrinker.core.ui.widget.modifier.container
import ru.tech.imageresizershrinker.core.ui.widget.modifier.drawHorizontalStroke
import ru.tech.imageresizershrinker.core.ui.widget.other.BoxAnimatedVisibility
import ru.tech.imageresizershrinker.core.ui.widget.other.DrawLockScreenOrientation
import ru.tech.imageresizershrinker.core.ui.widget.other.EnhancedTopAppBar
import ru.tech.imageresizershrinker.core.ui.widget.other.EnhancedTopAppBarType
Expand All @@ -141,7 +142,9 @@ import ru.tech.imageresizershrinker.core.ui.widget.preferences.PreferenceRowSwit
import ru.tech.imageresizershrinker.core.ui.widget.sheets.ProcessImagesPreferenceSheet
import ru.tech.imageresizershrinker.core.ui.widget.sheets.SimpleSheetDefaults
import ru.tech.imageresizershrinker.core.ui.widget.text.marquee
import ru.tech.imageresizershrinker.feature.draw.domain.DrawPathMode
import ru.tech.imageresizershrinker.feature.draw.presentation.components.BrushSoftnessSelector
import ru.tech.imageresizershrinker.feature.draw.presentation.components.DrawPathModeSelector
import ru.tech.imageresizershrinker.feature.draw.presentation.components.LineWidthSelector
import ru.tech.imageresizershrinker.feature.draw.presentation.components.PtSaver
import ru.tech.imageresizershrinker.feature.erase_background.presentation.components.AutoEraseBackgroundCard
Expand All @@ -150,7 +153,6 @@ import ru.tech.imageresizershrinker.feature.erase_background.presentation.compon
import ru.tech.imageresizershrinker.feature.erase_background.presentation.components.RecoverModeButton
import ru.tech.imageresizershrinker.feature.erase_background.presentation.components.RecoverModeCard
import ru.tech.imageresizershrinker.feature.erase_background.presentation.components.TrimImageToggle
import ru.tech.imageresizershrinker.feature.erase_background.presentation.components.UseLassoSelector
import ru.tech.imageresizershrinker.feature.erase_background.presentation.viewModel.EraseBackgroundViewModel

@OptIn(ExperimentalMaterial3Api::class)
Expand Down Expand Up @@ -250,9 +252,7 @@ fun EraseBackgroundContent(
)
}

var useLasso by rememberSaveable {
mutableStateOf(false)
}
val drawPathMode = viewModel.drawPathMode

var originalImagePreviewAlpha by rememberSaveable {
mutableFloatStateOf(0.2f)
Expand Down Expand Up @@ -345,7 +345,7 @@ fun EraseBackgroundContent(
.fillMaxSize(),
panEnabled = panEnabled,
originalImagePreviewAlpha = originalImagePreviewAlpha,
useLasso = useLasso
drawPathMode = drawPathMode
)
}
}
Expand Down Expand Up @@ -521,18 +521,31 @@ fun EraseBackgroundContent(
},
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp)
)
UseLassoSelector(
value = useLasso,
onValueChange = {
useLasso = it
},
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp)
)
LineWidthSelector(
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp),
value = strokeWidth.value,
onValueChange = { strokeWidth = it.pt }
DrawPathModeSelector(
modifier = Modifier.padding(
start = 16.dp,
end = 16.dp,
top = 8.dp
),
value = drawPathMode,
onValueChange = viewModel::updateDrawPathMode,
values = remember {
listOf(
DrawPathMode.Free,
DrawPathMode.Line,
DrawPathMode.Lasso,
DrawPathMode.Rect(),
DrawPathMode.Oval
)
}
)
BoxAnimatedVisibility(drawPathMode.isStroke) {
LineWidthSelector(
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp),
value = strokeWidth.value,
onValueChange = { strokeWidth = it.pt }
)
}
BrushSoftnessSelector(
modifier = Modifier
.padding(top = 8.dp, end = 16.dp, start = 16.dp),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,17 @@ import ru.tech.imageresizershrinker.core.ui.widget.modifier.smartDelayAfterDownI
import ru.tech.imageresizershrinker.core.ui.widget.modifier.transparencyChecker
import ru.tech.imageresizershrinker.feature.draw.domain.DrawPathMode
import ru.tech.imageresizershrinker.feature.draw.presentation.components.UiPathPaint
import ru.tech.imageresizershrinker.feature.draw.presentation.components.utils.rememberPathHelper

@Composable
fun BitmapEraser(
imageBitmap: ImageBitmap,
imageBitmapForShader: ImageBitmap?,
paths: List<UiPathPaint>,
brushSoftness: Pt,
useLasso: Boolean,
originalImagePreviewAlpha: Float,
onAddPath: (UiPathPaint) -> Unit,
drawPathMode: DrawPathMode = DrawPathMode.Lasso,
strokeWidth: Pt,
isRecoveryOn: Boolean = false,
modifier: Modifier,
Expand Down Expand Up @@ -159,7 +160,8 @@ fun BitmapEraser(
}

var motionEvent by remember { mutableStateOf(MotionEvent.Idle) }
var previousPosition by remember { mutableStateOf(Offset.Unspecified) }
var previousDrawPosition by remember { mutableStateOf(Offset.Unspecified) }
var drawDownPosition by remember { mutableStateOf(Offset.Unspecified) }

val imageWidth = constraints.maxWidth
val imageHeight = constraints.maxHeight
Expand Down Expand Up @@ -218,15 +220,15 @@ fun BitmapEraser(
}

val drawPaint by remember(
drawPathMode,
strokeWidth,
isRecoveryOn,
brushSoftness,
canvasSize,
useLasso
canvasSize
) {
derivedStateOf {
Paint().apply {
style = if (useLasso) {
style = if (drawPathMode.isFilled) {
PaintingStyle.Fill
} else PaintingStyle.Stroke

Expand All @@ -252,60 +254,83 @@ fun BitmapEraser(
) { mutableStateOf(Path()) }

canvas.apply {
val drawHelper by rememberPathHelper(
drawDownPosition = drawDownPosition,
currentDrawPosition = currentDrawPosition,
onPathChange = { drawPath = it },
strokeWidth = strokeWidth,
canvasSize = canvasSize,
drawPathMode = drawPathMode,
isEraserOn = false
)

when (motionEvent) {

MotionEvent.Down -> {
if (currentDrawPosition.isSpecified) {
drawPath.moveTo(currentDrawPosition.x, currentDrawPosition.y)
previousPosition = currentDrawPosition
previousDrawPosition = currentDrawPosition
} else {
drawPath = Path()
}
motionEvent = MotionEvent.Idle
}

MotionEvent.Move -> {
if (previousPosition.isUnspecified && currentDrawPosition.isSpecified) {
drawPath.moveTo(currentDrawPosition.x, currentDrawPosition.y)
previousPosition = currentDrawPosition
}
if (previousPosition.isSpecified && currentDrawPosition.isSpecified) {
drawPath.quadraticTo(
previousPosition.x,
previousPosition.y,
(previousPosition.x + currentDrawPosition.x) / 2,
(previousPosition.y + currentDrawPosition.y) / 2
)
}
previousPosition = currentDrawPosition
drawHelper.drawPath(
onDrawFreeArrow = {},
onBaseDraw = {
if (previousDrawPosition.isUnspecified && currentDrawPosition.isSpecified) {
drawPath.moveTo(currentDrawPosition.x, currentDrawPosition.y)
previousDrawPosition = currentDrawPosition
}

if (currentDrawPosition.isSpecified && previousDrawPosition.isSpecified) {
drawPath.quadraticTo(
previousDrawPosition.x,
previousDrawPosition.y,
(previousDrawPosition.x + currentDrawPosition.x) / 2,
(previousDrawPosition.y + currentDrawPosition.y) / 2
)
}
previousDrawPosition = currentDrawPosition
}
)

motionEvent = MotionEvent.Idle
}

MotionEvent.Up -> {
PathMeasure().apply {
setPath(drawPath, false)
}.let {
it.getPosition(it.length)
}.takeOrElse { currentDrawPosition }.let { lastPoint ->
if (currentDrawPosition.isSpecified) {
drawPath.moveTo(lastPoint.x, lastPoint.y)
drawPath.lineTo(currentDrawPosition.x, currentDrawPosition.y)
onAddPath(
UiPathPaint(
path = drawPath,
strokeWidth = strokeWidth,
brushSoftness = brushSoftness,
isErasing = isRecoveryOn,
canvasSize = canvasSize,
drawPathMode = if (useLasso) {
DrawPathMode.Lasso
} else DrawPathMode.Free
drawHelper.drawPath(
onDrawFreeArrow = {},
onBaseDraw = {
PathMeasure().apply {
setPath(drawPath, false)
}.let {
it.getPosition(it.length)
}.takeOrElse { currentDrawPosition }.let { lastPoint ->
drawPath.moveTo(lastPoint.x, lastPoint.y)
drawPath.lineTo(
currentDrawPosition.x,
currentDrawPosition.y
)
)
}
}
}
)

onAddPath(
UiPathPaint(
path = drawPath,
strokeWidth = strokeWidth,
brushSoftness = brushSoftness,
isErasing = isRecoveryOn,
canvasSize = canvasSize,
drawPathMode = drawPathMode
)
)

currentDrawPosition = Offset.Unspecified
previousPosition = Offset.Unspecified
previousDrawPosition = Offset.Unspecified
motionEvent = MotionEvent.Idle

scope.launch {
Expand Down Expand Up @@ -345,7 +370,7 @@ fun BitmapEraser(
) {
derivedStateOf {
Paint().apply {
style = if (mode is DrawPathMode.Lasso) {
style = if (mode.isFilled) {
PaintingStyle.Fill
} else PaintingStyle.Stroke
blendMode = if (isRecoveryOn) blendMode else BlendMode.Clear
Expand Down Expand Up @@ -386,6 +411,7 @@ fun BitmapEraser(
if (drawStartedWithOnePointer) {
motionEvent = MotionEvent.Down
currentDrawPosition = pointerInputChange.position
drawDownPosition = pointerInputChange.position
pointerInputChange.consume()
invalidations++
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import ru.tech.imageresizershrinker.core.domain.saving.model.ImageSaveTarget
import ru.tech.imageresizershrinker.core.domain.saving.model.SaveResult
import ru.tech.imageresizershrinker.core.ui.utils.BaseViewModel
import ru.tech.imageresizershrinker.core.ui.utils.state.update
import ru.tech.imageresizershrinker.feature.draw.domain.DrawPathMode
import ru.tech.imageresizershrinker.feature.draw.domain.ImageDrawApplier
import ru.tech.imageresizershrinker.feature.draw.presentation.components.UiPathPaint
import ru.tech.imageresizershrinker.feature.erase_background.domain.AutoBackgroundRemover
Expand Down Expand Up @@ -79,6 +80,9 @@ class EraseBackgroundViewModel @Inject constructor(
private val _undonePaths = mutableStateOf(listOf<UiPathPaint>())
val undonePaths: List<UiPathPaint> by _undonePaths

private val _drawPathMode: MutableState<DrawPathMode> = mutableStateOf(DrawPathMode.Free)
val drawPathMode: DrawPathMode by _drawPathMode

private val _isSaving: MutableState<Boolean> = mutableStateOf(false)
val isSaving: Boolean by _isSaving

Expand Down Expand Up @@ -331,4 +335,8 @@ class EraseBackgroundViewModel @Inject constructor(
}
}

fun updateDrawPathMode(drawPathMode: DrawPathMode) {
_drawPathMode.update { drawPathMode }
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,8 @@ fun SingleEditContent(
lastPaths = viewModel.eraseLastPaths,
undonePaths = viewModel.eraseUndonePaths,
addPath = viewModel::addPathToEraseList,
drawPathMode = viewModel.drawPathMode,
onUpdateDrawPathMode = viewModel::updateDrawPathMode,
autoBackgroundRemover = viewModel.getBackgroundRemover()
)
}
Loading

0 comments on commit ee56dd3

Please sign in to comment.