Skip to content

Commit

Permalink
add color detecton from screen demo
Browse files Browse the repository at this point in the history
  • Loading branch information
SmartToolFactory committed Apr 15, 2022
1 parent 7dcb2be commit 9567c64
Show file tree
Hide file tree
Showing 6 changed files with 3,869 additions and 9 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,5 +203,6 @@ data class BrushColor(
- [x] Add option to display colors in a dialog
- [x] Add gradient color selection with percentage stops, linear, radial and sweep options
- [x] Add gradient selection demo
- [x] Add color detection from screen demo


Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class MainActivity : ComponentActivity() {
private fun HomeContent() {

val pagerState: PagerState = rememberPagerState(initialPage = 0)

val coroutineScope = rememberCoroutineScope()

ScrollableTabRow(
Expand All @@ -66,7 +67,7 @@ private fun HomeContent() {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
},
}
)
}
}
Expand All @@ -79,12 +80,13 @@ private fun HomeContent() {
when (page) {
0 -> ColorPickerDemo()
1 -> ColorAndGradientPickerDemo()
2 -> SaturationSelectorDemo()
3 -> GradientSelectionDemo()
4 -> GradientAngleDemo()
5 -> HSVHSLGradientDemo()
6 -> ColorfulSliderDemo()
7 -> HexConversionDemo()
2 -> GradientSelectionDemo()
3 -> ColorDetectionFromScreenDemo()
4 -> HexConversionDemo()
5 -> GradientAngleDemo()
6 -> SaturationSelectorDemo()
7 -> HSVHSLGradientDemo()
8 -> ColorfulSliderDemo()
else -> ColorModeConversionDemo()
}
}
Expand All @@ -94,11 +96,12 @@ internal val tabList =
listOf(
"Color Picker",
"Gradient Color Picker",
"Saturation Selector",
"Gradient Selection",
"Detect Screen Color",
"Hex Conversions",
"Gradient Angle",
"Saturation Selector",
"HSV&HSL Gradients",
"Colorful Sliders",
"Hex Conversions",
"Color Mode Conversions"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package com.smarttoolfactory.composecolorpicker.demo

import android.graphics.Bitmap
import android.graphics.Canvas
import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.isUnspecified
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.*
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.smarttoolfactory.colorpicker.ui.Blue400
import com.smarttoolfactory.composecolorpicker.R

@Composable
fun ColorDetectionFromScreenDemo() {
// These are for debugging
var text by remember { mutableStateOf("") }
var colorAtTouchPosition by remember { mutableStateOf(Color.Unspecified) }


Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {

Box(
modifier = Modifier
.fillMaxWidth()
.height(100.dp)
)
Text(
text = "Simple demonstration to detect colors in ImageColorDetection composable " +
"covered with green border. Bitmap of the composable is created when after " +
"globally positioned",
fontSize = 14.sp,
color = Blue400,
modifier = Modifier.padding(2.dp)
)

ImageColorDetection(
modifier=Modifier.padding(10.dp),
content = {

Column(
modifier = Modifier
.border(2.dp, Color.Green)
.padding(5.dp)
) {

Image(
bitmap = ImageBitmap.imageResource(
LocalContext.current.resources,
R.drawable.landscape
),
contentDescription = null,
modifier = Modifier
.background(Color.LightGray)
.fillMaxWidth()
// This is for displaying different ratio, optional
.aspectRatio(4f / 3),
contentScale = ContentScale.Crop
)

Button(onClick = { /*TODO*/ }) {
Text("Sample Button")
}
}
},
{ colorChange: Color, textChange: String ->
colorAtTouchPosition = colorChange
text = textChange
},

)

Text(text = text)
Box(
modifier = Modifier
.then(
if (colorAtTouchPosition.isUnspecified) {
Modifier
} else {
Modifier
.clip(RoundedCornerShape(20))
.border(2.dp, Color.Black, shape = RoundedCornerShape(20))
.background(colorAtTouchPosition)
}
)
.size(100.dp)

)
}
}

@Composable
private fun ImageColorDetection(
modifier: Modifier=Modifier,
content: @Composable () -> Unit,
onColorChange: (Color, String) -> Unit,
) {

val view = LocalView.current

var offsetX by remember { mutableStateOf(0f) }
var offsetY by remember { mutableStateOf(0f) }

var color by remember { mutableStateOf(Color.Unspecified) }

var composableBounds by remember {
mutableStateOf<Rect?>(null)
}
var bitmap by remember {
mutableStateOf<Bitmap?>(
null
)
}

DisposableEffect(Unit) {
onDispose {
bitmap?.apply {
if (!isRecycled) recycle()
bitmap = null
}
}
}

val colorDetectionModifier = modifier
.pointerInput(Unit) {
detectDragGestures(onDrag = { change: PointerInputChange, _: Offset ->

if (composableBounds == null) return@detectDragGestures

if (bitmap == null) {
val boundsRect = composableBounds!!

bitmap = Bitmap.createBitmap(
boundsRect.width.toInt(),
boundsRect.height.toInt(),
Bitmap.Config.ARGB_8888
)

bitmap?.let { bmp ->
val canvas = Canvas(bmp)
.apply {
translate(-boundsRect.left, -boundsRect.top)
}
view.draw(canvas)
}
}

val bmp: Bitmap = bitmap!!
val bitmapWidth = bmp.width
val bitmapHeight = bmp.height

// Touch coordinates on image
offsetX = change.position.x.coerceIn(0f, bitmapWidth.toFloat())
offsetY = change.position.y.coerceIn(0f, bitmapHeight.toFloat())

// Scale from Image touch coordinates to range in Bitmap
val scaledX = offsetX
val scaledY = offsetY

try {
val pixel: Int = bmp.getPixel(scaledX.toInt(), scaledY.toInt())

val red = android.graphics.Color.red(pixel)
val green = android.graphics.Color.green(pixel)
val blue = android.graphics.Color.blue(pixel)

val text = "Touch offsetX:$offsetX, offsetY: $offsetY\n" +
"Bitmap width: ${bitmapWidth}, height: $bitmapHeight\n" +
"scaledX: $scaledX, scaledY: $scaledY\n" +
"red: $red, green: $green, blue: $blue\n"

color = Color(red, green, blue)

onColorChange(color, text)
} catch (e: Exception) {
println("Exception e: ${e.message}")
}
}
)
}
.drawWithContent {
drawContent()
val center = Offset(offsetX, offsetY)
drawCircle(Color.Black, radius = 20f, style = Stroke(16f), center = center)
drawCircle(Color.White, radius = 20f, style = Stroke(14f), center = center)
}
.onGloballyPositioned {
composableBounds = it.boundsInRoot()
}


Column(modifier = colorDetectionModifier) {
content()
}
}
Binary file added app/src/main/res/drawable/landscape.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 9567c64

Please sign in to comment.