Skip to content

This API cuts out tiles from Cloud Optimized GeoTIFFs (COG) or other datasets using GDAL.

License

Notifications You must be signed in to change notification settings

codeforberlin/gdal-tiles-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GDAL-Tiles-API

This API cuts out tiles (e.g., for Leaflet) from Cloud Optimized GeoTIFFs (COG) or other datasets using GDAL. It is used on https://tiles.codefor.de.

It is meant to replace TileStache (which seems unmaintained), but only it's TileStache.Goodies.Providers.GDAL:Provider. A similar workflow could be implemented using TiTiler or Terracotta, but both tools have a different focus, and a lot of additional features.

The core functionality of the API is provided by a call to gdal.Warp (which is apearantly faster than gdal.ReprojectImage used by TileStache):

gdal.Warp(
        '',
        dataset_path,
        format='MEM',
        dstSRS="EPSG:4326",
        outputBounds=(west, south, east, north),
        width=width,
        height=height,
        resampleAlg='cubic'
    )

For optimal performance, the input dataset should be a valid COG or a VRT composed of COG. Such datasets can be created with GDAL, e.g.:

gdal_translate INPUT OUTPUT \
    -of COG -b 1 -b 2 -b 3 -a_srs EPSG:25833 \
    -co COMPRESS=JPEG -co QUALITY=75 -co BLOCKSIZE=512 \
    -co OVERVIEWS=IGNORE_EXISTING -co NUM_THREADS=4 \

Like TiTiler, GDAL-Tiles-API is build using FastAPI.

Setup

Instal GDAL, e.g. for Debian 12:

sudo apt-get install gdal-bin libgdal-dev

Install the matching GDAL python bindings (in a virtual environment):

pip install GDAL==3.6.2

Install the package

pip install gdal-tiles-api
pip install git+https://github.com/codeforberlin/gdal-tiles-api  # directly from GitHub

Usage

The API expects a config.toml in the current directory and/or a set of .toml files in a config.d directory (which are all merged into one config object).

The config file(s) look like this:

[tiles]
host = 'https://tiles.codefor.de'
path = "/data"

[[maps]]
name = "Digitale farbige TrueOrthophotos 2024 (DOP20RGBI)"
path = "berlin/geoportal/luftbilder/2024-dop20rgbi/tiles.vrt"
attribution.text = "Senatsverwaltung für Stadtentwicklung, Bauen und Wohnen Berlin / Digitale farbige Orthophotos 2024 (DOP20RGBI)"
attribution.href = "https://gdi.berlin.de/geonetwork/srv/ger/catalog.search#/metadata/aff8a8a5-2b48-44e8-949b-ea5f7d382a4f"

[[maps]]
path = "berlin/geoportal/luftbilder/2023-dop20rgbi"

[[maps]]
path = "berlin/geoportal/historische-karten/1750"
dataset = "cog/Berlin_1750_2.tif"

The actual path to the COG of the map build from the tiles path, the map path, and the dataset (which defaults to tiles.vrt). For the config above, we get:

/data/berlin/geoportal/luftbilder/2024-dop20rgbi/tiles.vrt
/data/berlin/geoportal/luftbilder/2023-dop20rgbi/tiles.vrt
/data/berlin/geoportal/historische-karten/1750/cog/Berlin_1750_2.tif

The other entries are only displayed in the root url.

Development server

The local developtment server can be started using:

fastapi dev gdal_tiles_api/main.py

The API is then available at http://localhost:8000.

Production deployment

In production, gunicorn with the uvicorn should be used. In order to run with Systemd, the a service similar to the following should be placed in /etc/systemd/system/tiles.service:

[Unit]
Description=GDAL-Tiles-API gunicorn daemon
After=network.target

[Service]
User=tiles
Group=tiles

WorkingDirectory=/srv/tiles/tiles-config

LogsDirectory=gunicorn
RuntimeDirectory=gunicorn

Environment="PATH=/srv/tiles/tiles-config/env/"
Environment="PYTHONUNBUFFERED=1"

ExecStart=gunicorn
    --workers 4 \
    --worker-class uvicorn.workers.UvicornWorker \
    --timeout 5 \
    --bind unix:/run/gunicorn/tiles.sock \
    --pid /run/gunicorn/tiles.pid \
    --access-logfile /var/log/gunicorn/access.log \
    --error-logfile /var/log/gunicorn/error.log \
    gdal_tiles_api.main:app

ExecReload=/bin/sh -c '/usr/bin/pkill -HUP -F ${GUNICORN_PID_FILE}'

ExecStop=/bin/sh -c '/usr/bin/pkill -TERM -F ${GUNICORN_PID_FILE}'

Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

The gunicorn should be reverse proxied using NGINX, with the create tiles cached by the build in Content Caching. The following configuration can be used for this (in /etc/nginx/sites-enabled/default):

proxy_cache_path /tmp/nginx_cache keys_zone=tiles:10m max_size=10g use_temp_path=off;

proxy_connect_timeout 5;
proxy_send_timeout 5;
proxy_read_timeout 5;
send_timeout 5;

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;
    index index.html;

    server_name _;

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_pass http://unix:/run/gunicorn/tiles.sock;

        proxy_cache tiles;
        proxy_cache_valid 200 302 404 7d;
        proxy_cache_use_stale error timeout updating;
        add_header X-Cache-Status $upstream_cache_status;
    }
}

About

This API cuts out tiles from Cloud Optimized GeoTIFFs (COG) or other datasets using GDAL.

Resources

License

Stars

Watchers

Forks

Languages