Skip to content

Commit

Permalink
Resizing blur + blur in draw mode
Browse files Browse the repository at this point in the history
  • Loading branch information
shubertm authored and kirillt committed Aug 6, 2023
1 parent 0008f49 commit f7eee28
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ fun EditDrawCanvas(
computeDeltaX(currentPoint.x, eventX),
computeDeltaY(currentPoint.y, eventY)
)
editManager.blurOperation.moveBrush(position, delta)
editManager.blurOperation.move(position, delta)
currentPoint.x = eventX
currentPoint.y = eventY
}
Expand Down Expand Up @@ -283,7 +283,7 @@ fun EditDrawCanvas(
canvas.nativeCanvas.setMatrix(matrix)
if (isResizeMode.value) return@drawIntoCanvas
if (isBlurMode.value) {
editManager.blurOperation.drawBrush(context, canvas)
editManager.blurOperation.draw(context, canvas)
return@drawIntoCanvas
}
if (isCropMode.value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class EditManager {
val backgroundImage = mutableStateOf<ImageBitmap?>(null)
private val _backgroundColor = mutableStateOf(Color.Transparent)
val backgroundColor: State<Color> = _backgroundColor
private val backgroundImage2 = mutableStateOf<ImageBitmap?>(null)
val backgroundImage2 = mutableStateOf<ImageBitmap?>(null)
private val originalBackgroundImage = mutableStateOf<ImageBitmap?>(null)

val matrix = Matrix()
Expand Down Expand Up @@ -480,6 +480,10 @@ class EditManager {
backgroundImage2.value = backgroundImage.value
}

fun redrawBackgroundImage2() {
backgroundImage.value = backgroundImage2.value
}

fun setOriginalBackgroundImage(imgBitmap: ImageBitmap?) {
originalBackgroundImage.value = imgBitmap
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,12 @@ fun EditScreen(
val editManager = viewModel.editManager
if (
editManager.isCropMode.value || editManager.isRotateMode.value ||
editManager.isResizeMode.value || editManager.isEyeDropperMode.value
editManager.isResizeMode.value || editManager.isEyeDropperMode.value ||
editManager.isBlurMode.value
) {
viewModel.cancelOperation()
return@BackHandler
}
if (editManager.isBlurMode.value) {
editManager.toggleBlurMode()
return@BackHandler
}
if (editManager.canUndo.value) {
editManager.undo()
return@BackHandler
Expand Down Expand Up @@ -423,15 +420,12 @@ private fun BoxScope.TopMenu(
viewModel.editManager.apply {
if (
isCropMode.value || isRotateMode.value ||
isResizeMode.value || isEyeDropperMode.value
isResizeMode.value || isEyeDropperMode.value ||
isBlurMode.value
) {
viewModel.cancelOperation()
return@clickable
}
if (isBlurMode.value) {
toggleBlurMode()
return@clickable
}
if (
!viewModel.editManager.canUndo.value
) {
Expand Down Expand Up @@ -865,36 +859,39 @@ private fun EditMenuContent(
Color.Black,
contentDescription = null
)
if (editManager.backgroundImage.value != null) {
Icon(
modifier = Modifier
.padding(12.dp)
.size(40.dp)
.clip(CircleShape)
.clickable {
editManager.apply {
if (
!isRotateMode.value &&
!isCropMode.value &&
!isEyeDropperMode.value &&
!isResizeMode.value &&
!isEraseMode.value &&
!viewModel.strokeSliderExpanded
) toggleBlurMode()
if (isBlurMode.value) {
blurOperation.init()
}
Icon(
modifier = Modifier
.padding(12.dp)
.size(40.dp)
.clip(CircleShape)
.clickable {
editManager.apply {
if (
!isRotateMode.value &&
!isCropMode.value &&
!isEyeDropperMode.value &&
!isResizeMode.value &&
!isEraseMode.value &&
!viewModel.strokeSliderExpanded
) toggleBlurMode()
if (isBlurMode.value) {
setBackgroundImage2()
backgroundImage.value =
viewModel.getEditedImage()
blurOperation.init()
return@clickable
}
},
imageVector = ImageVector
.vectorResource(R.drawable.ic_blur_on),
tint = if (editManager.isBlurMode.value)
MaterialTheme.colors.primary
else
Color.Black,
contentDescription = null
)
}
blurOperation.cancel()
}
},
imageVector = ImageVector
.vectorResource(R.drawable.ic_blur_on),
tint = if (editManager.isBlurMode.value)
MaterialTheme.colors.primary
else
Color.Black,
contentDescription = null
)
}
}
viewModel.bottomButtonsScrollIsAtStart.value = scrollState.value == 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,11 @@ class EditViewModel(
cancelEyeDropper()
menusVisible = true
}
if (isBlurMode.value) {
toggleBlurMode()
blurOperation.cancel()
menusVisible = true
}
scaleToFit()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Slider
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import space.taran.arkretouch.R
import space.taran.arkretouch.presentation.drawing.EditManager

@Composable
Expand All @@ -19,19 +22,35 @@ fun BlurIntensityPopup(
Column(
Modifier
.fillMaxWidth()
.height(50.dp)
.height(150.dp)
.padding(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Slider(
modifier = Modifier
.fillMaxWidth(),
value = editManager.blurIntensity.value,
onValueChange = {
editManager.blurIntensity.value = it
},
valueRange = 0f..25f,
)
Column {
Text(stringResource(R.string.blur_intensity))
Slider(
modifier = Modifier
.fillMaxWidth(),
value = editManager.blurIntensity.value,
onValueChange = {
editManager.blurIntensity.value = it
},
valueRange = 0f..25f,
)
}
Column {
Text(stringResource(R.string.blur_size))
Slider(
modifier = Modifier
.fillMaxWidth(),
value = editManager.blurOperation.blurSize.value,
onValueChange = {
editManager.blurOperation.blurSize.value = it
editManager.blurOperation.resize()
},
valueRange = 100f..500f,
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package space.taran.arkretouch.presentation.edit.blur

import android.content.Context
import android.graphics.Bitmap
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Canvas
import androidx.compose.ui.graphics.ImageBitmap
Expand All @@ -24,46 +25,64 @@ class BlurOperation(private val editManager: EditManager) : Operation {
private var offset = Offset.Zero
private var bitmapPosition = IntOffset.Zero

val blurSize = mutableStateOf(BRUSH_SIZE.toFloat())

fun init() {
editManager.apply {
backgroundImage.value?.let {
bitmapPosition = IntOffset(
(it.width / 2) - (BRUSH_SIZE / 2),
(it.height / 2) - (BRUSH_SIZE / 2)
(it.width / 2) - (blurSize.value.toInt() / 2),
(it.height / 2) - (blurSize.value.toInt() / 2)
)
brushBitmap = Bitmap.createBitmap(
it.asAndroidBitmap(),
bitmapPosition.x,
bitmapPosition.y,
BRUSH_SIZE,
BRUSH_SIZE
blurSize.value.toInt(),
blurSize.value.toInt()
)
}
}
}

fun drawBrush(context: Context, canvas: Canvas) {
fun resize() {
editManager.backgroundImage.value?.let {
this.context = context
if (isWithinBounds(it)) {
offset = Offset(
bitmapPosition.x.toFloat(),
bitmapPosition.y.toFloat()
brushBitmap = Bitmap.createBitmap(
it.asAndroidBitmap(),
bitmapPosition.x,
bitmapPosition.y,
blurSize.value.toInt(),
blurSize.value.toInt()
)
}
blur(context)
canvas.drawImage(
blurredBitmap.asImageBitmap(),
offset,
Paint()
)
}
}

fun moveBrush(brushPosition: Offset, delta: Offset) {
fun draw(context: Context, canvas: Canvas) {
if (blurSize.value in MIN_SIZE..MAX_SIZE) {
editManager.backgroundImage.value?.let {
this.context = context
if (isWithinBounds(it)) {
offset = Offset(
bitmapPosition.x.toFloat(),
bitmapPosition.y.toFloat()
)
}
blur(context)
canvas.drawImage(
blurredBitmap.asImageBitmap(),
offset,
Paint()
)
}
}
}

fun move(blurPosition: Offset, delta: Offset) {
val position = Offset(
brushPosition.x * editManager.bitmapScale.x,
brushPosition.y * editManager.bitmapScale.y
blurPosition.x * editManager.bitmapScale.x,
blurPosition.y * editManager.bitmapScale.y
)
if (isBrushTouched(position)) {
editManager.apply {
Expand All @@ -77,8 +96,8 @@ class BlurOperation(private val editManager: EditManager) : Operation {
it.asAndroidBitmap(),
bitmapPosition.x,
bitmapPosition.y,
BRUSH_SIZE,
BRUSH_SIZE
blurSize.value.toInt(),
blurSize.value.toInt()
)
}
}
Expand All @@ -92,13 +111,17 @@ class BlurOperation(private val editManager: EditManager) : Operation {
editManager.updateRevised()
}

fun cancel() {
editManager.redrawBackgroundImage2()
}

private fun isWithinBounds(image: ImageBitmap) = bitmapPosition.x >= 0 &&
(bitmapPosition.x + BRUSH_SIZE) <= image.width && bitmapPosition.y >= 0 &&
(bitmapPosition.y + BRUSH_SIZE) <= image.height
(bitmapPosition.x + blurSize.value) <= image.width &&
bitmapPosition.y >= 0 && (bitmapPosition.y + blurSize.value) <= image.height

private fun isBrushTouched(position: Offset): Boolean {
return position.x >= offset.x && position.x <= (offset.x + BRUSH_SIZE) &&
position.y >= offset.y && position.y <= (offset.y + BRUSH_SIZE)
return position.x >= offset.x && position.x <= (offset.x + blurSize.value) &&
position.y >= offset.y && position.y <= (offset.y + blurSize.value)
}

override fun apply() {
Expand All @@ -119,9 +142,10 @@ class BlurOperation(private val editManager: EditManager) : Operation {
offset,
Paint()
)
blurs.add(it)
blurs.add(editManager.backgroundImage2.value)
editManager.addBlur()
}
editManager.keepEditedPaths()
editManager.toggleBlurMode()
editManager.backgroundImage.value = image
}
Expand All @@ -130,12 +154,14 @@ class BlurOperation(private val editManager: EditManager) : Operation {
val bitmap = blurs.pop()
redoBlurs.push(editManager.backgroundImage.value)
editManager.backgroundImage.value = bitmap
editManager.redrawEditedPaths()
}

override fun redo() {
val bitmap = redoBlurs.pop()
blurs.push(editManager.backgroundImage.value)
editManager.backgroundImage.value = bitmap
editManager.keepEditedPaths()
}

private fun blur(context: Context) {
Expand All @@ -150,5 +176,7 @@ class BlurOperation(private val editManager: EditManager) : Operation {

companion object {
private const val BRUSH_SIZE = 250
const val MAX_SIZE = 500f
const val MIN_SIZE = 100f
}
}
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@
<string name="width_not_accepted">Width cannot be %s</string>
<string name="width_empty">Please enter width</string>
<string name="height_empty">Please enter height</string>
<string name="blur_intensity">Intensity</string>
<string name="blur_size">Size</string>
</resources>

0 comments on commit f7eee28

Please sign in to comment.