Open Boat Projects (C) 2026 Norbert Walter, MIT
The Map Converter is a server service for converting nautical charts into various resolutions and image formats. This allows for the creation of relatively simple navigation devices based on a microcontroller with various display types. Both color and black-and-white displays are supported.
The microcontroller sends an HTTP GET request to the server, specifying the geocoordinates, direction of travel, image size, and image type. The server then transmits the finished rendered image to the microcontroller. The server queries various map services and combines the individual tiles and navigation mark layers into an image, rotates the image in the desired direction, and outputs it in the desired size and color. The image is output as a PNG image or as a black-and-white binary image in JSON. The microcontroller then only needs to display the received image on the display and is freed from all image processing functions.
The server acts as a map proxy with file and RAM cache to improve performance and can be accessed via various URLs:
This page is the landing page and show the version number.
zoom: Zoom level 1...17
lat: Latitude
lon: Latitude
mtype: Map type 1...9
1 Open Street Map
2 Google Hybrid
3 Google Street
4 Google Terrain Street Hybrid
5 Open Topo Map
6 Esri Base Map
7 Stadimaps Toner SW
8 Stadimaps Terrain
9 Free Nautical Charts (limited to German coastal waters)
mrot: Map rotation in degrees 0...360°, +/- 360°
itype: Image types 1...4
1 Color
2 Grayscale 256-bit
3 Grayscale 4-bit
4 Black and white image 1-bit, dithered
dtype: Dithering types 1...4 for black and white images
1 Threshold dithering
2 Flow Steinberg dithering
3 Ordered dithering
4 Atkinson dithering
width: Image width in pixels
height: Image height in pixels
cutout: Image cutouts
0 No cutout
1 Elliptical cutout
2 Square cutout left
3 Square cutout right
4 Square cutout top
5 Square cutout bottom
6 Square cutout left + right
7 Square cutout top + bottom
8 Circle cutout (only for 1bit pbm format
tab: Tab width in pixels (only for square cutouts)
border: Border width in pixel 0...6
alpha: Transparency value for cutouts 0...100%
symbol: Symbol for center marking
0 No symbol
1 Cross
2 Triangle
srot: Symbol rotation 0...360°
ssize: Symbol size in pixels 0...100
grid: Show tile grid overlay
0 off
1 on
debug: Additional information 0/1, tile cut, and georeference
1 Debug on
2 Debug ogff
All parameters are identical to the previous section, plus the new parameter oformat.
oformat: Output format 1...4The image data is returned in Base64 as a binary byte stream. Pixel data is serialized row by row from left to right and top to bottom, with the origin at the upper-left corner. The nautical chart can be decorated as an image and copied into the display framebuffer. The output is compatible with common microcontroller display pipelines (including ESP32-S3 use cases) and with the Adafruit GFX library. Sample code for OBP60 and OBP40 can be found here:https://github.com/norbert-walter/obp60-navigation-map
For the smallest data footprint, 1-bit black-and-white PBM format is available. The alpha and itype parameters are not required for this format.
http://ip-address:8080/dashboard
Displays a dashboard with information about server utilization:
http://ip-address:8080/map_service
The map service displays a web page that allows for simple navigation. The map center is your current location. Various NMEA 0183 sources can be transmitted and displayed to transmit geocoordinates and some boat information. This can be used for navigation on mobile phones and laptops with a built-in GPS receiver. The device’s own GPS receiver takes priority. The settings for the WebSocket connection are stored in a cookie.
http://ip-address:8080/map_service?ip=127.0.0.1&port=3000&start=1
The website functions the same as before, with the difference that you can pass parameters for the websocket. The values passed for the websocket connection are passed as default parameters and stored in a cookie for later calls. The start parameter can be used to specify whether the connection should be started immediately when the website is accessed (start=1).
http://ip-address:8080/map_help
This page is a online help for the Map Service.
The Docker container is listed in the public repository on Docker Hub. It can be found at:
openboatprojects/maps_converter
The container contains a main directory for the application software and two additional external persistent drives are mounted for log files and the cache map directory.
/app - Application folder
/app/logs - Log foulder
/app/tile_cache - Cache folder for maps
The dashboard accesses the log file and displays the values in charts. The log file is designed as a rotating file that cannot exceed a specified size. The cache map directory is organized and stored as MB Tiles. It can also be used for an MB Tiles server. Depending on the use of different geographical regions, the Map Converter's cache map directory grows over time. A distinction is made between the respective map sources, which are stored in separate subfolders.
/app/tile_cache/1 - Open Street Map Cache
/app/tile_cache/2 - Google Hybrid Cache
...
etc.
Currently accessed map areas are stored in a RAM cache for subsequent access. The RAM cache size is 512 MB. This allows approximately 10,000 tiles to be stored in the RAM cache and allows approximately 50 devices to be served simultaneously. Older saved map areas are automatically deleted when the cache is full.
# Base-Image with PythonFROM python:3.11-slim
# Create folderWORKDIR /app
# Install sytem requirements (for Pillow and other)RUN apt-get update && apt-get install -y --no-install-recommends \build-essential \libjpeg-dev \zlib1g-dev \libfreetype6-dev \liblcms2-dev \libwebp-dev \libopenjp2-7 \libtiff-dev \libxml2-dev \libxslt1-dev \libharfbuzz-dev \libfribidi-dev \libxcb1 \&& rm -rf /var/lib/apt/lists/*
# Create directorysRUN mkdir /app/logsRUN mkdir /app/staticRUN mkdir /app/tile_cache
# Copy and install requirements.txtCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt
# Copy project dataCOPY Maps_Converter_V1_21.py .COPY monitor.py .COPY map_logic_7.js . /app/static
# Set portEXPOSE 8080
# Run serverCMD ["sh", "-c", "gunicorn -w ${WORKERS:-4} --threads ${THREADS:-4} --timeout ${TIMEOUT:-60} -b 0.0.0.0:8080 Maps_Converter_V1_21:app"]
flask==2.3.3
flask-compress==1.13
diskcache==5.6.1
numpy==1.26.4
requests==2.31.0
Pillow==10.2.0
psutil==5.9.8
#!/bin/bashset -e
echo "Crate Docker Image..."docker build -t maps-converter-monitored .
echo "Delete old docker container (when necessary)..."docker rm -f maps-server 2>/dev/null || true
echo "Start Docker Container..."docker run -d \--name maps-server \-p 8080:8080 \-v "$(pwd)/tile_cache:/app/tile_cache" \-v "$(pwd)/logs:/app/logs" \--restart unless-stopped \maps-converter-monitored
echo "Server runs on: http://localhost:8080"