Refactor auto background remover

This commit is contained in:
T8RIN
2025-03-20 03:22:44 +03:00
parent 46610abd7d
commit 4992c0454d
6 changed files with 144 additions and 108 deletions

View File

@ -1,6 +1,6 @@
/* /*
* ImageToolbox is an image editor for android * ImageToolbox is an image editor for android
* Copyright (c) 2024 T8RIN (Malik Mukhametzyanov) * Copyright (c) 2025 T8RIN (Malik Mukhametzyanov)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,21 +18,19 @@
package ru.tech.imageresizershrinker.feature.erase_background.data package ru.tech.imageresizershrinker.feature.erase_background.data
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Build import ru.tech.imageresizershrinker.feature.erase_background.domain.AutoBackgroundRemoverBackend
import androidx.annotation.RequiresApi import javax.inject.Inject
@RequiresApi(api = Build.VERSION_CODES.N) internal class AndroidAutoBackgroundRemoverBackend @Inject constructor() :
internal object MlKitSubjectBackgroundRemover { AutoBackgroundRemoverBackend<Bitmap> {
/** override fun performBackgroundRemove(
* Process the image to get buffer and image height and width image: Bitmap,
* @param bitmap Bitmap which you want to remove background.
* @param onFinish listener for success and failure callback.
**/
@RequiresApi(api = Build.VERSION_CODES.N)
fun removeBackground(
bitmap: Bitmap,
onFinish: (Result<Bitmap>) -> Unit onFinish: (Result<Bitmap>) -> Unit
) = onFinish(Result.failure(UnsupportedOperationException("FOSS"))) ) {
onFinish(
Result.failure(UnsupportedOperationException("FOSS"))
)
}
} }

View File

@ -1,41 +0,0 @@
/*
* ImageToolbox is an image editor for android
* Copyright (c) 2024 T8RIN (Malik Mukhametzyanov)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* You should have received a copy of the Apache License
* along with this program. If not, see <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package ru.tech.imageresizershrinker.feature.erase_background.data
import android.graphics.Bitmap
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
internal object MlKitBackgroundRemover {
/**
* Process the image to get buffer and image height and width
* @param bitmap Bitmap which you want to remove background.
* @param onFinish listener for success and failure callback.
**/
fun removeBackground(
bitmap: Bitmap,
scope: CoroutineScope,
onFinish: suspend (Result<Bitmap>) -> Unit
) {
scope.launch {
onFinish(Result.failure(UnsupportedOperationException("FOSS")))
}
}
}

View File

@ -17,21 +17,19 @@
package ru.tech.imageresizershrinker.feature.erase_background.data package ru.tech.imageresizershrinker.feature.erase_background.data
import android.annotation.SuppressLint
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Build
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import kotlinx.coroutines.CoroutineScope import com.t8rin.logger.makeLog
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import ru.tech.imageresizershrinker.core.domain.dispatchers.DispatchersHolder
import ru.tech.imageresizershrinker.feature.erase_background.domain.AutoBackgroundRemover import ru.tech.imageresizershrinker.feature.erase_background.domain.AutoBackgroundRemover
import ru.tech.imageresizershrinker.feature.erase_background.domain.AutoBackgroundRemoverBackend
import javax.inject.Inject import javax.inject.Inject
internal class AndroidAutoBackgroundRemover @Inject constructor( internal class AndroidAutoBackgroundRemover @Inject constructor(
dispatchersHolder: DispatchersHolder private val backend: AutoBackgroundRemoverBackend<Bitmap>
) : DispatchersHolder by dispatchersHolder, AutoBackgroundRemover<Bitmap> { ) : AutoBackgroundRemover<Bitmap> {
override suspend fun trimEmptyParts( override suspend fun trimEmptyParts(
image: Bitmap image: Bitmap
@ -83,54 +81,16 @@ internal class AndroidAutoBackgroundRemover @Inject constructor(
image: Bitmap, image: Bitmap,
onSuccess: (Bitmap) -> Unit, onSuccess: (Bitmap) -> Unit,
onFailure: (Throwable) -> Unit onFailure: (Throwable) -> Unit
) { ) = backend.performBackgroundRemove(
runCatching { image = image,
autoRemove( onFinish = { result ->
type = ApiType.Best, result
image = image, .onSuccess(onSuccess)
onFinish = { .onFailure {
it.onSuccess(onSuccess).onFailure(onFailure) it.makeLog()
onFailure(it)
} }
)
}.onFailure(onFailure)
}
private fun autoRemove(
type: ApiType,
image: Bitmap,
onFinish: (Result<Bitmap>) -> Unit
) {
val old = {
MlKitBackgroundRemover.removeBackground(
bitmap = image,
scope = CoroutineScope(defaultDispatcher),
onFinish = onFinish
)
} }
val new = { )
@SuppressLint("NewApi")
MlKitSubjectBackgroundRemover.removeBackground(
bitmap = image,
onFinish = {
if (it.isFailure) {
old()
} else onFinish(it)
}
)
}
when (type) {
ApiType.Old -> old()
ApiType.New -> new()
}
}
private enum class ApiType {
Old, New;
companion object {
val Best: ApiType get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) New else Old
}
}
} }

