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 a MissingImageRequest that holds 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.