1 /*
2  * Copyright 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.compose.integration.hero.common.implementation
18 
19 import android.graphics.Bitmap
20 import android.graphics.Canvas
21 import android.graphics.Paint
22 import android.graphics.RadialGradient
23 import android.graphics.Shader
24 import kotlin.math.sqrt
25 
26 /**
27  * Generate a [Bitmap] with a radial gradient. This is useful for creating images that are unique
28  * and can help avoiding system caches.
29  *
30  * @param width The width of the bitmap.
31  * @param height The height of the bitmap.
32  * @param seed The seed used to generate the gradient colors.
33  */
GradientBitmapnull34 fun GradientBitmap(
35     width: Int,
36     height: Int,
37     seed: Int,
38 ): Bitmap =
39     GradientBitmap(
40         width = width,
41         height = height,
42         colors = gradientColorsFor(seed * 100 /* introduce greater variance */)
43     )
44 
45 /**
46  * Generate a [Bitmap] with a radial gradient. This is useful for creating images that are unique
47  * and can help avoiding system caches.
48  *
49  * @param width The width of the bitmap.
50  * @param height The height of the bitmap.
51  * @param colors The gradient colors.
52  */
53 fun GradientBitmap(
54     width: Int,
55     height: Int,
56     colors: IntArray,
57 ): Bitmap {
58     val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
59     val canvas = Canvas(bitmap)
60     val cx = width / 2f
61     val cy = height / 2f
62     val r = sqrt(cx * cx + cy * cy)
63     val grad = RadialGradient(cx, cy, r, colors, null, Shader.TileMode.CLAMP)
64     val paint = Paint()
65     paint.isDither = true
66     paint.shader = grad
67     canvas.drawCircle(cx, cy, r, paint)
68     return bitmap
69 }
70 
71 /** Generate a set of gradient colors for the given key */
gradientColorsFornull72 fun gradientColorsFor(key: Int): IntArray {
73     var hash = key
74     val cs = if (hash and 0b1 != 0) firstGradientPalette else secondGradientPalette
75     hash = hash shr 1
76     val c1 = cs[hash.mod(5)]
77     hash = hash shr 8
78     val c2 = cs[hash.mod(5)]
79     return intArrayOf(c1, c2)
80 }
81 
82 private val firstGradientPalette =
83     intArrayOf(
84         0xFFE2EFDE.toInt(),
85         0xFFAFD0BF.toInt(),
86         0xFF808F87.toInt(),
87         0xFF9B7E46.toInt(),
88         0xFFF4B266.toInt(),
89         0xFFA50E0E.toInt(),
90         0xFF1E8E3E.toInt(),
91         0xFFE8710A.toInt(),
92         0xFFE52592.toInt()
93     )
94 
95 private val secondGradientPalette =
96     intArrayOf(
97         0xFFDCE0D9.toInt(),
98         0xFF31081F.toInt(),
99         0xFF6B0F1A.toInt(),
100         0xFF595959.toInt(),
101         0xFF808F85.toInt(),
102         0xFF9334E6.toInt(),
103         0xFF12B5CB.toInt(),
104         0xFFFCC934.toInt(),
105         0xFF4285F4.toInt()
106     )
107