From d6ff80c062e43395923d6da8c59b395c17c8478b Mon Sep 17 00:00:00 2001 From: Lee Taehoon <48707020+TaehoonLeee@users.noreply.github.com> Date: Mon, 26 Dec 2022 17:34:19 +0900 Subject: [PATCH] Imageviewer Bitmap Filter for uikit (#2575) --- .../example/imageviewer/ImageViewer.ios.kt | 17 ++--- .../model/filtration/BlurFilter.kt | 13 ++++ .../model/filtration/GrayScaleFilter.kt | 13 ++++ .../model/filtration/PixelFilter.kt | 13 ++++ .../imageviewer/utils/GraphicsMath.ios.kt | 75 +++++++++++++++++++ 5 files changed, 121 insertions(+), 10 deletions(-) create mode 100644 experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/BlurFilter.kt create mode 100644 experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/GrayScaleFilter.kt create mode 100644 experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/PixelFilter.kt create mode 100644 experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/utils/GraphicsMath.ios.kt diff --git a/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/ImageViewer.ios.kt b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/ImageViewer.ios.kt index 34dcbc76a1..2f0eb17ab2 100755 --- a/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/ImageViewer.ios.kt +++ b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/ImageViewer.ios.kt @@ -11,6 +11,9 @@ import example.imageviewer.model.ContentRepository import example.imageviewer.model.State import example.imageviewer.model.adapter import example.imageviewer.model.createNetworkRepository +import example.imageviewer.model.filtration.BlurFilter +import example.imageviewer.model.filtration.GrayScaleFilter +import example.imageviewer.model.filtration.PixelFilter import example.imageviewer.style.ImageViewerTheme import example.imageviewer.view.Toast import example.imageviewer.view.ToastState @@ -39,18 +42,12 @@ internal fun ImageViewerIos() { } } -class StubFilter : BitmapFilter { - override fun apply(bitmap: ImageBitmap): ImageBitmap { - return bitmap - } -} - -private fun getDependencies(ioScope: CoroutineScope, toastState: MutableState) = object : Dependencies { +fun getDependencies(ioScope: CoroutineScope, toastState: MutableState) = object : Dependencies { override val ioScope: CoroutineScope = ioScope override fun getFilter(type: FilterType): BitmapFilter = when (type) { - FilterType.GrayScale -> StubFilter() - FilterType.Pixel -> StubFilter() - FilterType.Blur -> StubFilter() + FilterType.GrayScale -> GrayScaleFilter() + FilterType.Pixel -> PixelFilter() + FilterType.Blur -> BlurFilter() } override val localization: Localization = object : Localization { diff --git a/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/BlurFilter.kt b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/BlurFilter.kt new file mode 100644 index 0000000000..f0efb262ac --- /dev/null +++ b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/BlurFilter.kt @@ -0,0 +1,13 @@ +package example.imageviewer.model.filtration + +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asComposeImageBitmap +import androidx.compose.ui.graphics.asSkiaBitmap +import example.imageviewer.core.BitmapFilter +import example.imageviewer.utils.applyBlurFilter + +class BlurFilter : BitmapFilter { + override fun apply(bitmap: ImageBitmap): ImageBitmap { + return applyBlurFilter(bitmap.asSkiaBitmap()).asComposeImageBitmap() + } +} \ No newline at end of file diff --git a/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/GrayScaleFilter.kt b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/GrayScaleFilter.kt new file mode 100644 index 0000000000..46c1502833 --- /dev/null +++ b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/GrayScaleFilter.kt @@ -0,0 +1,13 @@ +package example.imageviewer.model.filtration + +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asComposeImageBitmap +import androidx.compose.ui.graphics.asSkiaBitmap +import example.imageviewer.core.BitmapFilter +import example.imageviewer.utils.applyGrayScaleFilter + +class GrayScaleFilter : BitmapFilter { + override fun apply(bitmap: ImageBitmap): ImageBitmap { + return applyGrayScaleFilter(bitmap.asSkiaBitmap()).asComposeImageBitmap() + } +} \ No newline at end of file diff --git a/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/PixelFilter.kt b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/PixelFilter.kt new file mode 100644 index 0000000000..8b7dfb4460 --- /dev/null +++ b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/model/filtration/PixelFilter.kt @@ -0,0 +1,13 @@ +package example.imageviewer.model.filtration + +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asComposeImageBitmap +import androidx.compose.ui.graphics.asSkiaBitmap +import example.imageviewer.core.BitmapFilter +import example.imageviewer.utils.applyPixelFilter + +class PixelFilter : BitmapFilter { + override fun apply(bitmap: ImageBitmap): ImageBitmap { + return applyPixelFilter(bitmap.asSkiaBitmap()).asComposeImageBitmap() + } +} \ No newline at end of file diff --git a/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/utils/GraphicsMath.ios.kt b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/utils/GraphicsMath.ios.kt new file mode 100644 index 0000000000..1ac1cb25ec --- /dev/null +++ b/experimental/examples/imageviewer/shared/src/iosMain/kotlin/example/imageviewer/utils/GraphicsMath.ios.kt @@ -0,0 +1,75 @@ +package example.imageviewer.utils + +import org.jetbrains.skia.* + +fun scaleBitmapAspectRatio( + bitmap: Bitmap, + width: Int, + height: Int +): Bitmap { + val boundWidth = width.toFloat() + val boundHeight = height.toFloat() + + val ratioX = boundWidth / bitmap.width + val ratioY = boundHeight / bitmap.height + val ratio = if (ratioX < ratioY) ratioX else ratioY + + val resultWidth = (bitmap.width * ratio).toInt() + val resultHeight = (bitmap.height * ratio).toInt() + + val result = Bitmap().apply { + allocN32Pixels(resultWidth, resultHeight) + } + val canvas = Canvas(result) + canvas.drawImageRect(Image.makeFromBitmap(bitmap), result.bounds.toRect()) + canvas.readPixels(result, 0, 0) + canvas.close() + + return result +} + +fun applyGrayScaleFilter(bitmap: Bitmap): Bitmap { + val imageInfo = ImageInfo( + width = bitmap.width, + height = bitmap.height, + colorInfo = ColorInfo(ColorType.GRAY_8, ColorAlphaType.PREMUL, null) + ) + val result = Bitmap().apply { + allocPixels(imageInfo) + } + + val canvas = Canvas(result) + canvas.drawImageRect(Image.makeFromBitmap(bitmap), bitmap.bounds.toRect()) + canvas.readPixels(result, 0, 0) + canvas.close() + + return result +} + +fun applyPixelFilter(bitmap: Bitmap): Bitmap { + val width = bitmap.width + val height = bitmap.height + + var result = scaleBitmapAspectRatio(bitmap, width / 20, height / 20) + result = scaleBitmapAspectRatio(result, width, height) + + return result +} + +fun applyBlurFilter(bitmap: Bitmap): Bitmap { + val result = Bitmap().apply { + allocN32Pixels(bitmap.width, bitmap.height) + } + val blur = Paint().apply { + imageFilter = ImageFilter.makeBlur(10f, 10f, FilterTileMode.CLAMP) + } + + val canvas = Canvas(result) + canvas.saveLayer(null, blur) + canvas.drawImageRect(Image.makeFromBitmap(bitmap), bitmap.bounds.toRect()) + canvas.restore() + canvas.readPixels(result, 0, 0) + canvas.close() + + return result +} \ No newline at end of file