Skip to content

Commit 9567c64

Browse files
add color detecton from screen demo
1 parent 7dcb2be commit 9567c64

File tree

6 files changed

+3869
-9
lines changed

6 files changed

+3869
-9
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,5 +203,6 @@ data class BrushColor(
203203
- [x] Add option to display colors in a dialog
204204
- [x] Add gradient color selection with percentage stops, linear, radial and sweep options
205205
- [x] Add gradient selection demo
206+
- [x] Add color detection from screen demo
206207

207208

app/src/main/java/com/smarttoolfactory/composecolorpicker/MainActivity.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class MainActivity : ComponentActivity() {
4646
private fun HomeContent() {
4747

4848
val pagerState: PagerState = rememberPagerState(initialPage = 0)
49+
4950
val coroutineScope = rememberCoroutineScope()
5051

5152
ScrollableTabRow(
@@ -66,7 +67,7 @@ private fun HomeContent() {
6667
coroutineScope.launch {
6768
pagerState.animateScrollToPage(index)
6869
}
69-
},
70+
}
7071
)
7172
}
7273
}
@@ -79,12 +80,13 @@ private fun HomeContent() {
7980
when (page) {
8081
0 -> ColorPickerDemo()
8182
1 -> ColorAndGradientPickerDemo()
82-
2 -> SaturationSelectorDemo()
83-
3 -> GradientSelectionDemo()
84-
4 -> GradientAngleDemo()
85-
5 -> HSVHSLGradientDemo()
86-
6 -> ColorfulSliderDemo()
87-
7 -> HexConversionDemo()
83+
2 -> GradientSelectionDemo()
84+
3 -> ColorDetectionFromScreenDemo()
85+
4 -> HexConversionDemo()
86+
5 -> GradientAngleDemo()
87+
6 -> SaturationSelectorDemo()
88+
7 -> HSVHSLGradientDemo()
89+
8 -> ColorfulSliderDemo()
8890
else -> ColorModeConversionDemo()
8991
}
9092
}
@@ -94,11 +96,12 @@ internal val tabList =
9496
listOf(
9597
"Color Picker",
9698
"Gradient Color Picker",
97-
"Saturation Selector",
9899
"Gradient Selection",
100+
"Detect Screen Color",
101+
"Hex Conversions",
99102
"Gradient Angle",
103+
"Saturation Selector",
100104
"HSV&HSL Gradients",
101105
"Colorful Sliders",
102-
"Hex Conversions",
103106
"Color Mode Conversions"
104107
)
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
package com.smarttoolfactory.composecolorpicker.demo
2+
3+
import android.graphics.Bitmap
4+
import android.graphics.Canvas
5+
import androidx.compose.foundation.*
6+
import androidx.compose.foundation.gestures.detectDragGestures
7+
import androidx.compose.foundation.layout.*
8+
import androidx.compose.foundation.shape.RoundedCornerShape
9+
import androidx.compose.material.Button
10+
import androidx.compose.material.Text
11+
import androidx.compose.runtime.*
12+
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.draw.clip
14+
import androidx.compose.ui.draw.drawWithContent
15+
import androidx.compose.ui.geometry.Offset
16+
import androidx.compose.ui.geometry.Rect
17+
import androidx.compose.ui.graphics.Color
18+
import androidx.compose.ui.graphics.ImageBitmap
19+
import androidx.compose.ui.graphics.drawscope.Stroke
20+
import androidx.compose.ui.graphics.isUnspecified
21+
import androidx.compose.ui.input.pointer.PointerInputChange
22+
import androidx.compose.ui.input.pointer.pointerInput
23+
import androidx.compose.ui.layout.*
24+
import androidx.compose.ui.platform.LocalContext
25+
import androidx.compose.ui.platform.LocalView
26+
import androidx.compose.ui.res.imageResource
27+
import androidx.compose.ui.unit.dp
28+
import androidx.compose.ui.unit.sp
29+
import com.smarttoolfactory.colorpicker.ui.Blue400
30+
import com.smarttoolfactory.composecolorpicker.R
31+
32+
@Composable
33+
fun ColorDetectionFromScreenDemo() {
34+
// These are for debugging
35+
var text by remember { mutableStateOf("") }
36+
var colorAtTouchPosition by remember { mutableStateOf(Color.Unspecified) }
37+
38+
39+
Column(
40+
modifier = Modifier
41+
.fillMaxSize()
42+
.verticalScroll(rememberScrollState())
43+
) {
44+
45+
Box(
46+
modifier = Modifier
47+
.fillMaxWidth()
48+
.height(100.dp)
49+
)
50+
Text(
51+
text = "Simple demonstration to detect colors in ImageColorDetection composable " +
52+
"covered with green border. Bitmap of the composable is created when after " +
53+
"globally positioned",
54+
fontSize = 14.sp,
55+
color = Blue400,
56+
modifier = Modifier.padding(2.dp)
57+
)
58+
59+
ImageColorDetection(
60+
modifier=Modifier.padding(10.dp),
61+
content = {
62+
63+
Column(
64+
modifier = Modifier
65+
.border(2.dp, Color.Green)
66+
.padding(5.dp)
67+
) {
68+
69+
Image(
70+
bitmap = ImageBitmap.imageResource(
71+
LocalContext.current.resources,
72+
R.drawable.landscape
73+
),
74+
contentDescription = null,
75+
modifier = Modifier
76+
.background(Color.LightGray)
77+
.fillMaxWidth()
78+
// This is for displaying different ratio, optional
79+
.aspectRatio(4f / 3),
80+
contentScale = ContentScale.Crop
81+
)
82+
83+
Button(onClick = { /*TODO*/ }) {
84+
Text("Sample Button")
85+
}
86+
}
87+
},
88+
{ colorChange: Color, textChange: String ->
89+
colorAtTouchPosition = colorChange
90+
text = textChange
91+
},
92+
93+
)
94+
95+
Text(text = text)
96+
Box(
97+
modifier = Modifier
98+
.then(
99+
if (colorAtTouchPosition.isUnspecified) {
100+
Modifier
101+
} else {
102+
Modifier
103+
.clip(RoundedCornerShape(20))
104+
.border(2.dp, Color.Black, shape = RoundedCornerShape(20))
105+
.background(colorAtTouchPosition)
106+
}
107+
)
108+
.size(100.dp)
109+
110+
)
111+
}
112+
}
113+
114+
@Composable
115+
private fun ImageColorDetection(
116+
modifier: Modifier=Modifier,
117+
content: @Composable () -> Unit,
118+
onColorChange: (Color, String) -> Unit,
119+
) {
120+
121+
val view = LocalView.current
122+
123+
var offsetX by remember { mutableStateOf(0f) }
124+
var offsetY by remember { mutableStateOf(0f) }
125+
126+
var color by remember { mutableStateOf(Color.Unspecified) }
127+
128+
var composableBounds by remember {
129+
mutableStateOf<Rect?>(null)
130+
}
131+
var bitmap by remember {
132+
mutableStateOf<Bitmap?>(
133+
null
134+
)
135+
}
136+
137+
DisposableEffect(Unit) {
138+
onDispose {
139+
bitmap?.apply {
140+
if (!isRecycled) recycle()
141+
bitmap = null
142+
}
143+
}
144+
}
145+
146+
val colorDetectionModifier = modifier
147+
.pointerInput(Unit) {
148+
detectDragGestures(onDrag = { change: PointerInputChange, _: Offset ->
149+
150+
if (composableBounds == null) return@detectDragGestures
151+
152+
if (bitmap == null) {
153+
val boundsRect = composableBounds!!
154+
155+
bitmap = Bitmap.createBitmap(
156+
boundsRect.width.toInt(),
157+
boundsRect.height.toInt(),
158+
Bitmap.Config.ARGB_8888
159+
)
160+
161+
bitmap?.let { bmp ->
162+
val canvas = Canvas(bmp)
163+
.apply {
164+
translate(-boundsRect.left, -boundsRect.top)
165+
}
166+
view.draw(canvas)
167+
}
168+
}
169+
170+
val bmp: Bitmap = bitmap!!
171+
val bitmapWidth = bmp.width
172+
val bitmapHeight = bmp.height
173+
174+
// Touch coordinates on image
175+
offsetX = change.position.x.coerceIn(0f, bitmapWidth.toFloat())
176+
offsetY = change.position.y.coerceIn(0f, bitmapHeight.toFloat())
177+
178+
// Scale from Image touch coordinates to range in Bitmap
179+
val scaledX = offsetX
180+
val scaledY = offsetY
181+
182+
try {
183+
val pixel: Int = bmp.getPixel(scaledX.toInt(), scaledY.toInt())
184+
185+
val red = android.graphics.Color.red(pixel)
186+
val green = android.graphics.Color.green(pixel)
187+
val blue = android.graphics.Color.blue(pixel)
188+
189+
val text = "Touch offsetX:$offsetX, offsetY: $offsetY\n" +
190+
"Bitmap width: ${bitmapWidth}, height: $bitmapHeight\n" +
191+
"scaledX: $scaledX, scaledY: $scaledY\n" +
192+
"red: $red, green: $green, blue: $blue\n"
193+
194+
color = Color(red, green, blue)
195+
196+
onColorChange(color, text)
197+
} catch (e: Exception) {
198+
println("Exception e: ${e.message}")
199+
}
200+
}
201+
)
202+
}
203+
.drawWithContent {
204+
drawContent()
205+
val center = Offset(offsetX, offsetY)
206+
drawCircle(Color.Black, radius = 20f, style = Stroke(16f), center = center)
207+
drawCircle(Color.White, radius = 20f, style = Stroke(14f), center = center)
208+
}
209+
.onGloballyPositioned {
210+
composableBounds = it.boundsInRoot()
211+
}
212+
213+
214+
Column(modifier = colorDetectionModifier) {
215+
content()
216+
}
217+
}
1.5 MB
Loading

0 commit comments

Comments
 (0)