0
# Image and Drawable Resources
1
2
Image and drawable resources provide type-safe access to visual assets including raster images, vector graphics, and SVG files. The library automatically handles format detection, density-aware scaling, and platform-specific optimizations.
3
4
## Core Types
5
6
```kotlin { .api }
7
class DrawableResource(id: String, items: Set<ResourceItem>) : Resource(id, items)
8
```
9
10
A drawable resource represents any visual asset that can be rendered as an image, vector, or painter. This includes PNG, JPEG, WebP, XML vectors, and SVG files.
11
12
## Composable Functions
13
14
### Automatic Painter Creation
15
16
```kotlin { .api }
17
@Composable
18
fun painterResource(resource: DrawableResource): Painter
19
```
20
21
Creates a Painter from a drawable resource with automatic format detection. The function selects the appropriate painter type based on the file extension:
22
- `.xml` files → Vector painter
23
- `.svg` files → SVG painter
24
- Other formats → Bitmap painter
25
26
**Usage:**
27
```kotlin
28
@Composable
29
fun AppIcon() {
30
val icon = painterResource(Res.drawable.app_icon)
31
Image(
32
painter = icon,
33
contentDescription = "Application Icon",
34
modifier = Modifier.size(48.dp)
35
)
36
}
37
```
38
39
### Bitmap Image Loading
40
41
```kotlin { .api }
42
@Composable
43
fun imageResource(resource: DrawableResource): ImageBitmap
44
```
45
46
Loads a raster image as an ImageBitmap with automatic density scaling. The function selects the best density variant and scales appropriately for the current screen.
47
48
**Usage:**
49
```kotlin
50
@Composable
51
fun ProfilePhoto(user: User) {
52
val photo = imageResource(Res.drawable.default_profile)
53
Image(
54
bitmap = photo,
55
contentDescription = "Profile Photo",
56
contentScale = ContentScale.Crop,
57
modifier = Modifier
58
.size(80.dp)
59
.clip(CircleShape)
60
)
61
}
62
```
63
64
**Density Handling:**
65
The library automatically selects the best image density variant:
66
1. Exact or higher density match (preferred)
67
2. Lower density with upscaling
68
3. Default (MDPI) with scaling
69
4. LDPI as last resort
70
71
### Vector Graphics Loading
72
73
```kotlin { .api }
74
@Composable
75
fun vectorResource(resource: DrawableResource): ImageVector
76
```
77
78
Loads XML vector graphics as ImageVector objects. Supports Android Vector Drawable format with full path, group, and gradient support.
79
80
**Usage:**
81
```kotlin
82
@Composable
83
fun NavigationIcon(isSelected: Boolean) {
84
val icon = vectorResource(
85
if (isSelected) Res.drawable.ic_home_filled
86
else Res.drawable.ic_home_outline
87
)
88
Icon(
89
imageVector = icon,
90
contentDescription = "Home",
91
tint = if (isSelected) MaterialTheme.colors.primary
92
else MaterialTheme.colors.onSurface
93
)
94
}
95
```
96
97
## Suspend Functions
98
99
### Raw Resource Bytes
100
101
```kotlin { .api }
102
suspend fun getDrawableResourceBytes(
103
environment: ResourceEnvironment,
104
resource: DrawableResource
105
): ByteArray
106
```
107
108
Retrieves the raw byte content of a drawable resource. Useful for custom processing, external libraries, or passing to platform-specific APIs.
109
110
**Parameters:**
111
- `environment` - Resource environment for variant selection
112
- `resource` - The drawable resource to load
113
114
**Usage:**
115
```kotlin
116
suspend fun uploadImageToServer(imageResource: DrawableResource) {
117
val environment = getSystemResourceEnvironment()
118
val imageBytes = getDrawableResourceBytes(environment, imageResource)
119
120
// Upload bytes to server
121
uploadService.uploadImage(imageBytes)
122
}
123
124
suspend fun saveImageToFile(imageResource: DrawableResource, outputPath: String) {
125
val environment = getSystemResourceEnvironment()
126
val bytes = getDrawableResourceBytes(environment, imageResource)
127
File(outputPath).writeBytes(bytes)
128
}
129
```
130
131
## Resource Variants and Selection
132
133
### Density Qualifiers
134
135
The library supports multiple density variants for optimal display quality:
136
137
```
138
drawable/ # Default (MDPI - 160dpi)
139
drawable-ldpi/ # Low density (120dpi)
140
drawable-hdpi/ # High density (240dpi)
141
drawable-xhdpi/ # Extra high density (320dpi)
142
drawable-xxhdpi/ # Extra extra high density (480dpi)
143
drawable-xxxhdpi/ # Extra extra extra high density (640dpi)
144
```
145
146
**Selection Algorithm:**
147
1. Find exact or next higher density
148
2. Scale down if necessary (preferred)
149
3. Fall back to lower density with upscaling
150
4. Use default (MDPI) if no specific density available
151
152
### Theme Variants
153
154
Support for light and dark theme variants:
155
156
```
157
drawable/ # Default/light theme
158
drawable-night/ # Dark theme variants
159
```
160
161
**Usage:**
162
```kotlin
163
@Composable
164
fun ThemedIcon() {
165
// Automatically selects light/dark variant based on system theme
166
val icon = painterResource(Res.drawable.themed_icon)
167
Icon(imageVector = icon, contentDescription = "Themed Icon")
168
}
169
```
170
171
## Supported Formats
172
173
### Raster Images
174
- **PNG** - Full transparency support, recommended for icons
175
- **JPEG** - Efficient for photos, no transparency
176
- **WebP** - Modern format with excellent compression
177
178
### Vector Graphics
179
- **XML Vector Drawable** - Android's vector format with paths, groups, gradients
180
- **SVG** - Scalable Vector Graphics with broad compatibility
181
182
### Format Detection
183
The library automatically detects format based on file extension:
184
- `.png`, `.jpg`, `.jpeg`, `.webp` → Bitmap handling
185
- `.xml` → Vector drawable parsing
186
- `.svg` → SVG parsing and rendering
187
188
## Performance Considerations
189
190
### Image Caching
191
192
The library includes automatic caching to improve performance:
193
194
```kotlin
195
// Images are cached by path and density
196
// Cache key format: "path-{density}dpi"
197
val cachedImage = imageResource(Res.drawable.large_image) // Cached on first load
198
```
199
200
### Memory Management
201
202
**Best Practices:**
203
1. Use appropriate image densities to avoid unnecessary memory usage
204
2. Consider WebP format for better compression
205
3. Use vector graphics for simple icons and illustrations
206
4. Lazy load images in lists and grids
207
208
### Cache Control
209
210
```kotlin
211
// For testing or memory management, cache can be cleared
212
// Note: This is internal API
213
internal fun dropImageCache()
214
```
215
216
## Platform-Specific Behavior
217
218
### Android
219
- Native bitmap decoding with hardware acceleration
220
- Automatic density selection based on screen density
221
- Vector drawable native support
222
223
### Desktop (JVM)
224
- Skia-based rendering for consistent appearance
225
- Density simulation for high-DPI displays
226
- SVG support through integrated parser
227
228
### iOS
229
- Core Graphics integration for optimal performance
230
- Retina display support with automatic scaling
231
- Memory-efficient image loading
232
233
### Web (JS/Wasm)
234
- Canvas-based rendering for vectors
235
- Efficient image loading with browser caching
236
- Progressive loading for better user experience
237
238
## Error Handling
239
240
**Common Exceptions:**
241
- `MissingResourceException` - Resource file not found
242
- `IllegalArgumentException` - Invalid resource ID
243
- Rendering errors for corrupted or unsupported image formats
244
245
**Example Error Handling:**
246
```kotlin
247
@Composable
248
fun SafeImageLoad(resourceId: DrawableResource) {
249
try {
250
val image = painterResource(resourceId)
251
Image(painter = image, contentDescription = null)
252
} catch (e: MissingResourceException) {
253
// Show placeholder or error state
254
Icon(Icons.Default.ImageNotSupported, contentDescription = "Image not found")
255
}
256
}
257
```
258
259
## Best Practices
260
261
1. **Provide multiple density variants** for raster images:
262
```
263
drawable-mdpi/icon.png (48x48)
264
drawable-hdpi/icon.png (72x72)
265
drawable-xhdpi/icon.png (96x96)
266
drawable-xxhdpi/icon.png (144x144)
267
```
268
269
2. **Use vector drawables for simple graphics**:
270
- Icons, simple illustrations
271
- Graphics that need to scale without quality loss
272
- UI elements with solid colors
273
274
3. **Use raster images for complex graphics**:
275
- Photographs
276
- Complex illustrations with gradients
277
- Images with many colors and details
278
279
4. **Optimize image sizes** for target platforms:
280
- Consider platform-specific limitations
281
- Use appropriate compression settings
282
- Test on actual devices for performance
283
284
5. **Provide theme variants** when appropriate:
285
```kotlin
286
// Use same resource ID, library selects theme variant automatically
287
val icon = painterResource(Res.drawable.app_icon) // Auto light/dark
288
```
289
290
## Image Decoder Extensions
291
292
The library provides extension functions for decoding raw image bytes into Compose graphics objects.
293
294
### Bitmap Decoder
295
296
```kotlin { .api }
297
fun ByteArray.decodeToImageBitmap(): ImageBitmap
298
```
299
300
Decodes a byte array of a bitmap to an ImageBitmap. Supports JPEG, PNG, BMP, WEBP formats. Different platforms may support additional formats.
301
302
**Usage:**
303
```kotlin
304
suspend fun loadExternalImage(imageUrl: String): ImageBitmap {
305
val imageBytes = httpClient.get(imageUrl).readBytes()
306
return imageBytes.decodeToImageBitmap()
307
}
308
309
suspend fun processImageResource(): ImageBitmap {
310
val environment = getSystemResourceEnvironment()
311
val rawBytes = getDrawableResourceBytes(environment, Res.drawable.photo)
312
return rawBytes.decodeToImageBitmap()
313
}
314
```
315
316
### Vector Decoder
317
318
```kotlin { .api }
319
fun ByteArray.decodeToImageVector(density: Density): ImageVector
320
```
321
322
Decodes a byte array of a vector XML file to an ImageVector with the specified density for unit conversion.
323
324
**Parameters:**
325
- `density` - Density to apply during converting the source units to ImageVector units
326
327
**Usage:**
328
```kotlin
329
@Composable
330
fun CustomVectorProcessor() {
331
val density = LocalDensity.current
332
333
LaunchedEffect(Unit) {
334
val environment = getSystemResourceEnvironment()
335
val vectorBytes = getDrawableResourceBytes(environment, Res.drawable.vector_icon)
336
val processedVector = vectorBytes.decodeToImageVector(density)
337
338
// Further processing of the ImageVector
339
customVectorProcessor.process(processedVector)
340
}
341
}
342
343
suspend fun convertVectorResource(
344
resource: DrawableResource,
345
targetDensity: Density
346
): ImageVector {
347
val environment = getSystemResourceEnvironment()
348
val bytes = getDrawableResourceBytes(environment, resource)
349
return bytes.decodeToImageVector(targetDensity)
350
}
351
```
352
353
### Decoder Use Cases
354
355
**Custom Image Processing:**
356
```kotlin
357
suspend fun applyImageFilters(resource: DrawableResource): ImageBitmap {
358
val environment = getSystemResourceEnvironment()
359
val rawBytes = getDrawableResourceBytes(environment, resource)
360
val originalBitmap = rawBytes.decodeToImageBitmap()
361
362
return imageProcessor.applyFilters(originalBitmap)
363
}
364
```
365
366
**Dynamic Vector Manipulation:**
367
```kotlin
368
@Composable
369
fun DynamicVectorIcon(resource: DrawableResource, color: Color) {
370
val density = LocalDensity.current
371
var processedVector by remember { mutableStateOf<ImageVector?>(null) }
372
373
LaunchedEffect(resource, color) {
374
val environment = getSystemResourceEnvironment()
375
val bytes = getDrawableResourceBytes(environment, resource)
376
val vector = bytes.decodeToImageVector(density)
377
378
// Apply dynamic color changes
379
processedVector = vectorColorProcessor.changeColor(vector, color)
380
}
381
382
processedVector?.let { vector ->
383
Icon(imageVector = vector, contentDescription = null)
384
}
385
}
386
```