-
Notifications
You must be signed in to change notification settings - Fork 307
/
CircleCropTransformation.kt
110 lines (100 loc) · 3.97 KB
/
CircleCropTransformation.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
108
109
110
/*
* Copyright (C) 2022 panpf <panpfpanpf@outlook.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
package com.github.panpf.sketch.transform
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.PorterDuff.Mode.SRC_IN
import android.graphics.PorterDuffXfermode
import androidx.annotation.WorkerThread
import com.github.panpf.sketch.Sketch
import com.github.panpf.sketch.decode.internal.getOrCreate
import com.github.panpf.sketch.request.internal.RequestContext
import com.github.panpf.sketch.resize.Precision.SAME_ASPECT_RATIO
import com.github.panpf.sketch.resize.Scale
import com.github.panpf.sketch.resize.internal.calculateResizeMapping
import com.github.panpf.sketch.util.safeConfig
import java.lang.Integer.min
/**
* A [Transformation] that crops an image using a centered circle as the mask.
*
* If you're using Jetpack Compose, use `Modifier.clip(CircleShape)` instead of this transformation
* as it's more efficient.
*
* @param scale Specify which part of the original image to keep. If null, use ImageRequest.resizeScaleDecider
*/
class CircleCropTransformation constructor(val scale: Scale? = null) : Transformation {
override val key: String = "CircleCropTransformation($scale)"
@WorkerThread
override suspend fun transform(
sketch: Sketch,
requestContext: RequestContext,
input: Bitmap
): TransformResult {
val newSize = min(input.width, input.height)
val scale = scale
?: requestContext.request.resizeScaleDecider.get(
imageWidth = input.width,
imageHeight = input.height,
resizeWidth = newSize,
resizeHeight = newSize
)
val resizeMapping = calculateResizeMapping(
input.width, input.height, newSize, newSize, SAME_ASPECT_RATIO, scale
)!!
val config = input.safeConfig
val outBitmap = sketch.bitmapPool.getOrCreate(
width = resizeMapping.newWidth,
height = resizeMapping.newHeight,
config = config,
disallowReuseBitmap = requestContext.request.disallowReuseBitmap,
caller = "CircleCropTransformation"
)
val paint = Paint().apply {
isAntiAlias = true
color = -0x10000
}
val canvas = Canvas(outBitmap).apply {
drawARGB(0, 0, 0, 0)
}
canvas.drawCircle(
resizeMapping.newWidth / 2f,
resizeMapping.newHeight / 2f,
min(resizeMapping.newWidth, resizeMapping.newHeight) / 2f,
paint
)
paint.xfermode = PorterDuffXfermode(SRC_IN)
canvas.drawBitmap(input, resizeMapping.srcRect, resizeMapping.destRect, paint)
return TransformResult(outBitmap, createCircleCropTransformed(scale))
}
override fun toString(): String = key
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as CircleCropTransformation
if (scale != other.scale) return false
return true
}
override fun hashCode(): Int {
return scale.hashCode()
}
}
fun createCircleCropTransformed(scale: Scale) =
"CircleCropTransformed(${scale})"
fun isCircleCropTransformed(transformed: String): Boolean =
transformed.startsWith("CircleCropTransformed(")
fun List<String>.getCircleCropTransformed(): String? =
find { isCircleCropTransformed(it) }