Skip to content

Commit

Permalink
Fix RoundedCornersTransformation not scaling the input bitmap. (#1437)
Browse files Browse the repository at this point in the history
* Fix RoundedCornersTransformation not scaling the input bitmap.

* Revert.
  • Loading branch information
colinrtwhite committed Sep 8, 2022
1 parent 7f3dc7a commit a17aeaf
Show file tree
Hide file tree
Showing 11 changed files with 59 additions and 4 deletions.
2 changes: 2 additions & 0 deletions coil-base/src/androidTest/java/coil/request/DisposableTest.kt
Expand Up @@ -17,6 +17,7 @@ import coil.util.ViewTestActivity
import coil.util.activity
import coil.util.requestManager
import coil.util.runTestMain
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import org.junit.After
Expand All @@ -28,6 +29,7 @@ import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue

@OptIn(ExperimentalCoroutinesApi::class)
class DisposableTest {

private lateinit var context: Context
Expand Down
Expand Up @@ -2,8 +2,10 @@ package coil.transform

import android.content.Context
import androidx.test.core.app.ApplicationProvider
import coil.base.test.R
import coil.size.Dimension
import coil.size.Size
import coil.util.assertIsSimilarTo
import coil.util.decodeBitmapAsset
import coil.util.size
import kotlinx.coroutines.ExperimentalCoroutinesApi
Expand All @@ -30,6 +32,7 @@ class RoundedCornerTransformationTest {
val actual = transformation.transform(input, Size(100, 100))

assertEquals(Size(100, 100), actual.size)
actual.assertIsSimilarTo(R.drawable.rounded_corners_1)
}

@Test
Expand All @@ -38,6 +41,7 @@ class RoundedCornerTransformationTest {
val actual = transformation.transform(input, Size(Dimension.Undefined, 100))

assertEquals(Size(80, 100), actual.size)
actual.assertIsSimilarTo(R.drawable.rounded_corners_2)
}

@Test
Expand All @@ -46,6 +50,7 @@ class RoundedCornerTransformationTest {
val actual = transformation.transform(input, Size(100, Dimension.Undefined))

assertEquals(Size(100, 125), actual.size)
actual.assertIsSimilarTo(R.drawable.rounded_corners_3)
}

@Test
Expand All @@ -54,5 +59,27 @@ class RoundedCornerTransformationTest {
val actual = transformation.transform(input, Size.ORIGINAL)

assertEquals(Size(103, 129), actual.size)
actual.assertIsSimilarTo(R.drawable.rounded_corners_4)
}

/** Regression test: https://github.com/coil-kt/coil/issues/1426 */
@Test
fun imageIsSmallerThanTarget() = runTest {
val expectedSize = Size(200, 200)
val input = context.decodeBitmapAsset("normal_small.jpg")
val actual = transformation.transform(input, expectedSize)

assertEquals(expectedSize, actual.size)
actual.assertIsSimilarTo(R.drawable.rounded_corners_5)
}

@Test
fun imageIsLargerThanTarget() = runTest {
val expectedSize = Size(200, 200)
val input = context.decodeBitmapAsset("normal.jpg")
val actual = transformation.transform(input, expectedSize)

assertEquals(expectedSize, actual.size)
actual.assertIsSimilarTo(R.drawable.rounded_corners_6)
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Expand Up @@ -60,7 +60,18 @@ class RoundedCornersTransformation(
drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)

val matrix = Matrix()
matrix.setTranslate((outputWidth - input.width) / 2f, (outputHeight - input.height) / 2f)
val multiplier = DecodeUtils.computeSizeMultiplier(
srcWidth = input.width,
srcHeight = input.height,
dstWidth = outputWidth,
dstHeight = outputHeight,
scale = Scale.FILL
).toFloat()
val dx = (outputWidth - multiplier * input.width) / 2
val dy = (outputHeight - multiplier * input.height) / 2
matrix.setTranslate(dx, dy)
matrix.preScale(multiplier, multiplier)

val shader = BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
shader.setLocalMatrix(matrix)
paint.shader = shader
Expand All @@ -69,7 +80,7 @@ class RoundedCornersTransformation(
topLeft, topLeft,
topRight, topRight,
bottomRight, bottomRight,
bottomLeft, bottomLeft
bottomLeft, bottomLeft,
)
val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
val path = Path().apply { addRoundRect(rect, radii, Path.Direction.CW) }
Expand Down
15 changes: 15 additions & 0 deletions coil-test/src/main/java/coil/util/Bitmaps.kt
@@ -1,11 +1,14 @@
package coil.util

import android.graphics.Bitmap
import androidx.annotation.DrawableRes
import androidx.annotation.FloatRange
import androidx.core.graphics.alpha
import androidx.core.graphics.blue
import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.green
import androidx.core.graphics.red
import androidx.test.platform.app.InstrumentationRegistry
import coil.size.Size
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
Expand Down Expand Up @@ -102,3 +105,15 @@ fun Bitmap.assertIsSimilarTo(
"The images are not visually similar. Expected: $threshold; Actual: $similarity."
}
}

/**
* Asserts that [this] and [expected] are the same size and that
* the cross correlation of their ARGB channels is >= [threshold].
*/
fun Bitmap.assertIsSimilarTo(
@DrawableRes expected: Int,
@FloatRange(from = -1.0, to = 1.0) threshold: Double = 0.99
) {
val context = InstrumentationRegistry.getInstrumentation().targetContext
assertIsSimilarTo(context.getDrawable(expected)!!.toBitmap(), threshold)
}
4 changes: 2 additions & 2 deletions coil-test/src/main/java/coil/util/JvmTestFunctions.kt
Expand Up @@ -68,15 +68,15 @@ fun Context.copyAssetToFile(fileName: String): File {
return file
}

@OptIn(ExperimentalCoroutinesApi::class)
@ExperimentalCoroutinesApi
fun runTestMain(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> Unit
) = runTest(context) {
withContext(Dispatchers.Main.immediate, block)
}

@OptIn(ExperimentalCoroutinesApi::class)
@ExperimentalCoroutinesApi
fun runTestAsync(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> Unit
Expand Down

0 comments on commit a17aeaf

Please sign in to comment.