ExPmtiles (ExPmtiles v0.3.4)
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
HTTP Connection Pooling
For optimal S3 performance, this module uses a dedicated Hackney connection pool. The pool is automatically started when the application starts. You can configure the pool size via application configuration:
config :ex_pmtiles,
http_pool_size: 100, # Maximum number of connections (default: 100)
http_timeout: 15_000 # Request timeout in milliseconds (default: 15_000)
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