Read-only mirror of https://github.com/swisstopo/mbtiles2vtpk — Bundesamt für Landestopografie. Issues & pull requests at the source.
  • Python 99.7%
  • Dockerfile 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-06-24 23:10:19 +02:00
mbtiles2vtpk Prevent cache hit for 'styles' category 2026-06-18 07:40:07 +02:00
.gitignore Fixed CLI params - Remove committed pyc files and update .gitignore 2026-04-17 07:56:11 +02:00
.gitmodules added style resolution. 2026-04-17 00:00:44 +02:00
Dockerfile added Dockerfile 2026-06-24 23:07:31 +02:00
pyproject.toml removed rowid constraint 2026-06-13 17:41:21 +02:00
README.md added Dockerfile 2026-06-24 23:07:31 +02:00

mbtiles2vtpk

Repack MBTiles vector tile packages to the ESRI VTPK format. Tested with ArcGIS Pro and QGIS. When using --style option, repacks also fonts, glyphs and sprites. Some V8 styles may not be supported by Pro or ESRI VT Editor.

Installation

# 1. Clone
git clone https://github.com/swisstopo/mbtiles2vtpk.git
cd mbtiles2vtpk

# Init submodules:
git submodule update --init --recursive

The mbtiles2vtpk command is then available in the terminal.


Usage

Basic conversion

mbtiles2vtpk -i input.mbtiles -o output.vtpk

or as a script

mbtiles2vtpk\__main__,py -i input.mbtiles -o output.vtpk

With a custom Mapbox GL style

Provide a URL or a local path to a Mapbox GL style JSON. Fonts (PBF glyphs) and sprites are downloaded automatically and cached locally so subsequent conversions are instant. The pipeline stops immediately if any required resource cannot be downloaded.

# From a public URL
mbtiles2vtpk -i input.mbtiles -o output.vtpk \
  --style https://raw.githubusercontent.com/mapbox/mapbox-gl-styles/master/styles/basic-v8.json

# From a local file
mbtiles2vtpk -i input.mbtiles -o output.vtpk --style ./style/dark_minimal.json

# With a custom working directory
mbtiles2vtpk -i input.mbtiles -o output.vtpk --style ./my-style.json --work-dir C:\Temp\work

All options

mbtiles2vtpk -i INPUT -o OUTPUT [--style URL_OR_PATH] [--work-dir DIR]
mbtiles2vtpk --cache-info
mbtiles2vtpk --clear-cache

conversion:
  -i, --input   PATH        Source .mbtiles file
  -o, --output  PATH        Output .vtpk file
  --style       URL_OR_PATH Mapbox GL style to embed (URL or local path)
  --work-dir    DIR         Intermediate working directory (default: auto temp)

cache:
  --cache-info              Show cache location and size, then exit
  --clear-cache             Delete all cached resources, then exit

PyCharm / no install

Run > Edit Configurations
  → Module name : mbtiles2vtpk.cli
  → Parameters  : -i input.mbtiles -o output.vtpk [--style ...]
  → Working dir : <repo root>

Docker

# Build the image
docker build -t mbtiles2vtpk .

# Basic conversion (mount a local directory)
docker run --rm -v /path/to/data:/data mbtiles2vtpk -i /data/input.mbtiles -o /data/output.vtpk

# With a style URL
docker run --rm -v /path/to/data:/data mbtiles2vtpk -i /data/input.mbtiles -o /data/output.vtpk --style https://raw.githubusercontent.com/mapbox/mapbox-gl-styles/master/styles/basic-v8.json

# With MapTiler credentials
docker run --rm -v /path/to/data:/data -e MAPTILER_KEY=your_key_here -e MAPTILER_ORIGIN=https://your-app.example.com mbtiles2vtpk -i /data/input.mbtiles -o /data/output.vtpk --style https://api.maptiler.com/...

Resource cache

Downloaded fonts and sprites are cached in:

~/.mbtiles2vtpk/cache/
    styles/     ← style JSON files
    fonts/      ← PBF glyph files  (256 ranges × N fonts)
    sprites/    ← sprite.json / sprite.png / @2x variants

The cache key is the SHA-256 of the resource URL without the query string, so changing API keys does not invalidate existing entries.

mbtiles2vtpk --cache-info    # show size
mbtiles2vtpk --clear-cache   # wipe everything

MapTiler API credentials

When the style, fonts, or sprites are served from api.maptiler.com, set these environment variables before running:

Variable Purpose
MAPTILER_KEY API key — appended to every request as ?key=<value>
MAPTILER_ORIGIN Allowed origin — sent as the Origin: HTTP header

If either variable is missing and the URL targets api.maptiler.com, the conversion stops with a clear error message.

Windows (PowerShell)

$env:MAPTILER_KEY    = "your_key_here"
$env:MAPTILER_ORIGIN = "https://your-app.example.com"
mbtiles2vtpk -i input.mbtiles -o output.vtpk --style https://api.maptiler.com/...

Windows (CMD)

set MAPTILER_KEY=your_key_here
set MAPTILER_ORIGIN=https://your-app.example.com
mbtiles2vtpk -i input.mbtiles -o output.vtpk --style https://api.maptiler.com/...

Linux / macOS

export MAPTILER_KEY=your_key_here
export MAPTILER_ORIGIN=https://your-app.example.com
mbtiles2vtpk -i input.mbtiles -o output.vtpk --style https://api.maptiler.com/...

The credentials are injected at fetch time and never stored in the cache.


External dependency

Tile bundle creation is delegated to ltbam/python-mbtiles2compactcache, included as a git submodule under mbtiles2vtpk/vendor/.

# Populate after cloning
git submodule update --init --recursive

Conversion pipeline

# Class Description
1 StructureCreator Create VTPK folder skeleton
2 TileExtractor Extract tiles → Compact Cache V2 bundles (via submodule)
3 TilemapEditor Build presence quadtree → p12/tilemap/root.json
4 StyleCopier Embed Mapbox GL style + download fonts & sprites
5 RootJsonCreator Write p12/root.json, metadata.json, esriinfo/
6 TileSizeEditor Patch tile size to 512 × 512
7 LodsEditor Verify LODs match extracted zoom levels
8 FontResolver Write p12/resources/info/root.json resource index
9 Repacker ZIP everything into a .vtpk archive (ZIP_STORED)

Output VTPK structure

output.vtpk  (ZIP, no compression)
├── esriinfo/
│   ├── item.pkinfo
│   └── iteminfo.xml
└── p12/
    ├── root.json
    ├── metadata.json
    ├── tile/
    │   ├── L00/R0000C0000.bundle
    │   └── ...
    ├── tilemap/
    │   └── root.json
    └── resources/
        ├── styles/root.json
        ├── fonts/<FontName>/<range>.pbf
        ├── sprites/sprite.json|png|@2x.*
        └── info/root.json