View File

@ -23,7 +23,9 @@ import dagger.Module
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import ru.tech.imageresizershrinker.feature.erase_background.data.AndroidAutoBackgroundRemover import ru.tech.imageresizershrinker.feature.erase_background.data.AndroidAutoBackgroundRemover
import ru.tech.imageresizershrinker.feature.erase_background.data.AndroidAutoBackgroundRemoverBackend
import ru.tech.imageresizershrinker.feature.erase_background.domain.AutoBackgroundRemover import ru.tech.imageresizershrinker.feature.erase_background.domain.AutoBackgroundRemover
import ru.tech.imageresizershrinker.feature.erase_background.domain.AutoBackgroundRemoverBackend
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@ -36,4 +38,10 @@ internal interface EraseBackgroundModule {
remover: AndroidAutoBackgroundRemover remover: AndroidAutoBackgroundRemover
): AutoBackgroundRemover<Bitmap> ): AutoBackgroundRemover<Bitmap>
@Binds
@Singleton
fun provideBackend(
backend: AndroidAutoBackgroundRemoverBackend
): AutoBackgroundRemoverBackend<Bitmap>
} }

View File

@ -0,0 +1,27 @@
/*
* ImageToolbox is an image editor for android
* Copyright (c) 2025 T8RIN (Malik Mukhametzyanov)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* You should have received a copy of the Apache License
* along with this program. If not, see <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package ru.tech.imageresizershrinker.feature.erase_background.domain
internal interface AutoBackgroundRemoverBackend<I> {
fun performBackgroundRemove(
image: I,
onFinish: (Result<I>) -> Unit
)
}

View File

@ -0,0 +1,84 @@
/*
* ImageToolbox is an image editor for android
* Copyright (c) 2025 T8RIN (Malik Mukhametzyanov)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* You should have received a copy of the Apache License
* along with this program. If not, see <http://www.apache.org/licenses/LICENSE-2.0>.
*/
package ru.tech.imageresizershrinker.feature.erase_background.data
import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.os.Build
import kotlinx.coroutines.CoroutineScope
import ru.tech.imageresizershrinker.core.domain.dispatchers.DispatchersHolder
import ru.tech.imageresizershrinker.feature.erase_background.domain.AutoBackgroundRemoverBackend
import javax.inject.Inject
internal class AndroidAutoBackgroundRemoverBackend @Inject constructor(
dispatchersHolder: DispatchersHolder
) : AutoBackgroundRemoverBackend<Bitmap>, DispatchersHolder by dispatchersHolder {
override fun performBackgroundRemove(
image: Bitmap,
onFinish: (Result<Bitmap>) -> Unit
) {
runCatching {
autoRemove(
image = image,
onFinish = onFinish
)
}.onFailure {
onFinish(Result.failure(it))
}
}
@SuppressLint("NewApi")
private fun autoRemove(
type: ApiType = ApiType.Best,
image: Bitmap,
onFinish: (Result<Bitmap>) -> Unit
) {
val old = {
MlKitBackgroundRemover.removeBackground(
bitmap = image,
scope = CoroutineScope(defaultDispatcher),
onFinish = onFinish
)
}
val new = {
MlKitSubjectBackgroundRemover.removeBackground(
bitmap = image,
onFinish = {
if (it.isFailure) {
old()
} else onFinish(it)
}
)
}
when (type) {
ApiType.Old -> old()
ApiType.New -> new()
}
}
private enum class ApiType {
Old, New;
companion object {
val Best: ApiType get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) New else Old
}
}
}