libtiles is a modern C++20 library for working with tile storage formats.
It is designed to be easy to use, efficient and to integrate smoothly into C++ applications that work with map tiles.
- PMTiles Support: Complete implementation of PMTiles v3 specification.
- Modular Design: Clean separation between low-level format handling and high-level APIs.
- Format Conversion: Convert between MBTiles, PMTiles and custom index formats.
- High Performance: Optimized for large tile datasets.
Requirements:
- Bazel 8+ build system.
- C++20 compatible toolchain.
- Dependencies are managed by Bazel (abseil, xxhash, zlib, protozero, gzip-hpp, hilbert_curves).
Add to your MODULE.bazel:
bazel_dep(name = "libtiles", version = "0.1.0")
archive_override(
module_name = "libtiles",
strip_prefix = "libtiles-0.1.0",
urls = ["https://github.com/eak1mov/libtiles/archive/v0.1.0.zip"],
)Add dependency to BUILD.bazel:
cc_library(
name = "your_library",
...
deps = ["@libtiles//:pm"],
)#include "libtiles/pm/writer.h"
namespace pm = libtiles::pm;
int main() {
auto writer = pm::createWriter({.filePath = "output.pmtiles"});
auto tileId = pm::TileId{.x = 1, .y = 2, .z = 3};
auto tileData = "example tile data";
writer->writeTile(tileId, tileData);
writer->finalize();
}#include "libtiles/pm/reader.h"
namespace pm = libtiles::pm;
int main() {
auto reader = pm::createFileReader("input.pmtiles");
auto tileId = pm::TileId{.x = 1, .y = 2, .z = 3};
auto tileData = reader->readTile(tileId);
std::cout << "tileData: " << tileData.size() << " bytes" << std::endl;
// Iterate over all tiles
for (const auto& [tileId, tileData] : reader->tiles()) {
std::cout << "Tile x=" << tileId.x << ", size=" << tileData.size() << std::endl;
}
}# Build all tools
bazel build //tileutils:all
# Export tile index and tiles from mbtiles:
# bazel-bin/tileutils/mb_export_index --input_path=input.mbtiles --output_index_path=output.index --output_tiles_path=output.tiles
# Export tile index from pmtiles:
bazel-bin/tileutils/pm_export_index --input_path=input.pmtiles --output_path=output.index
# Import from tile index and tiles file to pmtiles:
bazel-bin/tileutils/pm_import_index --input_index_path=input.index --input_tiles_path=input.tiles --output_path=output.pmtiles
# Convert mbtiles to pmtiles:
bazel-bin/tileutils/mb_to_pm --input_path=input.mbtiles --output_path=output.pmtiles
# Convert pmtiles to mbtiles:
bazel-bin/tileutils/pm_to_mb --input_path=input.pmtiles --output_path=output.mbtiles
# Export pmtiles file to directory of files:
bazel-bin/tileutils/pm_to_xyz --input_path=input.pmtiles --output_path="tiles/{z}/{x}/{y}.png"
# Import directory of files into pmtiles file:
bazel-bin/tileutils/xyz_to_pm --input_path="tiles/{z}/{x}/{y}.png" --output_path=output.pmtileslibtiles/pm: high-level API for reading and writing tiles, metadata and headers in PMTiles format.libtiles/pm/spec: low-level implementation of the PMTiles v3 specification, including serialization/deserialization of headers and directories.
libtiles/
├── pm/ # High-level PMTiles API
│ ├── reader.h # Reader (access to tiles from pmtiles file)
│ ├── writer.h # Writer (write tiles to pmtiles file)
├── pm/spec/ # Low-level implementation of PMTiles specification
│ ├── header.h # Header serialization and deserialization
│ ├── directory.h # Tile directory management
│ ├── tile_id.h # Tile coordinate encoding
├── tileindex/ # Custom index format utilities
tileutils/ # Command-line conversion tools
# Run tests:
bazel run //:tests
# Run benchmarks, clang-format and clang-tidy checks:
bazel run //:benchmark
bazel build --config=clang-format -k //:all
bazel build --config=clang-tidy -k //:allThis project is licensed under the MIT License - see the LICENSE file for details.
pm/specis based on the PMTiles specification by Protomaps.tileutils/mb_*tools are based on the MBTiles specification by Mapbox.- Built with the help of excellent open-source libraries, including Abseil, xxHash, and protozero.