Leaflet-Karten mit gdal2tiles und QGis erstellen
Gepostet am 03. Mai 2023 • 6 Minuten • 1196 Wörter
Für spezielle Karten und Overlays habe ich jahrelang MapTiler verwendet. Ich war auch ganz zufrieden damit, bis die Firma im letzten Jahr ihre Lizenzbedingungen geändert hat und nun statt 15 USD im Jahr satte 25 USD im Monat will. Da habe ich mich nach einer Open Source-Alternative umgesehen und diese stelle ich kurz vor.
Warum eigene Karten erstellen?
Ich habe immer wieder Mal den Fall, dass ich gerne eigene Karten wie OpenStreetMap oder Google Maps erstellen will. Ich denke, das geht nicht nur mir so. Beispiele für eigene Karten sind:
- Raumpläne für Veranstaltungen, Firmen, u.ä. - eigenes Beispiel: Gamesvention Raumpläne
- Historische Karten (z.B. von Tabulae Geographicae )
- Karten für Rollenspiele (Fantasy-Karten)
Grundlage aller genannter Use Cases ist, dass man Karten als großes Bild vorliegen hat (oder als PDF). Für das Web ist es jedoch besser, diese großen Bilder in viele kleine zu zerstückeln und mittels eines Tile Servers bzw. Kartenservers zur Verfügung zu stellen. Das spart Bandbreite und ermöglicht ein schöneres Zoom-Erlebnis. Außerdem kann es bei großen Karten vorkommen, dass Browser an ihre Grenzen kommen (habe ich tatsächlich schon erlebt).
Die Herausforderung - Bild zerteilen
Ich gehe davon aus, dass wir ein großes Bild vorliegen haben. Groß in diesem Fall ist mehr als 1000 Pixel Höhe und Breite, vermutlich eher mehrere tausend Pixel. Hat man ein PDF als Ausgangsformat muss man dieses zunächst in ein Bild konvertieren. Dazu gibt es eine Menge guter Hinweise im Internet (z.B. Gimp, ImageMagick/GraphicsMagick, Master PDF Editor, diverse Online-Tools, usw.), ich gehe hier nicht weiter darauf ein. Das Endformat ist relativ egal, sinnvoll ist hier JPG oder PNG.
Kartenserver wie OpenStreetMap oder Google Maps funktionieren folgendermaßen: Man startet mit einer bestimmten Zoom-Stufe - der Kachselserver hat für diese Stufe das große Bild (oder eben eine Weltkarte) in viele kleine Kacheln zerteilt, die in der Regel 256 oder 512 Pixel pro Seite groß sind. Zoomt man weiter in die Karte hinein, werden Kacheln einer anderen Zoom-Stufe aufgerufen, die mehr Details zeigen. Umgekehrt werden bei einer größeren Ansicht Kacheln gezeigt, die weniger Details zeigen. Das bedeutet auch, dass in der größten Zoom-Stufe ziemlich viele Kacheln vorliegen müssen (zumindest bei einer Weltkarte).
Das Erstellen von Kacheln aus einem Bild ist weniger einfach als gedacht - die meisten Anleitungen im Internet gehen davon aus, dass man Bilder oder Overlays auf eine Weltkarte projizieren will. Das ist auch cool, aber in diesem Artikel will ich ein Bild als Karte verwenden.
Als Beispiel habe ich mir eine Karte über Azgaar’s Fantasy Map Generator generieren lassen. Diese ist 15992x8472 Pixel groß und damit ein gutes Beispiel. Die Karte kann hier angezeigt/heruntergeladen werden .
Möglichkeit 1: gdal2tiles.py
Zum Zerteilen gibt es mehrere Möglichkeiten. Die meisten arbeiten im Hintergrund mit gdal , einer Programmbibliothek für Kartentransformation und -bearbeitung. Das Python-Programm gdal2tiles.py ist ein Kommandozeilen-Programm, das diese Bibliothek benutzt. Es gibt dummerweise eine ganze Reihe von Varianten und Versionen, was die Benutzung etwas verwirrend macht, da die Programmparameter in einer Version nicht zwingend jene sein müssen, die in der anderen Version funktionieren.
Ich verwende die Version von der GitHub-Seite https://github.com/commenthol/gdal2tiles-leaflet - diese ist gut mit Leaflet zu verwenden, auf das ich weiter unten eingehen werde.
Man kann die Quelldateien via GitHub herunterladen oder mithilfe von
git clone https://github.com/commenthol/gdal2tiles-leaflet
, sofern man git installiert hat. Python 3 sollte ebenfalls
auf dem System installiert sein. Nun muss man die gdal-Bibliothek installieren, was auf Debian-basierten System mittels
sudo apt install python3-gdal
funktioniert.
Nun wechselt man in das entsprechende Verzeichnis, lädt die Beispieldatei herunter und konvertiert sie in Kacheln. Hier das gesamte Beispiel:
# gdal mit python bindings installieren
sudo apt install python3-gdal
# Projekt klonen
git clone https://github.com/commenthol/gdal2tiles-leaflet
cd gdal2tiles-leaflet
# Karte herunterladen
wget https://www.auxnet.de/downloads/example-map.jpg
# Karte konvertieren
python3 gdal2tiles.py -l -p raster -w none example-map.jpg example-map
Anmerkung: Hat man eine PNG-Karte als Ausgangsbasis muss diese in 8 Bit konvertiert werden! Das einfachste ist es, die Karte in Gimp zu laden und als PNG (8-Bit Farbtiefe) wieder zu exportieren.
Im Verzeichnis example-map
liegen die Tiles. Diese wollen wir nun anzeigen (mit Leaflet
).
Dazu erstellen wir folgende HTML-Datei (index.html
) im aktuellen gdal2tiles-leaflet
-Verzeichnis:
<html lang="de">
<head>
<title>Testkarte</title>
<meta charset="utf-8">
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"
integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
crossorigin=""
/>
<script
src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
crossorigin=""
></script>
</head>
<body style="margin: 0; padding: 0">
<div id="map" style="height: 100vh; width: 100vw"></div>
<script>
const map = L.map("map", {
crs: L.CRS.Simple,
minZoom: 0,
maxZoom: 6,
}).setView([-50, 100], 4);
L.tileLayer("/example-map/{z}/{x}/{y}.jpg", {
tileSize: 256,
crs: L.CRS.Simple,
}).addTo(map);
</script>
</body>
</html>
Wichtig ist hier:
- Bei eigenen Karten kann
example-map
natürlich einen anderen Verzeichnis-Namen bekommen. - Zoomstufen sollten mit der Anzahl der Verzeichnisse sein - gdal2tiles erstellt eine sinnvolle Anzahl von Zoom-Stufen.
- Die Kartenprojektion muss CRS.Simple sein!
setView([-50, 100], 4)
legt die anfänglichen Koordinaten und Zoom-Stufe fest. Hier kann man ein wenig experimentieren.
Die Karte lässt sich mithilfe eines Webservers anzeigen. Ein einfacher Server, den ich für ein anderes Projekt geschrieben habe, ist Go Fyne Webserver . Diesen kann man für seine Plattform (Linux, Windows, MacOS) herunterladen und einfach starten (auf unixoiden Systemen muss man die Datei noch als ausführbar definieren). Vor dem Start kann man das korrekte Verzeichnis wählen und den Server starten:
Die Karte sollte dann unter localhost:8080
oder einem ähnlichen Port aufrufbar sein (einfach auf die Adresse im
Fenster klicken).
Möglichkeit 2: QGis
Auch QGis ist in der Lage, Leaflet-basierte Karten zu erstellen. Das Vorgehen ist eigentlich relativ einfach, wenn man verstanden hat, wo die Fallstricke liegen. Knackpunkt ist hier das Koordinatensystem bzw. die Projektion.
Nachdem man QGis geöffnet hat, installieren wir zunächst den “Freehand raster georeferencer”. Das funktioniert über “Erweiterungen”⇒“Erweiterungen verwalten und installieren…” und die Suche nach dem georeferencer im Feld. Nach der Installation steht uns dann im Menü “Raster” diese Erweiterung zur Verfügung.
Auf einer neuen Karte erstellt man zunächst das OpenStreetMap Layer. Damit weiß man schon mal, wo die Welt ist:
Jetzt öffnen wir das Menü “Raster”⇒“Freehand Raster Georeferencer”⇒“Add raster for interactive georeferencing”. In der Dateiauswahl suchen wir nun unser Bild. “Add new” fügt das Bild hinzu:
Nun der eigentliche Trick: Wir müssen das Bild auf die Weltkarte projizieren. Dazu wählen wir “Scale” im Werkzeugmenü des Referenzers aus (gelbes Feld “SC”). Jetzt kann man das Bild, während man STRG und die linke Maustaste gedrückt hält, durch Verschieben der Maus vergrößern oder verkleinern. Wir wollen das Bild möglichst so groß haben wie die Weltkarte:
Damit ist das Bild von den Koordinaten her korrekt ausgerichtet. Die OSM-Karte blenden wir aus, die Transparenz des Bildes setzen wir auf 0 (Layer links unten, Rechtsklick “Eigenschaften…”).
Mit dem Menüpunkt “Verarbeitung”⇒“Werkzeugkiste” öffnen wir rechts die Werkzeugkiste und suchen nach “XYZ”. Der Punkt “XYZ-Kacheln erzeugen (Verzeichnis)” ist das, was wir wollen.
In dem Dialog wählen wir “Extent”⇒“Aus Layer berechnen”⇒unser Bildlayer. Minimum und Maximum Zoom sollte ähnlich wie mit gdal oben sein - in unserem Fall 0 bzw. 6. Unten ist es sinnvoll, ein Ausgabeverzeichnis und eine Ausgabedatei (Leaflet) zu wählen. Wenn man nun “Start” drückt, sollte die Karte korrekt erstellt werden. Diese ist auch Offline aufrufbar (ohne Server wie oben). Will man sie im Internet veröffentlichen, muss man allerdings noch etwas Hand anlegen.
Fazit
Welche der beiden Methoden man verwendet, ist offen. Die erste Methode erfordert etwas technisches Verständnis, ist jedoch durch das Skripting einfach umsetzbar. Die zweite ist interaktiver, durch die Anpassung des Bildes an das Koordinatensystem ist die Umsetzung etwas fummeliger.