-
Notifications
You must be signed in to change notification settings - Fork 638
/
RoundedCornersTransformation.kt
107 lines (94 loc) · 3.72 KB
/
RoundedCornersTransformation.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package coil.transform
import android.graphics.Bitmap
import android.graphics.BitmapShader
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PorterDuff
import android.graphics.RectF
import android.graphics.Shader
import androidx.annotation.Px
import androidx.core.graphics.applyCanvas
import androidx.core.graphics.createBitmap
import coil.decode.DecodeUtils
import coil.size.Scale
import coil.size.Size
import coil.util.heightPx
import coil.util.safeConfig
import coil.util.widthPx
import kotlin.math.roundToInt
/**
* A [Transformation] that crops the image to fit the target's dimensions and rounds the corners of
* the image.
*
* If you're using Jetpack Compose, use `Modifier.clip(RoundedCornerShape(radius))` instead of this
* transformation as it's more efficient.
*
* @param topLeft The radius for the top left corner.
* @param topRight The radius for the top right corner.
* @param bottomLeft The radius for the bottom left corner.
* @param bottomRight The radius for the bottom right corner.
*/
class RoundedCornersTransformation(
@Px private val topLeft: Float = 0f,
@Px private val topRight: Float = 0f,
@Px private val bottomLeft: Float = 0f,
@Px private val bottomRight: Float = 0f
) : Transformation {
constructor(@Px radius: Float) : this(radius, radius, radius, radius)
init {
require(topLeft >= 0 && topRight >= 0 && bottomLeft >= 0 && bottomRight >= 0) {
"All radii must be >= 0."
}
}
override val cacheKey = "${javaClass.name}-$topLeft,$topRight,$bottomLeft,$bottomRight"
override suspend fun transform(input: Bitmap, size: Size): Bitmap {
val paint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
val dstWidth = size.widthPx(Scale.FILL) { input.width }
val dstHeight = size.heightPx(Scale.FILL) { input.height }
val multiplier = DecodeUtils.computeSizeMultiplier(
srcWidth = input.width,
srcHeight = input.height,
dstWidth = dstWidth,
dstHeight = dstHeight,
scale = Scale.FILL
)
val outputWidth = (dstWidth / multiplier).roundToInt()
val outputHeight = (dstHeight / multiplier).roundToInt()
val output = createBitmap(outputWidth, outputHeight, input.safeConfig)
output.applyCanvas {
drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
val matrix = Matrix()
matrix.setTranslate((outputWidth - input.width) / 2f, (outputHeight - input.height) / 2f)
val shader = BitmapShader(input, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
shader.setLocalMatrix(matrix)
paint.shader = shader
val radii = floatArrayOf(
topLeft, topLeft,
topRight, topRight,
bottomRight, bottomRight,
bottomLeft, bottomLeft
)
val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
val path = Path().apply { addRoundRect(rect, radii, Path.Direction.CW) }
drawPath(path, paint)
}
return output
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
return other is RoundedCornersTransformation &&
topLeft == other.topLeft &&
topRight == other.topRight &&
bottomLeft == other.bottomLeft &&
bottomRight == other.bottomRight
}
override fun hashCode(): Int {
var result = topLeft.hashCode()
result = 31 * result + topRight.hashCode()
result = 31 * result + bottomLeft.hashCode()
result = 31 * result + bottomRight.hashCode()
return result
}
}