Skip to main content

osmimage

Render an OpenStreetMap tile image from a latitude, longitude and zoom level, and get a Pillow image back. Draw your own routes, markers or labels on top of it.

A route drawn on an OSM map with start/end markers

Install

pip install osmimage

Quick start

from osmimage import OSMImage

m = OSMImage(width=400, height=300)

# lat/lon/zoom -> PIL.Image (RGBA)
img = m.render(lat=37.5665, lon=126.9780, zoom=13)
img.save("seoul.png")

An OSM map centered on Seoul

Fitting many points

Give fit_zoom a list of (lat, lon) points and it returns the tightest zoom at which they all fit the canvas. Pair it with center_of to get the center to render around.

from osmimage import OSMImage

points = [(37.5665, 126.9780), (37.5700, 126.9820), (37.5740, 126.9790)]

m = OSMImage(400, 400)
zoom = m.fit_zoom(points)          # -> int, e.g. 15
lat, lon = m.center_of(points)     # -> (lat, lon) mid-point of the bounds
img = m.render(lat, lon, zoom)
img.save("area.png")

An area fitted to a set of points

Drawing a route and markers

draw_polyline and draw_marker draw straight onto the rendered map from geographic coordinates, anti-aliased. For anything custom, to_pixel() still converts a coordinate to a pixel position so you can use PIL.ImageDraw.

from osmimage import OSMImage

points = [
    (37.5758, 126.9768), (37.5769, 126.9770), (37.5780, 126.9773),
    (37.5790, 126.9778), (37.5799, 126.9786), (37.5805, 126.9797),
]

m = OSMImage(400, 400)
m.render(*m.center_of(points), m.fit_zoom(points))

m.draw_polyline(points, color="#3396FF", width=6)
m.draw_marker(*points[0],  radius=7, color="#2ECC71", outline="white", outline_width=2)
m.draw_marker(*points[-1], radius=7, color="#F23F5C", outline="white", outline_width=2)

m.image.save("route.png")

(That's the image at the top of this page.)

Caching and reliability

Pass cache_dir to reuse tiles across runs (recommended, and kinder to the tile server). Tile downloads are retried with backoff and fetched in parallel.

m = OSMImage(400, 400, cache_dir=".tile_cache", max_workers=8)

For full control, build a TileSource yourself:

from osmimage import OSMImage, TileSource

src = TileSource(
    "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
    cache_dir=".tile_cache",
    max_retries=3,
    backoff=0.5,
)
m = OSMImage(400, 400, tile_source=src)

API

OSMImage(width=300, height=300, *, tile_source=None, cache_dir=None, max_workers=8)

  • render(lat, lon, zoom) -> PIL.Image.Image — composite covering tiles onto a width x height canvas centered on the coordinate (tiles fetched in parallel). Returns an RGBA image.
  • draw_polyline(points, *, color="#3388FF", width=4, supersample=4) -> Image — anti-aliased line through (lat, lon) points on the last render.
  • draw_marker(lat, lon, *, radius=6, color="#F23F5C", outline=None, outline_width=0, supersample=4) -> Image — anti-aliased filled circle at a coordinate.
  • fit_zoom(points, *, padding=5, min_zoom=0, max_zoom=19) -> int — the tightest zoom (0-19) at which all (lat, lon) points fit the canvas.
  • center_of(points) -> (lat, lon) — mid-point of the bounds of points.
  • to_pixel(lat, lon) -> (x, y) — pixel position of a coordinate on the last rendered image. Call render() first.
  • image — the most recently rendered image (or None).

TileSource(url_template=..., *, tile_size=256, user_agent=..., timeout=10.0, session=None, cache_dir=None, max_retries=2, backoff=0.5)

Fetches tiles with an in-memory + optional on-disk cache, retry/backoff, and a parallel get_tiles(coords, max_workers=8) batch fetch. clear_cache() drops the in-memory cache (the on-disk cache is left intact).

Tile usage policy

The default tile server is the public OpenStreetMap one. Its use is subject to the OSM tile usage policy: send a descriptive User-Agent, avoid bulk downloading (use cache_dir), and for anything beyond light use, point at your own tile server.

Map data © OpenStreetMap contributors.

License

MIT

Release files for osmimage 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for osmimage 0.1.0
File Size Uploaded
osmimage-0.1.0.tar.gz 13.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for osmimage 0.1.0
File Interpreter ABI Platform
osmimage-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 26.9 kB

Release files / osmimage-0.1.0.tar.gz

Download URL osmimage-0.1.0.tar.gz
Size 13.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5f3606c81e27b9242d18813cb6831a0c10fa628aac276c21a376b7e67b8b1312
BLAKE2b-256 checksum
How to use checksums
7927004f6cb4bfae57bb65f0545eb918252c7ed93069d23d367a32db726bfe10
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / osmimage-0.1.0-py3-none-any.whl

Download URL osmimage-0.1.0-py3-none-any.whl
Size 12.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2a4b8a5cac89ce2852299437b48e75cbcaff2659a250ff38592885d7a9f43910
BLAKE2b-256 checksum
How to use checksums
f33ad3167db80582bd4dd579c86997fb9e051211583950a4f78b1b5c78f18210
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page