PMTiles
The PmTilesReader and PmTilesWriter classes provide PMTiles v3 archive support for both vector and raster tiles.
The implementation targets netstandard2.1 and is compatible with serverless (range-based) hosting scenarios.
Supported capabilities
| Capability | Supported |
|---|---|
| Read | Yes — PmTilesReader (GetTileAsync, GetTileByIdAsync, GetMetadataJsonAsync) |
| Write | Yes — PmTilesWriter (AddTile, WriteAsync, BuildAsync) |
| Gzip / Brotli compression | Yes |
| Zstandard compression | No — throws NotSupportedException |
| Leaf directories | Read only — the writer emits a single root directory |
Features
- Parse and emit the 127-byte PMTiles header (
PmTilesHeader). - Decode/encode directory entries with run-length support (
PmTilesDirectory). - Read from any random-access byte source via
IPmTilesStreamSource(local files, HTTP range requests, ...). - Build archives from a set of tiles with optional automatic Gzip/Brotli compression.
- Store and retrieve TileJSON metadata (compressed via the archive's internal compression).
- Automatic Hilbert curve conversions between
(z, x, y)and PMTiles tile identifiers (PmTilesHilbert).
Usage
// Write
var writer = new PmTilesWriter();
writer.AddTile(0, 0, 0, tileBytes);
await using var stream = File.Create("sample.pmtiles");
await writer.WriteAsync(stream, new PmTilesWriterOptions
{
TileType = PmTilesTileType.VectorMvt,
InternalCompression = PmTilesCompression.Gzip,
TileCompression = PmTilesCompression.Gzip,
MetadataJson = "{\"name\":\"sample\"}",
});
// Read — supply an IPmTilesStreamSource over your storage
await using var reader = new PmTilesReader(source);
await reader.InitializeAsync();
var tile = await reader.GetTileAsync(0, 0, 0);
string? metadata = reader.MetadataJson;
Limitations
- Zstandard compression is not implemented;
PmTilesCompression.ZstandardthrowsNotSupportedException. - The writer stores every entry in the root directory and never generates leaf directories (the header's leaf-directory section is written empty). The reader, however, can follow leaf directories in archives produced by other tools.
- The writer stores tiles sequentially without deduplication (every entry has run length 1).
- No
IPmTilesStreamSourceimplementation ships with the library — implement it over your storage (see the test suite's in-memory source for an example). TheIPmTilesRangeReadertypes (FilePmTilesRangeReader,InMemoryPmTilesRangeReader) are not consumed byPmTilesReader.