Add images and icons
A SymbolLayer draws an icon at each feature in its source. The
image expression supplies the icon, from a Compose painter, an
ImageBitmap, or the base style’s sprite.
Draw icons from a Compose painter
Section titled “Draw icons from a Compose painter”Pass a painter to image(). Use painterResource to load an app resource, or
supply your own painter:
val state = rememberMapState { val stations = rememberGeoJsonSource(GeoJsonData.Uri(Res.getUri("files/data/amtrak_stations.geojson")))
SymbolLayer( id = "station-icons", source = stations, iconImage = image(painterResource(Res.drawable.map_24px), size = DpSize(24.dp, 24.dp)), )}MaplibreMap(state = state)Draw icons from the style sprite
Section titled “Draw icons from the style sprite”Base styles usually bundle a sprite: a named set of icons. Pass the icon name
to image():
val state = rememberMapState { SymbolLayer(id = "station-markers", source = stations, iconImage = image("marker"))}MaplibreMap(state = state)Place an image on the map
Section titled “Place an image on the map”An ImageSource positions one image on the map by its four corner
coordinates. A RasterLayer draws it:
val state = rememberMapState { val corners = PositionQuad( topLeft = Position(longitude = -74.0178, latitude = 40.7040), topRight = Position(longitude = -74.0118, latitude = 40.7100), bottomRight = Position(longitude = -74.0060, latitude = 40.7067), bottomLeft = Position(longitude = -74.0120, latitude = 40.7006), ) val plan = rememberImageSource(position = corners, uri = Res.getUri("files/castello-plan.jpg")) RasterLayer(id = "castello-plan", source = plan, opacity = const(0.8f))}MaplibreMap(state = state)Supply a missing image
Section titled “Supply a missing image”A style can reference an icon that its sprite does not contain. Set
MapState.missingImageResolver to supply one. The map calls the
resolver with the icon’s ID and adds the ResolvedStyleImage that
it returns:
val mapState = rememberMapState()val density = LocalDensity.currentval layoutDirection = LocalLayoutDirection.currentDisposableEffect(mapState, fallback, density, layoutDirection) { mapState.missingImageResolver = { ResolvedStyleImage.fromPainter(fallback, density, layoutDirection) } onDispose { mapState.missingImageResolver = null }}MaplibreMap(state = mapState)Prepared images
Section titled “Prepared images”For imperative image updates, prepare an image with
ResolvedStyleImage.fromBitmap(bitmap) or
ResolvedStyleImage.fromPainter, then submit it with
state.style.images.set(id, image). Preparation owns a pixel copy,
so the result can be reused across image IDs and loaded styles.
set, setAll, and remove enqueue commands without waiting for the map. A
replacement keeps the previous image until it succeeds; an engine rejection is
logged. Looking up an image with state.style.images[id] suspends until the
commands enqueued before it have run, so code that needs an image in place
awaits its lookup. A finished command does not mean the map has rendered a
frame.