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