fix(image): Coil 2 대응 BlurTransformation 구현을 추가한다
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
package kr.co.vividnext.sodalive.common.image
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Bitmap.Config.ARGB_8888
|
||||
import android.graphics.Paint
|
||||
import android.renderscript.Allocation
|
||||
import android.renderscript.Element
|
||||
import android.renderscript.RenderScript
|
||||
import android.renderscript.ScriptIntrinsicBlur
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.graphics.applyCanvas
|
||||
import coil.size.Size
|
||||
import coil.transform.Transformation
|
||||
|
||||
/**
|
||||
* Coil 2.x 환경에서 기존 blur 호출부를 유지하기 위한 Android blur transformation이다.
|
||||
*/
|
||||
@RequiresApi(18)
|
||||
class BlurTransformation @JvmOverloads constructor(
|
||||
private val context: Context,
|
||||
private val radius: Float = DEFAULT_RADIUS,
|
||||
private val sampling: Float = DEFAULT_SAMPLING
|
||||
) : Transformation {
|
||||
|
||||
init {
|
||||
require(radius in 0.0f..25.0f) { "radius must be in [0, 25]." }
|
||||
require(sampling > 0f) { "sampling must be > 0." }
|
||||
}
|
||||
|
||||
override val cacheKey: String = "${BlurTransformation::class.java.name}-$radius-$sampling"
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
override suspend fun transform(input: Bitmap, size: Size): Bitmap {
|
||||
val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
|
||||
val scaledWidth = (input.width / sampling).toInt().coerceAtLeast(1)
|
||||
val scaledHeight = (input.height / sampling).toInt().coerceAtLeast(1)
|
||||
val output = Bitmap.createBitmap(scaledWidth, scaledHeight, input.config ?: ARGB_8888)
|
||||
|
||||
output.applyCanvas {
|
||||
scale(1f / sampling, 1f / sampling)
|
||||
drawBitmap(input, 0f, 0f, paint)
|
||||
}
|
||||
|
||||
var renderScript: RenderScript? = null
|
||||
var inputAllocation: Allocation? = null
|
||||
var outputAllocation: Allocation? = null
|
||||
var blurScript: ScriptIntrinsicBlur? = null
|
||||
|
||||
try {
|
||||
renderScript = RenderScript.create(context)
|
||||
inputAllocation = Allocation.createFromBitmap(
|
||||
renderScript,
|
||||
output,
|
||||
Allocation.MipmapControl.MIPMAP_NONE,
|
||||
Allocation.USAGE_SCRIPT
|
||||
)
|
||||
outputAllocation = Allocation.createTyped(renderScript, inputAllocation.type)
|
||||
blurScript = ScriptIntrinsicBlur.create(renderScript, Element.U8_4(renderScript))
|
||||
|
||||
blurScript.setRadius(radius)
|
||||
blurScript.setInput(inputAllocation)
|
||||
blurScript.forEach(outputAllocation)
|
||||
outputAllocation.copyTo(output)
|
||||
} finally {
|
||||
blurScript?.destroy()
|
||||
inputAllocation?.destroy()
|
||||
outputAllocation?.destroy()
|
||||
renderScript?.destroy()
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private const val DEFAULT_RADIUS = 10f
|
||||
private const val DEFAULT_SAMPLING = 1f
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package kr.co.vividnext.sodalive.common.image
|
||||
|
||||
import android.content.Context
|
||||
import io.mockk.mockk
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Test
|
||||
|
||||
class BlurTransformationTest {
|
||||
|
||||
@Test
|
||||
fun `cacheKey includes radius and sampling`() {
|
||||
val transformation = BlurTransformation(
|
||||
context = mockk<Context>(relaxed = true),
|
||||
radius = 25f,
|
||||
sampling = 2.5f
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
"kr.co.vividnext.sodalive.common.image.BlurTransformation-25.0-2.5",
|
||||
transformation.cacheKey
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `constructor rejects radius above max`() {
|
||||
assertThrows(IllegalArgumentException::class.java) {
|
||||
BlurTransformation(
|
||||
context = mockk<Context>(relaxed = true),
|
||||
radius = 26f,
|
||||
sampling = 2.5f
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user