ExPmtiles (ExPmtiles v0.1.2)
View SourceA module for working with PMTiles files.
PMTiles is a single-file format for storing tiled map data. This module provides functionality to read and access tiles from PMTiles files stored either locally or on S3.
Features
- Read PMTiles files from local storage or S3
- Access tiles by zoom level and coordinates (z/x/y)
- Automatic directory caching and decompression
- Support for various compression types (gzip, none)
- Tile ID calculations and conversions
Usage
# Open a local PMTiles file
instance = ExPmtiles.new("path/to/file.pmtiles", :local)
# Open a PMTiles file from S3
instance = ExPmtiles.new("region", "my-bucket", "path/to/file.pmtiles", :s3)
# Get a tile by coordinates
case ExPmtiles.get_zxy(instance, 10, 512, 256) do
{{offset, length, data}, updated_instance} ->
# Use the tile data
data
{nil, updated_instance} ->
# Tile not found
nil
end
# Convert coordinates to tile ID
tile_id = ExPmtiles.zxy_to_tile_id(10, 512, 256)
# Convert tile ID back to coordinates
{z, x, y} = ExPmtiles.tile_id_to_zxy(tile_id)
Compression Support
The module supports the following compression types:
:none
- No compression:gzip
- Gzip compression:unknown
- Unknown compression type
Note: Brotli and Zstd compression are not currently supported.
Tile Types
Supported tile types include:
:mvt
- Mapbox Vector Tiles:png
- PNG images:jpg
- JPEG images:webp
- WebP images:avif
- AVIF images:unknown
- Unknown tile type
Summary
Functions
Decompresses data based on the specified compression type.
Deserializes a PMTiles directory from binary data.
Finds a tile entry in a directory by tile ID.
Retrieves bytes from the PMTiles file using the configured storage backend.
Gets raw tile data from the PMTiles file at the specified offset and length.
Gets a tile by its zoom level and coordinates.
Creates a new PMTiles instance for a locally-stored file.
Creates a new PMTiles instance for an S3-stored file.
Parses the PMTiles file header from binary data.
Reads a variable-length integer from binary data.
Converts a PMTiles tile ID back to zoom level and coordinates.
Converts zoom level and coordinates to a PMTiles tile ID.
Functions
Decompresses data based on the specified compression type.
Parameters
data
- The compressed binary datacompression_type
- The compression type (:gzip
,:none
, etc.)
Returns
binary()
- The decompressed data
Raises
- Error for unsupported compression types (brotli, zstd)
Examples
iex> ExPmtiles.decompress(compressed_data, :gzip)
<<...>>
iex> ExPmtiles.decompress(data, :none)
data
Deserializes a PMTiles directory from binary data.
PMTiles directories contain entries with tile IDs, offsets, lengths, and run lengths. This function parses the binary format into a list of directory entries.
Parameters
buf
- Binary data containing the directory
Returns
list()
- List of directory entries with keys::tile_id
,:offset
,:length
,:run_length
Examples
iex> ExPmtiles.deserialize_directory(<<...>>)
[
%{tile_id: 0, offset: 0, length: 1024, run_length: 1},
%{tile_id: 1, offset: 1024, length: 512, run_length: 0}
]
Finds a tile entry in a directory by tile ID.
Uses binary search to efficiently locate the tile entry. Handles run-length encoding where multiple consecutive tiles may share the same entry.
Parameters
entries
- List of directory entriestile_id
- The tile ID to search for
Returns
map()
- The matching directory entrynil
- If no matching entry is found
Examples
iex> ExPmtiles.find_tile(entries, 1024)
%{tile_id: 1024, offset: 2048, length: 512, run_length: 1}
Retrieves bytes from the PMTiles file using the configured storage backend.
Parameters
instance
- The PMTiles instanceoffset
- Byte offset in the filelength
- Number of bytes to read
Returns
binary()
- The requested bytesnil
- If the bytes cannot be read
Examples
iex> ExPmtiles.get_bytes(instance, 0, 1024)
<<...>>
Gets raw tile data from the PMTiles file at the specified offset and length.
Parameters
instance
- The PMTiles instanceoffset
- Byte offset in the filelength
- Number of bytes to read
Returns
binary()
- The raw tile datanil
- If the data cannot be read
Examples
iex> ExPmtiles.get_tile(instance, 1024, 512)
<<...>>
Gets a tile by its zoom level and coordinates.
This function converts the z/x/y coordinates to a tile ID and searches for the tile in the PMTiles directory structure. It handles both leaf and internal directories automatically.
Parameters
instance
- The PMTiles instancez
- Zoom level (integer)x
- X coordinate (integer)y
- Y coordinate (integer)
Returns
{{offset, length, data}, updated_instance}
- Tuple containing tile information and updated instance{nil, updated_instance}
- If tile is not found or outside zoom bounds
Examples
iex> ExPmtiles.get_zxy(instance, 10, 512, 256)
{{1024, 512, <<...>>}, updated_instance}
iex> ExPmtiles.get_zxy(instance, 25, 0, 0)
{nil, instance} # Zoom level out of bounds
Creates a new PMTiles instance for a locally-stored file.
Parameters
path
- The local file path to the PMTiles file:local
- Source type identifier
Returns
%ExPmtiles{}
- A configured PMTiles instance with parsed headernil
- If the file cannot be accessed or is invalid
Examples
iex> ExPmtiles.new("data/world.pmtiles", :local)
%ExPmtiles{bucket: nil, path: "data/world.pmtiles", source: :local, header: %{...}}
Creates a new PMTiles instance for an S3-stored file.
Parameters
bucket
- The S3 bucket namepath
- The path to the PMTiles file within the bucket:s3
- Source type identifier
Returns
%ExPmtiles{}
- A configured PMTiles instance with parsed headernil
- If the file cannot be accessed or is invalid
Examples
iex> ExPmtiles.new("my-bucket", "maps/world.pmtiles", :s3)
%ExPmtiles{bucket: "my-bucket", path: "maps/world.pmtiles", source: :s3, header: %{...}}
Parses the PMTiles file header from binary data.
The PMTiles header contains metadata about the file including offsets, compression settings, zoom levels, and geographic bounds.
Parameters
binary
- Binary data containing the PMTiles header (first 16,384 bytes)
Returns
map()
- Header information with keys::magic_number
- File magic number ("PMTiles"):spec_version
- PMTiles specification version:root_offset
,:root_length
- Root directory location:metadata_offset
,:metadata_length
- Metadata location:leaf_dir_offset
,:leaf_dir_length
- Leaf directories location:tile_data_offset
,:tile_data_length
- Tile data location:num_addr_tiles
,:num_tile_entries
,:num_tile_contents
- Tile counts:clustered?
- Whether tiles are clustered:internal_compression
,:tile_compression
- Compression types:tile_type
- Type of tiles stored:min_zoom
,:max_zoom
- Zoom level bounds:min_position
,:max_position
- Geographic bounds:center_zoom
,:center_position
- Center point
Examples
iex> ExPmtiles.parse_header(header_binary)
%{
magic_number: "PMTiles",
spec_version: 3,
min_zoom: 0,
max_zoom: 14,
...
}
Reads a variable-length integer from binary data.
PMTiles uses variable-length integers (varints) for efficient encoding of small numbers. This function reads one varint from the beginning of the binary.
Parameters
binary
- Binary data containing the varintshift
- Internal parameter for bit shifting (default: 0)result
- Internal parameter for accumulating result (default: 0)
Returns
{integer(), binary()}
- Tuple of the decoded integer and remaining binary- Raises error if binary is empty or malformed
Examples
iex> ExPmtiles.read_varint(<<1>>)
{1, ""}
iex> ExPmtiles.read_varint(<<128, 1>>)
{128, ""}
Converts a PMTiles tile ID back to zoom level and coordinates.
Performs the inverse operation of zxy_to_tile_id/3
, converting a tile ID
back to its corresponding z/x/y coordinates.
Parameters
tile_id
- The tile ID to convert
Returns
{z, x, y}
- Tuple of zoom level and coordinates
Raises
ArgumentError
- If tile_id is invalid or exceeds 64-bit limit
Examples
iex> ExPmtiles.tile_id_to_zxy(1048576)
{10, 512, 256}
iex> ExPmtiles.tile_id_to_zxy(0)
{0, 0, 0}
Converts zoom level and coordinates to a PMTiles tile ID.
Uses the Hilbert curve mapping to convert z/x/y coordinates to a unique tile ID. This is the standard method used by PMTiles for tile identification.
Parameters
z
- Zoom level (integer, 0-26)x
- X coordinate (integer, 0 to 2^z - 1)y
- Y coordinate (integer, 0 to 2^z - 1)
Returns
integer()
- The tile ID
Raises
ArgumentError
- If zoom level exceeds 26 or coordinates are out of bounds
Examples
iex> ExPmtiles.zxy_to_tile_id(10, 512, 256)
1048576
iex> ExPmtiles.zxy_to_tile_id(0, 0, 0)
0