Skip to content

Commit 2a29b37

Browse files
add draw on image sample
1 parent a84f150 commit 2a29b37

File tree

2 files changed

+252
-1
lines changed

2 files changed

+252
-1
lines changed
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ fun ImageWithMarkersSample() {
6363
val markerList = rememberMarkerList()
6464

6565
Column(
66-
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(8.dp)
66+
modifier = Modifier
67+
.fillMaxSize()
68+
.verticalScroll(rememberScrollState())
69+
.padding(8.dp)
6770
) {
6871

6972
Text("ContentScale: ContentScale.Fit, alignment: TopCenter")
@@ -364,3 +367,4 @@ data class Marker(
364367
val coordinateY: Float,
365368
val note: String = "",
366369
)
370+
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
package com.smarttoolfactory.tutorial1_1basics.chapter5_gesture
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.border
6+
import androidx.compose.foundation.gestures.detectTapGestures
7+
import androidx.compose.foundation.layout.Box
8+
import androidx.compose.foundation.layout.Column
9+
import androidx.compose.foundation.layout.Spacer
10+
import androidx.compose.foundation.layout.aspectRatio
11+
import androidx.compose.foundation.layout.fillMaxSize
12+
import androidx.compose.foundation.layout.fillMaxWidth
13+
import androidx.compose.foundation.layout.height
14+
import androidx.compose.foundation.layout.padding
15+
import androidx.compose.foundation.rememberScrollState
16+
import androidx.compose.foundation.verticalScroll
17+
import androidx.compose.material.Text
18+
import androidx.compose.runtime.Composable
19+
import androidx.compose.runtime.getValue
20+
import androidx.compose.runtime.mutableStateListOf
21+
import androidx.compose.runtime.mutableStateOf
22+
import androidx.compose.runtime.remember
23+
import androidx.compose.runtime.setValue
24+
import androidx.compose.ui.Alignment
25+
import androidx.compose.ui.Modifier
26+
import androidx.compose.ui.draw.drawWithContent
27+
import androidx.compose.ui.geometry.Offset
28+
import androidx.compose.ui.geometry.Size
29+
import androidx.compose.ui.graphics.Color
30+
import androidx.compose.ui.graphics.drawscope.Stroke
31+
import androidx.compose.ui.graphics.painter.Painter
32+
import androidx.compose.ui.input.pointer.pointerInput
33+
import androidx.compose.ui.layout.ContentScale
34+
import androidx.compose.ui.layout.onSizeChanged
35+
import androidx.compose.ui.res.painterResource
36+
import androidx.compose.ui.tooling.preview.Preview
37+
import androidx.compose.ui.unit.dp
38+
import androidx.compose.ui.unit.toSize
39+
import com.smarttoolfactory.tutorial1_1basics.R
40+
41+
@Preview
42+
@Composable
43+
fun ImageBoundsDrawSample() {
44+
45+
Column(
46+
modifier = Modifier
47+
.fillMaxSize()
48+
.verticalScroll(rememberScrollState())
49+
.padding(8.dp)
50+
) {
51+
52+
val pointsOnBitmap = remember {
53+
mutableStateListOf<Offset>()
54+
}
55+
56+
val painter = painterResource(R.drawable.landscape10)
57+
58+
Text("ContentScale: ContentScale.Fit, alignment: TopCenter")
59+
ImageWithBounds(
60+
modifier = Modifier
61+
.border(2.dp, Color.Red)
62+
.background(Color.LightGray)
63+
.fillMaxWidth()
64+
.aspectRatio(4 / 3f),
65+
contentScale = ContentScale.Fit,
66+
pointsOnBitmap = pointsOnBitmap,
67+
painter = painter
68+
) { pointOnBitmap: Offset ->
69+
pointsOnBitmap.add(pointOnBitmap)
70+
}
71+
72+
Spacer(modifier = Modifier.height(16.dp))
73+
Text("ContentScale: ContentScale.FillBounds, alignment: TopCenter")
74+
ImageWithBounds(
75+
modifier = Modifier
76+
.border(2.dp, Color.Red)
77+
.background(Color.LightGray)
78+
.fillMaxWidth()
79+
.aspectRatio(3 / 2f),
80+
contentScale = ContentScale.FillBounds,
81+
pointsOnBitmap = pointsOnBitmap,
82+
painter = painter
83+
) { pointOnBitmap: Offset ->
84+
pointsOnBitmap.add(pointOnBitmap)
85+
}
86+
87+
Spacer(modifier = Modifier.height(16.dp))
88+
Text("ContentScale: ContentScale.Fit, alignment: BottomEnd")
89+
ImageWithBounds(
90+
modifier = Modifier
91+
.border(2.dp, Color.Red)
92+
.background(Color.LightGray)
93+
.fillMaxWidth()
94+
.aspectRatio(5 / 3f),
95+
contentScale = ContentScale.Fit,
96+
alignment = Alignment.BottomEnd,
97+
pointsOnBitmap = pointsOnBitmap,
98+
painter = painter
99+
) { pointOnBitmap: Offset ->
100+
pointsOnBitmap.add(pointOnBitmap)
101+
}
102+
103+
Spacer(modifier = Modifier.height(16.dp))
104+
Text("ContentScale: ContentScale.Crop, alignment: TopCenter")
105+
ImageWithBounds(
106+
modifier = Modifier
107+
.border(2.dp, Color.Red)
108+
.background(Color.LightGray)
109+
.fillMaxWidth()
110+
.aspectRatio(3 / 4f),
111+
contentScale = ContentScale.Crop,
112+
pointsOnBitmap = pointsOnBitmap,
113+
painter = painter
114+
) { pointOnBitmap: Offset ->
115+
pointsOnBitmap.add(pointOnBitmap)
116+
}
117+
Spacer(modifier = Modifier.height(16.dp))
118+
Text("ContentScale: ContentScale.Crop, alignment: TopStart")
119+
ImageWithBounds(
120+
modifier = Modifier
121+
.border(2.dp, Color.Red)
122+
.background(Color.LightGray)
123+
.fillMaxWidth()
124+
.aspectRatio(3 / 4f),
125+
contentScale = ContentScale.Crop,
126+
alignment = Alignment.TopStart,
127+
pointsOnBitmap = pointsOnBitmap,
128+
painter = painter
129+
) { pointOnBitmap: Offset ->
130+
pointsOnBitmap.add(pointOnBitmap)
131+
}
132+
}
133+
}
134+
135+
136+
@Composable
137+
private fun ImageWithBounds(
138+
modifier: Modifier = Modifier,
139+
contentScale: ContentScale,
140+
alignment: Alignment = Alignment.Center,
141+
painter: Painter,
142+
pointsOnBitmap: List<Offset>,
143+
onClick: (positionOnBitmap: Offset) -> Unit,
144+
) {
145+
146+
var imageProperties by remember {
147+
mutableStateOf(ImageProperties.Zero)
148+
}
149+
150+
151+
Box(
152+
modifier = Modifier.padding(vertical = 16.dp)
153+
) {
154+
155+
Image(
156+
modifier = modifier
157+
.drawWithContent {
158+
drawContent()
159+
160+
val drawAreaRect = imageProperties.drawAreaRect
161+
val bitmapRect = imageProperties.bitmapRect
162+
val scaleFactor = imageProperties.scaleFactor
163+
164+
// This is for displaying area that bitmap is drawn in Image Composable
165+
drawRect(
166+
color = Color.Green,
167+
topLeft = drawAreaRect.topLeft,
168+
size = drawAreaRect.size,
169+
style = Stroke(
170+
4.dp.toPx(),
171+
)
172+
)
173+
174+
val size = pointsOnBitmap.size
175+
pointsOnBitmap.forEachIndexed { index: Int, offset: Offset ->
176+
177+
val scaledCurrentOffset = scaleFromBitmapToScreenPosition(
178+
offsetBitmap = offset,
179+
drawAreaRect = drawAreaRect,
180+
bitmapRect = bitmapRect,
181+
scaleFactor = scaleFactor
182+
)
183+
if (size > 1 && index > 0) {
184+
185+
val scaledPreviousOffset = scaleFromBitmapToScreenPosition(
186+
offsetBitmap = pointsOnBitmap[index - 1],
187+
drawAreaRect = drawAreaRect,
188+
bitmapRect = bitmapRect,
189+
scaleFactor = scaleFactor
190+
)
191+
192+
drawLine(
193+
color = Color.Blue,
194+
start = scaledPreviousOffset,
195+
end = scaledCurrentOffset,
196+
strokeWidth = 3.dp.toPx()
197+
)
198+
}
199+
200+
drawCircle(
201+
color = Color.Red,
202+
center = scaledCurrentOffset,
203+
radius = 6.dp.toPx()
204+
)
205+
}
206+
}
207+
.pointerInput(contentScale) {
208+
detectTapGestures { offset: Offset ->
209+
210+
val bitmapRect = imageProperties.bitmapRect
211+
val drawAreaRect = imageProperties.drawAreaRect
212+
val isTouchInImage = drawAreaRect.contains(offset)
213+
214+
if (isTouchInImage) {
215+
216+
val offsetOnBitmap = scaleFromScreenToBitmapPosition(
217+
offsetScreen = offset,
218+
bitmapRect = bitmapRect,
219+
drawAreaRect = drawAreaRect,
220+
scaleFactor = imageProperties.scaleFactor
221+
)
222+
223+
onClick(offsetOnBitmap)
224+
}
225+
}
226+
}
227+
.onSizeChanged {
228+
val imageSize = it
229+
val dstSize: Size = imageSize.toSize()
230+
231+
val srcSize = painter.intrinsicSize
232+
233+
imageProperties = calculateImageDrawProperties(
234+
srcSize = srcSize,
235+
dstSize = dstSize,
236+
contentScale = contentScale,
237+
alignment = alignment
238+
)
239+
},
240+
painter = painter,
241+
contentScale = contentScale,
242+
alignment = alignment,
243+
contentDescription = null
244+
)
245+
246+
}
247+
}

0 commit comments

Comments
 (0)