1
+ package com.example.compose.snippets.images
2
+
3
+ import androidx.compose.foundation.Image
4
+ import androidx.compose.foundation.background
5
+ import androidx.compose.foundation.layout.Box
6
+ import androidx.compose.foundation.layout.padding
7
+ import androidx.compose.foundation.layout.wrapContentSize
8
+ import androidx.compose.runtime.Composable
9
+ import androidx.compose.runtime.remember
10
+ import androidx.compose.ui.Modifier
11
+ import androidx.compose.ui.draw.paint
12
+ import androidx.compose.ui.geometry.Size
13
+ import androidx.compose.ui.graphics.BlendMode
14
+ import androidx.compose.ui.graphics.Color
15
+ import androidx.compose.ui.graphics.ImageBitmap
16
+ import androidx.compose.ui.graphics.drawscope.DrawScope
17
+ import androidx.compose.ui.graphics.painter.Painter
18
+ import androidx.compose.ui.layout.ContentScale
19
+ import androidx.compose.ui.res.imageResource
20
+ import androidx.compose.ui.res.stringResource
21
+ import androidx.compose.ui.tooling.preview.Preview
22
+ import androidx.compose.ui.unit.IntOffset
23
+ import androidx.compose.ui.unit.IntSize
24
+ import androidx.compose.ui.unit.dp
25
+ import androidx.compose.ui.unit.toSize
26
+ import com.example.compose.snippets.R
27
+ import kotlin.math.roundToInt
28
+
29
+ /*
30
+ * Copyright 2022 The Android Open Source Project
31
+ *
32
+ * Licensed under the Apache License, Version 2.0 (the "License");
33
+ * you may not use this file except in compliance with the License.
34
+ * You may obtain a copy of the License at
35
+ *
36
+ * http://www.apache.org/licenses/LICENSE-2.0
37
+ *
38
+ * Unless required by applicable law or agreed to in writing, software
39
+ * distributed under the License is distributed on an "AS IS" BASIS,
40
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
41
+ * See the License for the specific language governing permissions and
42
+ * limitations under the License.
43
+ */
44
+ @Preview
45
+ @Composable
46
+ fun CustomPainterUsage () {
47
+ // [START android_compose_images_custom_painter_usage]
48
+ val rainbowImage = ImageBitmap .imageResource(id = R .drawable.rainbow)
49
+ val dogImage = ImageBitmap .imageResource(id = R .drawable.dog)
50
+ val customPainter = remember {
51
+ OverlayImagePainter (dogImage, rainbowImage)
52
+ }
53
+ Image (
54
+ painter = customPainter,
55
+ contentDescription = stringResource(id = R .string.dog_content_description),
56
+ contentScale = ContentScale .Crop ,
57
+ modifier = Modifier .wrapContentSize()
58
+ )
59
+ // [END android_compose_images_custom_painter_usage]
60
+ }
61
+
62
+ // [START android_compose_images_custom_painter]
63
+ class OverlayImagePainter constructor(
64
+ private val image : ImageBitmap ,
65
+ private val imageOverlay : ImageBitmap ,
66
+ private val srcOffset : IntOffset = IntOffset .Zero ,
67
+ private val srcSize : IntSize = IntSize (image.width, image.height),
68
+ private val overlaySize : IntSize = IntSize (imageOverlay.width, imageOverlay.height)
69
+ ) : Painter() {
70
+
71
+ private val size: IntSize = validateSize(srcOffset, srcSize)
72
+ override fun DrawScope.onDraw () {
73
+ // draw the first image without any blend mode
74
+ drawImage(
75
+ image,
76
+ srcOffset,
77
+ srcSize,
78
+ dstSize = IntSize (
79
+ this @onDraw.size.width.roundToInt(),
80
+ this @onDraw.size.height.roundToInt()
81
+ )
82
+ )
83
+ // draw the second image with an Overlay blend mode to blend the two together
84
+ drawImage(
85
+ imageOverlay,
86
+ srcOffset,
87
+ overlaySize,
88
+ dstSize = IntSize (
89
+ this @onDraw.size.width.roundToInt(),
90
+ this @onDraw.size.height.roundToInt()
91
+ ),
92
+ blendMode = BlendMode .Overlay
93
+ )
94
+ }
95
+
96
+ /* *
97
+ * Return the dimension of the underlying [ImageBitmap] as it's intrinsic width and height
98
+ */
99
+ override val intrinsicSize: Size get() = size.toSize()
100
+
101
+ private fun validateSize (srcOffset : IntOffset , srcSize : IntSize ): IntSize {
102
+ require(
103
+ srcOffset.x >= 0 &&
104
+ srcOffset.y >= 0 &&
105
+ srcSize.width >= 0 &&
106
+ srcSize.height >= 0 &&
107
+ srcSize.width <= image.width &&
108
+ srcSize.height <= image.height
109
+ )
110
+ return srcSize
111
+ }
112
+ }
113
+ // [END android_compose_images_custom_painter]
114
+
115
+ @Preview
116
+ @Composable
117
+ fun CustomPainterModifier () {
118
+ // [START android_compose_custom_painter_modifier]
119
+ val rainbowImage = ImageBitmap .imageResource(id = R .drawable.rainbow)
120
+ val dogImage = ImageBitmap .imageResource(id = R .drawable.dog)
121
+ val customPainter = remember {
122
+ OverlayImagePainter (dogImage, rainbowImage)
123
+ }
124
+ Box (
125
+ modifier =
126
+ Modifier .background(color = Color .Gray )
127
+ .padding(30 .dp)
128
+ .background(color = Color .Yellow )
129
+ .paint(customPainter)
130
+ ) { /* * intentionally empty **/ }
131
+ // [END android_compose_custom_painter_modifier]
132
+ }
0 commit comments