Skip to content

Commit 71cf7fd

Browse files
refactor ScreenColorDetector
1 parent f3dc7fe commit 71cf7fd

File tree

4 files changed

+356
-125
lines changed

4 files changed

+356
-125
lines changed

app/src/main/java/com/smarttoolfactory/composecolorpicker/demo/ColorDetectionFromScreenDemo.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,16 @@ fun ColorDetectionFromScreenDemo() {
4848
)
4949

5050
ScreenColorDetector(
51-
modifier = Modifier.wrapContentSize().padding(10.dp),
51+
modifier = Modifier.border(2.dp, Color.Cyan).padding(25.dp),
5252
content = {
5353
Column(
54-
modifier = Modifier
55-
.border(2.dp, Color.Green)
56-
.padding(5.dp)
54+
modifier = Modifier.border(1.dp, Color.Magenta)
5755
) {
5856

5957
Image(
6058
bitmap = ImageBitmap.imageResource(
6159
LocalContext.current.resources,
62-
R.drawable.landscape
60+
R.drawable.landscape10
6361
),
6462
contentDescription = null,
6563
modifier = Modifier
25.6 KB
Loading
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package com.smarttoolfactory.colorpicker.util
2+
3+
import android.graphics.Bitmap
4+
import androidx.compose.ui.graphics.Color
5+
6+
/**
7+
* Calculates color of pixel in ([offsetX], [offsetY]) in [bitmap] that is in a Composable with
8+
* [width] and [height].
9+
*
10+
* @param offsetX x position of bitmap
11+
* @param offsetY y position of bitmap
12+
* @param startImageX x coordinate of top left position of image.
13+
* @param startImageY y coordinate of top left position of image.
14+
* @param width width of Composable that contains [bitmap].
15+
* @param height height of Composable that contains [bitmap].
16+
* might not match each other.
17+
* @param bitmap image used for detecting colors of.
18+
*/
19+
fun calculateColorInPixel(
20+
offsetX: Float,
21+
offsetY: Float,
22+
startImageX: Float = 0f,
23+
startImageY: Float = 0f,
24+
width: Int,
25+
height: Int,
26+
bitmap: Bitmap,
27+
): Color {
28+
29+
val bitmapWidth = bitmap.width
30+
val bitmapHeight = bitmap.height
31+
32+
// End positions, this might be less than Image dimensions if bitmap doesn't fit Image
33+
val endImageX = width - startImageX
34+
val endImageY = height - startImageY
35+
36+
val scaledX =
37+
scale(
38+
start1 = startImageX,
39+
end1 = endImageX,
40+
pos = offsetX,
41+
start2 = 0f,
42+
end2 = bitmapWidth.toFloat()
43+
).toInt().coerceIn(0, bitmapWidth - 1)
44+
45+
val scaledY =
46+
scale(
47+
start1 = startImageY,
48+
end1 = endImageY,
49+
pos = offsetY,
50+
start2 = 0f,
51+
end2 = bitmapHeight.toFloat()
52+
).toInt().coerceIn(0, bitmapHeight - 1)
53+
54+
val pixel: Int = bitmap.getPixel(scaledX, scaledY)
55+
56+
val red = android.graphics.Color.red(pixel)
57+
val green = android.graphics.Color.green(pixel)
58+
val blue = android.graphics.Color.blue(pixel)
59+
60+
return (Color(red, green, blue))
61+
}
62+
63+
/**
64+
* Calculates color in a [radius] in ([offsetX], [offsetY]) in [bitmap] that is in a Composable with
65+
* [width] and [height].
66+
*
67+
* @param offsetX x position of bitmap
68+
* @param offsetY y position of bitmap
69+
* @param startImageX x coordinate of top left position of image.
70+
* @param startImageY y coordinate of top left position of image.
71+
* @param width width of Composable that contains [bitmap].
72+
* @param height height of Composable that contains [bitmap].
73+
* @param radius of color detection circle. Based on this radius colors are calculated and
74+
* average of red, green, blue is returned as [Color]
75+
* @param bitmap image used for detecting colors of.
76+
*/
77+
fun calculateColorInRadius(
78+
offsetX: Float,
79+
offsetY: Float,
80+
startImageX: Float = 0f,
81+
startImageY: Float = 0f,
82+
width: Int,
83+
height: Int,
84+
radius: Float = 0f,
85+
bitmap: Bitmap,
86+
): Color {
87+
88+
val bitmapWidth = bitmap.width
89+
val bitmapHeight = bitmap.height
90+
91+
// End positions, this might be less than Image dimensions if bitmap doesn't fit Image
92+
val endImageX = width - startImageX
93+
val endImageY = height - startImageY
94+
95+
val scaledX =
96+
scale(
97+
start1 = startImageX,
98+
end1 = endImageX,
99+
pos = offsetX,
100+
start2 = 0f,
101+
end2 = bitmapWidth.toFloat()
102+
).toInt().coerceIn(0, bitmapWidth - 1)
103+
104+
val scaledY =
105+
scale(
106+
start1 = startImageY,
107+
end1 = endImageY,
108+
pos = offsetY,
109+
start2 = 0f,
110+
end2 = bitmapHeight.toFloat()
111+
).toInt().coerceIn(0, bitmapHeight - 1)
112+
113+
val color = if (radius <= 0f) {
114+
val pixel: Int = bitmap.getPixel(scaledX, scaledY)
115+
116+
val red = android.graphics.Color.red(pixel)
117+
val green = android.graphics.Color.green(pixel)
118+
val blue = android.graphics.Color.blue(pixel)
119+
Color(red, green, blue)
120+
} else {
121+
val startX = (scaledX - radius).toInt().coerceAtLeast(0)
122+
val endX = (scaledX + radius).toInt().coerceAtMost(width)
123+
124+
val startY = (scaledY - radius).toInt().coerceAtLeast(0)
125+
val endY = (scaledY + radius).toInt().coerceAtMost(height)
126+
127+
val averageColor = floatArrayOf(0f, 0f, 0f)
128+
129+
var count = 1
130+
131+
for (x in startX..endX) {
132+
for (y in startY..endY) {
133+
134+
// TODO Add a distance check to make sure that pixels are inside a circle
135+
val pixel: Int = bitmap.getPixel(x, y)
136+
137+
val red = android.graphics.Color.red(pixel)
138+
val green = android.graphics.Color.green(pixel)
139+
val blue = android.graphics.Color.blue(pixel)
140+
141+
averageColor[0] += (red - averageColor[0]) / count
142+
averageColor[1] += (green - averageColor[1]) / count
143+
averageColor[2] += (blue - averageColor[2]) / count
144+
145+
count++
146+
}
147+
}
148+
149+
Color(averageColor[0].toInt(), averageColor[1].toInt(), averageColor[2].toInt())
150+
}
151+
152+
return color
153+
}

0 commit comments

Comments
 (0)