updated: 2025-04-14T17:20:59.837696235+00:00[Etc/UTC]
utiles
utiles = utils + tiles
web map tile utilities, batching, serving, python and bears (oh-my)
Installation
# __CLI__
# from crates
cargo install utiles
# from source
cargo install --git https://github.com/jessekrubin/utiles.git utiles
# install the oxipng mbtiles/tiles-db wrapper cli
cargo install --git https://github.com/jessekrubin/utiles.git utiles-oxipng
# via the python package (which wrappers the rust-cli)
pip install -U utiles
# __LIBS__
# python (python lib + rust-cli)
pip install -U utiles
# rust-cli
cargo install utiles
# rust-libs
cargo add utiles-core utiles
About
utiles
started off as a python port of mapbox’s web-mercator utils
python-library mercantile written
in rust. It has since been expanded into a slim rust crate (utiles-core
)
a less slim crate with a lib/cli (utiles
), that has a python package wrapper.
For more details on the python package see: ./utiles-pyo3
python
A mostly drop-in replacement for mercantile written w/ rust, plus several other util(e)ities
dev
Contributing
- Please do! Would love some feedback!
- Be kind!
- DO NOT USE the phrases
blazing fast
/blazingly fast
in any PRs, issues or docs. - I will happily accept PRs, and add you to the currently (5/26/2023) non-existent contributors list.
MISC
zoom info
zoom | ntiles | total | rowcol_range | max_rowcol |
---|---|---|---|---|
0 | 1 | 1 | 0 | 1 |
1 | 4 | 5 | 1 | 2 |
2 | 16 | 21 | 3 | 4 |
3 | 64 | 85 | 7 | 8 |
4 | 256 | 341 | 15 | 16 |
5 | 1_024 | 1_365 | 31 | 32 |
6 | 4_096 | 5_461 | 63 | 64 |
7 | 16_384 | 21_845 | 127 | 128 |
8 | 65_536 | 87_381 | 255 | 256 |
9 | 262_144 | 349_525 | 511 | 512 |
10 | 1_048_576 | 1_398_101 | 1_023 | 1_024 |
11 | 4_194_304 | 5_592_405 | 2_047 | 2_048 |
12 | 16_777_216 | 22_369_621 | 4_095 | 4_096 |
13 | 67_108_864 | 89_478_485 | 8_191 | 8_192 |
14 | 268_435_456 | 357_913_941 | 16_383 | 16_384 |
15 | 1_073_741_824 | 1_431_655_765 | 32_767 | 32_768 |
16 | 4_294_967_296 | 5_726_623_061 | 65_535 | 65_536 |
17 | 17_179_869_184 | 22_906_492_245 | 131_071 | 131_072 |
18 | 68_719_476_736 | 91_625_968_981 | 262_143 | 262_144 |
19 | 274_877_906_944 | 366_503_875_925 | 524_287 | 524_288 |
20 | 1_099_511_627_776 | 1_466_015_503_701 | 1_048_575 | 1_048_576 |
21 | 4_398_046_511_104 | 5_864_062_014_805 | 2_097_151 | 2_097_152 |
22 | 17_592_186_044_416 | 23_456_248_059_221 | 4_194_303 | 4_194_304 |
23 | 70_368_744_177_664 | 93_824_992_236_885 | 8_388_607 | 8_388_608 |
24 | 281_474_976_710_656 | 375_299_968_947_541 | 16_777_215 | 16_777_216 |
25 | 1_125_899_906_842_624 | 1_501_199_875_790_165 | 33_554_431 | 33_554_432 |
26 | 4_503_599_627_370_496 | 6_004_799_503_160_661 | 67_108_863 | 67_108_864 |
27 | 18_014_398_509_481_984 | 24_019_198_012_642_645 | 134_217_727 | 134_217_728 |
28 | 72_057_594_037_927_936 | 96_076_792_050_570_581 | 268_435_455 | 268_435_456 |
29 | 288_230_376_151_711_744 | 384_307_168_202_282_325 | 536_870_911 | 536_870_912 |
30 | 1_152_921_504_606_846_976 | 1_537_228_672_809_129_301 | 1_073_741_823 | 1_073_741_824 |
31 | 4_611_686_018_427_387_904 | 6_148_914_691_236_517_205 | 2_147_483_647 | 2_147_483_648 |
Zoom levels
zoom ntiles total rowcol_range max_rowcol
0 0 1 1 0 1
1 1 4 5 1 2
2 2 16 21 3 4
3 3 64 85 7 8
4 4 256 341 15 16
5 5 1024 1365 31 32
6 6 4096 5461 63 64
7 7 16384 21845 127 128
8 8 65536 87381 255 256
9 9 262144 349525 511 512
10 10 1048576 1398101 1023 1024
11 11 4194304 5592405 2047 2048
12 12 16777216 22369621 4095 4096
13 13 67108864 89478485 8191 8192
14 14 268435456 357913941 16383 16384
15 15 1073741824 1431655765 32767 32768
16 16 4294967296 5726623061 65535 65536
17 17 17179869184 22906492245 131071 131072
18 18 68719476736 91625968981 262143 262144
19 19 274877906944 366503875925 524287 524288
20 20 1099511627776 1466015503701 1048575 1048576
21 21 4398046511104 5864062014805 2097151 2097152
22 22 17592186044416 23456248059221 4194303 4194304
23 23 70368744177664 93824992236885 8388607 8388608
24 24 281474976710656 375299968947541 16777215 16777216
25 25 1125899906842624 1501199875790165 33554431 33554432
26 26 4503599627370496 6004799503160661 67108863 67108864
27 27 18014398509481984 24019198012642645 134217727 134217728
28 28 72057594037927936 96076792050570581 268435455 268435456
29 29 288230376151711744 384307168202282325 536870911 536870912
30 30 1152921504606846976 1537228672809129301 1073741823 1073741824
31 31 4611686018427387904 6148914691236517205 2147483647 2147483648
json
[
{
"max_rowcol": 1,
"ntiles": 1,
"rowcol_range": 0,
"total": 1,
"zoom": 0
},
{
"max_rowcol": 2,
"ntiles": 4,
"rowcol_range": 1,
"total": 5,
"zoom": 1
},
{
"max_rowcol": 4,
"ntiles": 16,
"rowcol_range": 3,
"total": 21,
"zoom": 2
},
{
"max_rowcol": 8,
"ntiles": 64,
"rowcol_range": 7,
"total": 85,
"zoom": 3
},
{
"max_rowcol": 16,
"ntiles": 256,
"rowcol_range": 15,
"total": 341,
"zoom": 4
},
{
"max_rowcol": 32,
"ntiles": 1024,
"rowcol_range": 31,
"total": 1365,
"zoom": 5
},
{
"max_rowcol": 64,
"ntiles": 4096,
"rowcol_range": 63,
"total": 5461,
"zoom": 6
},
{
"max_rowcol": 128,
"ntiles": 16384,
"rowcol_range": 127,
"total": 21845,
"zoom": 7
},
{
"max_rowcol": 256,
"ntiles": 65536,
"rowcol_range": 255,
"total": 87381,
"zoom": 8
},
{
"max_rowcol": 512,
"ntiles": 262144,
"rowcol_range": 511,
"total": 349525,
"zoom": 9
},
{
"max_rowcol": 1024,
"ntiles": 1048576,
"rowcol_range": 1023,
"total": 1398101,
"zoom": 10
},
{
"max_rowcol": 2048,
"ntiles": 4194304,
"rowcol_range": 2047,
"total": 5592405,
"zoom": 11
},
{
"max_rowcol": 4096,
"ntiles": 16777216,
"rowcol_range": 4095,
"total": 22369621,
"zoom": 12
},
{
"max_rowcol": 8192,
"ntiles": 67108864,
"rowcol_range": 8191,
"total": 89478485,
"zoom": 13
},
{
"max_rowcol": 16384,
"ntiles": 268435456,
"rowcol_range": 16383,
"total": 357913941,
"zoom": 14
},
{
"max_rowcol": 32768,
"ntiles": 1073741824,
"rowcol_range": 32767,
"total": 1431655765,
"zoom": 15
},
{
"max_rowcol": 65536,
"ntiles": 4294967296,
"rowcol_range": 65535,
"total": 5726623061,
"zoom": 16
},
{
"max_rowcol": 131072,
"ntiles": 17179869184,
"rowcol_range": 131071,
"total": 22906492245,
"zoom": 17
},
{
"max_rowcol": 262144,
"ntiles": 68719476736,
"rowcol_range": 262143,
"total": 91625968981,
"zoom": 18
},
{
"max_rowcol": 524288,
"ntiles": 274877906944,
"rowcol_range": 524287,
"total": 366503875925,
"zoom": 19
},
{
"max_rowcol": 1048576,
"ntiles": 1099511627776,
"rowcol_range": 1048575,
"total": 1466015503701,
"zoom": 20
},
{
"max_rowcol": 2097152,
"ntiles": 4398046511104,
"rowcol_range": 2097151,
"total": 5864062014805,
"zoom": 21
},
{
"max_rowcol": 4194304,
"ntiles": 17592186044416,
"rowcol_range": 4194303,
"total": 23456248059221,
"zoom": 22
},
{
"max_rowcol": 8388608,
"ntiles": 70368744177664,
"rowcol_range": 8388607,
"total": 93824992236885,
"zoom": 23
},
{
"max_rowcol": 16777216,
"ntiles": 281474976710656,
"rowcol_range": 16777215,
"total": 375299968947541,
"zoom": 24
},
{
"max_rowcol": 33554432,
"ntiles": 1125899906842624,
"rowcol_range": 33554431,
"total": 1501199875790165,
"zoom": 25
},
{
"max_rowcol": 67108864,
"ntiles": 4503599627370496,
"rowcol_range": 67108863,
"total": 6004799503160661,
"zoom": 26
},
{
"max_rowcol": 134217728,
"ntiles": 18014398509481984,
"rowcol_range": 134217727,
"total": 24019198012642645,
"zoom": 27
},
{
"max_rowcol": 268435456,
"ntiles": 72057594037927936,
"rowcol_range": 268435455,
"total": 96076792050570581,
"zoom": 28
},
{
"max_rowcol": 536870912,
"ntiles": 288230376151711744,
"rowcol_range": 536870911,
"total": 384307168202282325,
"zoom": 29
},
{
"max_rowcol": 1073741824,
"ntiles": 1152921504606846976,
"rowcol_range": 1073741823,
"total": 1537228672809129301,
"zoom": 30
},
{
"max_rowcol": 2147483648,
"ntiles": 4611686018427387904,
"rowcol_range": 2147483647,
"total": 6148914691236517205,
"zoom": 31
}
]
cli
The utiles cli can be installed via cargo or pip; the python library bundles
a version of the cli that can be run just as utiles
and/or python -m utiles
.
The cli is a collection of commands for streaming tiles in text format (excellent for piping) and working with mbtiles/tile-db files.
All of the mercantile
cli commands are available, and burn
and edges
from supermercado
are also available.
What about the mbtiles
cli in the martin repo? [2025-01-14]
The mbtiles
cli is very good and has significant overlap with the utiles
cli.
(imo) The most intriguing feature of the mbtiles
cli is the diff
/patch
commands
that allow for comparing and updating mbtiles files; utiles
does not have this feature.
utiles
does have a streaming mode copy command that allows copying tiles from one mbtiles db to another without using the sqlite-ATTACH
command; this is in my testing and experience less crash-prone and much faster on super large tile-dbs.
The cli commands in utiles
that interact with mbtiles are more focused raster
format mbtiles
files.
agg-hash
utiles
adopted the standardized way of calculating an aggregate-tiles-hash
for an mbtiles file, and builds on it to allow for hash-algorithms aside from md5
. The cli command also allows for selecting zoom-levels, and bounding-boxes to calculate the hash over.
The default hashing alg is md5
to match the martin mbtiles
cli; but may change if I get around to updating some of our (dgi’s) very large datasets;
xxh64
is generally very fast.
> utiles agg-hash -z 2 osm-standard.z0z4.mbtiles
{
"hash_type": "md5",
"hash": "F211FF7D9FF917B58808302E0AAE82FF",
"ntiles": 16,
"dt": {
"secs": 0,
"nanos": 709600
}
}
> utiles agg-hash osm-standard.z0z4.mbtiles --hash md5
{
"hash_type": "md5",
"hash": "3A9279283D4D6B5B12362E3A76AF7201",
"ntiles": 341,
"dt": {
"secs": 0,
"nanos": 10092400
}
}
> utiles agg-hash osm-standard.z0z4.mbtiles
{
"hash_type": "md5",
"hash": "3A9279283D4D6B5B12362E3A76AF7201",
"ntiles": 341,
"dt": {
"secs": 0,
"nanos": 10108300
}
}
copy
> utiles tj osm-standard.z0z4.mbtiles
{
"tilejson": "3.0.0",
"tiles": [],
"bounds": [
-180.0,
-85.05113,
180.0,
85.05113
],
"center": [
0.0,
0.0,
2
],
"description": "osm standard png tiles 256",
"maxzoom": 4,
"minzoom": 0,
"name": "osm-standard",
"format": "png",
"type": "overlay"
}
> utiles copy osm-standard.z0z4.mbtiles osm-standard.z4.mbtiles -z 4
2025-01-14T22:17:07.113799Z INFO utiles::copy: copy-config-json: {
"src": "osm-standard.z0z4.mbtiles",
"dst": "osm-standard.z4.mbtiles",
"zset": 16,
"zooms": [
4
],
"bboxes": null,
"bounds_string": null,
"verbose": true,
"dryrun": false,
"force": false,
"jobs": null,
"istrat": "None",
"dst_type": null,
"hash": null,
"stream": false
}
2025-01-14T22:17:07.114507Z WARN utiles::copy::pasta: mbtiles-2-mbtiles copy is a WIP
2025-01-14T22:17:07.116782Z INFO utiles::copy::pasta: dst_db_type_if_new: Some(Flat)
2025-01-14T22:17:07.154346Z INFO utiles::copy::pasta: Copying from "osm-standard.z0z4.mbtiles" (flat) -> "osm-standard.z4.mbtiles" flat
2025-01-14T22:17:07.154803Z INFO utiles::copy::pasta: Copying tiles: "osm-standard.z0z4.mbtiles" -> "osm-standard.z4.mbtiles"
2025-01-14T22:17:07.165062Z INFO utiles::copy::pasta: Copied 256 tiles from "osm-standard.z0z4.mbtiles" -> "osm-standard.z4.mbtiles" in 10.0263ms
> utiles tj osm-standard.z4.mbtiles
{
"tilejson": "3.0.0",
"tiles": [],
"bounds": [
-180.0,
-85.05113,
180.0,
85.05113
],
"center": [
0.0,
0.0,
2
],
"description": "osm standard png tiles 256",
"maxzoom": 4,
"minzoom": 4,
"name": "osm-standard",
"dbtype": "flat",
"format": "png",
"type": "overlay"
}
utiles CLI commands
Table of contents
Command | Description |
---|---|
about | Echo info about utiles |
agg-hash | Aggregate tile hashes for tiles-db |
bounding-tile | Echo bounding tile at zoom for bbox / geojson |
burn | Burn tiles from GeoJSON stream at zoom level (tile coverage) |
children | Echo children tiles of input tiles |
commands | list all commands |
copy | Copy tiles from src -> dst |
dbcontains | Determine if mbtiles contains a latlong |
dev | Development/Playground command (hidden) |
edges | Echo edge tiles from stream of xyz tiles |
enumerate | Enumerate tiles db |
fmtstr | Format json-tiles [x, y, z] tiles w/ format-string |
info | Echo mbtiles info/stats |
lint | Lint mbtiles file(s) (wip) |
merge | Merge tiles from stream removing parent tiles if children are present |
metadata | Echo metadata (table) as json arr/obj |
metadata-set | Set metadata key/value or from json file if key is fspath |
neighbors | Echo the neighbor tiles for input tiles |
optimize | Optimize tiles-db |
parent | Echo parent tile of input tiles |
pmtileid | Converts tile(s) to/from pmtile-id/[x, y, z] |
quadkey | Converts tiles to/from quadkey/[x, y, z] |
rimraf | rm-rf dirpath |
serve | utiles server (wip) |
shapes | Echo tiles as GeoJSON feature collections/sequences |
sqlite | sqlite utils/cmds |
tilejson | Echo the tile.json for mbtiles file |
tiles | Echo tiles at zoom intersecting geojson bbox / feature / collection |
touch | Create new mbtiles db w/ schema |
update | Update mbtiles db |
vacuum | vacuum sqlite db inplace/into |
webpify | Convert raster mbtiles to webp format |
zxyify | zxyify/unzxyify tiles-db |
about
Echo info about utiles
Usage: utiles about [OPTIONS]
Options:
--debug debug mode (print/log more)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
agg-hash
Aggregate tile hashes for tiles-db
Usage: utiles agg-hash [OPTIONS] <FILEPATH>
Arguments:
<FILEPATH> sqlite filepath
Options:
--debug debug mode (print/log more)
-m, --min compact/minified json (default: false)
--bbox <BBOX> bbox(es) (west, south, east, north)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-z, --zoom <ZOOM> Zoom level (0-30)
--minzoom <MINZOOM> min zoom level (0-30)
--maxzoom <MAXZOOM> max zoom level (0-30)
--hash <HASH> hash to use for blob-id if copying to normal/hash db type [possible
values: md5, fnv1a, xxh32, xxh64, xxh3-64, xxh3-128]
-h, --help Print help
bounding-tile
Echo the Web Mercator tile at ZOOM level bounding `GeoJSON` [west, south,
east, north] bounding boxes, features, or collections read from stdin.
Input may be a compact newline-delimited sequences of JSON or a
pretty-printed ASCII RS-delimited sequence of JSON (like
<https://tools.ietf.org/html/rfc8142> and
<https://tools.ietf.org/html/rfc7159>).
Examples:
\> echo "[-105.05, 39.95, -105, 40]" | utiles bounding-tile
[426, 775, 11]
Usage: utiles bounding-tile [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
--trace
trace mode (print/log EVEN more)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
--log-json
format log as NDJSON
-h, --help
Print help (see a summary with '-h')
burn
Burn tiles from `GeoJSON` stream at zoom level (tile coverage)
Usage: utiles burn [OPTIONS] <ZOOM> [INPUT]
Arguments:
<ZOOM>
Zoom level (0-30)
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
--trace
trace mode (print/log EVEN more)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
--log-json
format log as NDJSON
-h, --help
Print help (see a summary with '-h')
children
Echo children tiles of input tiles
Input may be a compact newline-delimited sequences of JSON or a
pretty-printed ASCII RS-delimited sequence of JSON (like
<https://tools.ietf.org/html/rfc8142> and
<https://tools.ietf.org/html/rfc7159>).
Example:
\> echo "[486, 332, 10]" | utiles children
[972, 664, 11]
Usage: utiles children [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
--trace
trace mode (print/log EVEN more)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
--log-json
format log as NDJSON
--depth <DEPTH>
[default: 1]
-h, --help
Print help (see a summary with '-h')
commands
list all commands
Usage: utiles commands [OPTIONS]
Options:
--debug debug mode (print/log more)
-f, --full
-t, --table
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
copy
Copy tiles from src -> dst
Usage: utiles copy [OPTIONS] <SRC> <DST>
Arguments:
<SRC> source dataset fspath (mbtiles, dirpath)
<DST> destination dataset fspath (mbtiles, dirpath)
Options:
--debug debug mode (print/log more)
-n, --dryrun dryrun (don't actually copy)
-f, --force force overwrite dst
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-z, --zoom <ZOOM> Zoom level (0-30)
--minzoom <MINZOOM> min zoom level (0-30)
--maxzoom <MAXZOOM> max zoom level (0-30)
--bbox <BBOX> bbox (west, south, east, north)
-c, --conflict <CONFLICT> conflict strategy when copying tiles [default: undefined] [possible
values: undefined, ignore, replace, abort, fail]
--dst-type <DST_TYPE> db-type (default: src type) [possible values: flat, hash, norm]
--hash <HASH> hash to use for blob-id if copying to normal/hash db type [possible
values: md5, fnv1a, xxh32, xxh64, xxh3-64, xxh3-128]
-j, --jobs <JOBS> n-jobs ~ 0=ncpus (default: max(4, ncpus))
-h, --help Print help
dbcontains
Determine if mbtiles contains a latlong
Usage: utiles dbcontains [OPTIONS] <FILEPATH> <LNGLAT>
Arguments:
<FILEPATH> mbtiles filepath
<LNGLAT> lat/long
Options:
--debug debug mode (print/log more)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
dev
Development/Playground command (hidden)
Usage: utiles dev [OPTIONS] [FSPATH]
Arguments:
[FSPATH]
Options:
--debug debug mode (print/log more)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
edges
Echo edge tiles from stream of xyz tiles
Usage: utiles edges [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
--wrapx
--seq
Write tiles as RS-delimited JSON sequence
--trace
trace mode (print/log EVEN more)
--log-json
format log as NDJSON
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
-h, --help
Print help (see a summary with '-h')
enumerate
Enumerate tiles db
Usage: utiles enumerate [OPTIONS] <FSPATHS>...
Arguments:
<FSPATHS>...
Options:
--bbox <BBOX> bbox(es) (west, south, east, north)
--debug debug mode (print/log more)
--trace trace mode (print/log EVEN more)
-z, --zoom <ZOOM> Zoom level (0-30)
--log-json format log as NDJSON
--minzoom <MINZOOM> min zoom level (0-30)
--maxzoom <MAXZOOM> max zoom level (0-30)
-t, --tippecanoe tippecanoe-enumerate like output '{relpath} {x} {y} {z}'
-h, --help Print help
fmtstr
Format json-tiles `[x, y, z]` tiles w/ format-string
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
Example:
```
\> echo "[486, 332, 10]" | utiles fmtstr
[486, 332, 10]
\> echo "[486, 332, 10]" | utiles fmtstr --fmt "{x},{y},{z}"
486,332,10
\> echo "[486, 332, 10]" | utiles fmt --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND
tile_column = {x} AND tile_row = {y};"
SELECT * FROM tiles WHERE zoom_level = 10 AND tile_column = 486 AND tile_row = 332;
```
Usage: utiles fmtstr [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
--trace
trace mode (print/log EVEN more)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
--log-json
format log as NDJSON
-h, --help
Print help (see a summary with '-h')
info
Echo mbtiles info/stats
Usage: utiles info [OPTIONS] <FILEPATH>
Arguments:
<FILEPATH> sqlite filepath
Options:
--debug debug mode (print/log more)
-m, --min compact/minified json (default: false)
--full
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-s, --statistics [aliases: stats]
-h, --help Print help
lint
Lint mbtiles file(s) (wip)
Usage: utiles lint [OPTIONS] <FSPATHS>...
Arguments:
<FSPATHS>... filepath(s) or dirpath(s)
Options:
--debug debug mode (print/log more)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
merge
Merge tiles from stream removing parent tiles if children are present
Usage: utiles merge [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
-Z, --minzoom <MINZOOM>
min zoom level (0-30) to merge to
[default: 0]
-s, --sort
--trace
trace mode (print/log EVEN more)
--log-json
format log as NDJSON
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
-h, --help
Print help (see a summary with '-h')
metadata
Echo metadata (table) as json arr/obj
Usage: utiles metadata [OPTIONS] <FILEPATH>
Arguments:
<FILEPATH> sqlite filepath
Options:
--debug debug mode (print/log more)
-m, --min compact/minified json (default: false)
--obj Output as json object not array
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
--raw Output as json string for values (default: false)
-h, --help Print help
metadata-set
Set metadata key/value or from `json` file if key is fspath
Usage: utiles metadata-set [OPTIONS] <FILEPATH> <KEY/FSPATH> [VALUE]
Arguments:
<FILEPATH> sqlite filepath
<KEY/FSPATH> key or json-fspath
[VALUE] value
Options:
--debug debug mode (print/log more)
-m, --min compact/minified json (default: false)
-n, --dryrun dryrun (don't actually set)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
neighbors
Echo the neighbor tiles for input tiles
Input may be a compact newline-delimited sequences of JSON or a pretty-printed ASCII RS-delimited
sequence of JSON (like <https://tools.ietf.org/html/rfc8142> and
<https://tools.ietf.org/html/rfc7159>).
Usage: utiles neighbors [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
--trace
trace mode (print/log EVEN more)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
--log-json
format log as NDJSON
-h, --help
Print help (see a summary with '-h')
optimize
Optimize tiles-db
Usage: utiles optimize [OPTIONS] <FILEPATH> <DST>
Arguments:
<FILEPATH> sqlite filepath
<DST> destination dataset fspath (mbtiles, dirpath)
Options:
--debug debug mode (print/log more)
-m, --min compact/minified json (default: false)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
parent
Echo parent tile of input tiles
Usage: utiles parent [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
--trace
trace mode (print/log EVEN more)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
--log-json
format log as NDJSON
--depth <DEPTH>
[default: 1]
-h, --help
Print help (see a summary with '-h')
pmtileid
Converts tile(s) to/from pmtile-id/[x, y, z]
Input may be a compact newline-delimited sequences of JSON or a
pretty-printed ASCII RS-delimited sequence of JSON (like
<https://tools.ietf.org/html/rfc8142> and
<https://tools.ietf.org/html/rfc7159>).
Examples:
\> echo "[486, 332, 10]" | utiles pmtileid
506307
\> echo "506307" | utiles pmtileid
[486, 332, 10]
\> utiles pmtileid 506307
[486, 332, 10]
Usage: utiles pmtileid [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
--trace
trace mode (print/log EVEN more)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
--log-json
format log as NDJSON
-h, --help
Print help (see a summary with '-h')
quadkey
Converts tiles to/from quadkey/[x, y, z]
Input may be a compact newline-delimited sequences of JSON or a
pretty-printed ASCII RS-delimited sequence of JSON (like
<https://tools.ietf.org/html/rfc8142> and
<https://tools.ietf.org/html/rfc7159>).
Examples:
\> echo "[486, 332, 10]" | utiles quadkey
0313102310
\> echo "0313102310" | utiles quadkey
[486, 332, 10]
\> utiles quadkey 0313102310
[486, 332, 10]
Usage: utiles quadkey [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
--trace
trace mode (print/log EVEN more)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
--log-json
format log as NDJSON
-h, --help
Print help (see a summary with '-h')
rimraf
rm-rf dirpath
Usage: utiles rimraf [OPTIONS] <DIRPATH>
Arguments:
<DIRPATH> dirpath to nuke
Options:
--debug debug mode (print/log more)
--size collect and print file sizes
-n, --dryrun dryrun (don't actually rm)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
--verbose
-h, --help Print help
serve
utiles server (wip)
Usage: utiles serve [OPTIONS] [FSPATHS]...
Arguments:
[FSPATHS]... Filesystem paths to serve from
Options:
--debug debug mode (print/log more)
-p, --port <PORT> Port to server on [default: 3333]
-H, --host <HOST> Host bind address [default: 0.0.0.0]
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-s, --strict strict mode (default: false)
-h, --help Print help
shapes
Echo tiles as `GeoJSON` feature collections/sequences
Input may be a compact newline-delimited sequences of JSON or a pretty-printed ASCII RS-delimited
sequence of JSON (like <https://tools.ietf.org/html/rfc8142> and
<https://tools.ietf.org/html/rfc7159>).
Example:
\> echo "[486, 332, 10]" | utiles shapes --precision 4 --bbox [-9.1406, 53.1204, -8.7891, 53.3309]
Usage: utiles shapes [OPTIONS] [INPUT]
Arguments:
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
--precision <PRECISION>
Decimal precision of coordinates
--trace
trace mode (print/log EVEN more)
--geographic
Output in geographic coordinates (the default)
--log-json
format log as NDJSON
--mercator
Output in Web Mercator coordinates
--feature
Output as a `GeoJSON` feature collections
--bbox
Output in Web Mercator coordinates
--collect
Output as a `GeoJSON` feature collections
--extents
Write shape extents as ws-separated strings (default is False)
--buffer <BUFFER>
Shift shape x and y values by a constant number
-h, --help
Print help (see a summary with '-h')
sqlite
sqlite utils/cmds
Usage: utiles sqlite [OPTIONS] <COMMAND>
Commands:
analyze Analyze sqlite db
header Dump sqlite db header
vacuum vacuum sqlite db inplace/into
help Print this message or the help of the given subcommand(s)
Options:
--debug debug mode (print/log more)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
tilejson
Echo the `tile.json` for mbtiles file
Usage: utiles tilejson [OPTIONS] <FILEPATH>
Arguments:
<FILEPATH> sqlite filepath
Options:
--debug debug mode (print/log more)
-m, --min compact/minified json (default: false)
-t, --tilestats include tilestats
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
tiles
Echos web-mercator tiles at zoom level intersecting given geojson-bbox [west, south,
east, north], geojson-features, or geojson-collections read from stdin.
Output format is a JSON `[x, y, z]` array by default; use --obj to output a
JSON object `{x: x, y: y, z: z}`.
bbox shorthands (case-insensitive):
"*" | "world" => [-180, -85.0511, 180, 85.0511]
"n" | "north" => [-180, 0, 180, 85.0511]
"s" | "south" => [-180, -85.0511, 180, 0]
"e" | "east" => [0, -85.0511, 180, 85.0511]
"w" | "west" => [-180, -85.0511, 0, 85.0511]
"ne" | "northeast" => [0, 0, 180, 85.0511]
"se" | "southeast" => [0, -85.0511, 180, 0]
"nw" | "northwest" => [-180, 0, 0, 85.0511]
"sw" | "southwest" => [-180, -85.0511, 0, 0]
Input may be a compact newline-delimited sequences of JSON or a
pretty-printed ASCII RS-delimited sequence of JSON (like
<https://tools.ietf.org/html/rfc8142> and
<https://tools.ietf.org/html/rfc7159>).
Example:
\\> echo "[-105.05, 39.95, -105, 40]" | utiles tiles 12
[852, 1550, 12]
[852, 1551, 12]
[853, 1550, 12]
[853, 1551, 12]
\> utiles tiles 12 "[-105.05, 39.95, -105, 40]"
[852, 1550, 12]
[852, 1551, 12]
[853, 1550, 12]
[853, 1551, 12]
Usage: utiles tiles [OPTIONS] <ZOOM> [INPUT]
Arguments:
<ZOOM>
Zoom level (0-30)
[INPUT]
Options:
--debug
debug mode (print/log more)
--seq
Write tiles as RS-delimited JSON sequence
--obj
Format tiles as json objects (equiv to `-F/--fmt "{json_obj}"`)
--trace
trace mode (print/log EVEN more)
-F, --fmt <FMT>
Format string for tiles (default: `{json_arr}`)
Example:
> utiles tiles 1 * --fmt "http://thingy.com/{z}/{x}/{y}.png"
http://thingy.com/1/0/0.png
http://thingy.com/1/0/1.png
http://thingy.com/1/1/0.png
http://thingy.com/1/1/1.png
> utiles tiles 1 * --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column =
{x} AND tile_row = {-y};"
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 0 AND tile_row = 0;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 1;
SELECT * FROM tiles WHERE zoom_level = 1 AND tile_column = 1 AND tile_row = 0;
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
`{bbox}` -> [w, s, e, n] bbox lnglat (wgs84)
`{projwin}` -> ulx,uly,lrx,lry projwin 4 gdal (wgs84)
`{bbox_web}` -> [w, s, e, n] bbox web-mercator (epsg:3857)
`{projwin_web}` -> ulx,uly,lrx,lry projwin 4 gdal (epsg:3857)
--log-json
format log as NDJSON
-h, --help
Print help (see a summary with '-h')
touch
Create new mbtiles db w/ schema
Usage: utiles touch [OPTIONS] <FILEPATH>
Arguments:
<FILEPATH> mbtiles filepath
Options:
--debug debug mode (print/log more)
--page-size <PAGE_SIZE> page size
--dbtype <DBTYPE> db-type (default: flat) [default: flat] [possible values: flat, hash,
norm]
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
update
Update mbtiles db
Usage: utiles update [OPTIONS] <FILEPATH>
Arguments:
<FILEPATH> sqlite filepath
Options:
--debug debug mode (print/log more)
-m, --min compact/minified json (default: false)
-n, --dryrun dryrun (don't actually update)
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-h, --help Print help
vacuum
vacuum sqlite db inplace/into
Usage: utiles vacuum [OPTIONS] <FILEPATH> [INTO]
Arguments:
<FILEPATH> sqlite filepath
[INTO] fspath to vacuum db into
Options:
--debug debug mode (print/log more)
-m, --min compact/minified json (default: false)
-a, --analyze Analyze db after vacuum
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
--page-size <PAGE_SIZE> page size to set
-h, --help Print help
webpify
Convert raster mbtiles to webp format
Usage: utiles webpify [OPTIONS] <FILEPATH> <DST>
Arguments:
<FILEPATH> sqlite filepath
<DST> destination dataset fspath (mbtiles, dirpath)
Options:
--debug debug mode (print/log more)
-m, --min compact/minified json (default: false)
-j, --jobs <JOBS> n-jobs ~ 0=ncpus (default: max(4, ncpus))
--trace trace mode (print/log EVEN more)
--log-json format log as NDJSON
-q, --quiet quiet
-h, --help Print help
zxyify
zxyify/unzxyify tiles-db
Adds/removes `z/x/y` table/view for querying tiles not inverted
Usage: utiles zxyify [OPTIONS] <FILEPATH>
Arguments:
<FILEPATH>
sqlite filepath
Options:
--debug
debug mode (print/log more)
-m, --min
compact/minified json (default: false)
--rm
un-zxyify a db
--trace
trace mode (print/log EVEN more)
--log-json
format log as NDJSON
-h, --help
Print help (see a summary with '-h')
utiles (python)
utiles = utils + tiles
OR utiles = ultra-tiles
depending on the day.
Fast spherical mercator geo/tile util(e)ities.
A mostly drop-in replacement for mercantile written w/ rust, plus several other util(e)ities.
Installation
pip install utiles
uv add utiles
Usage
>>> import utiles as ut
>>> from utiles import Tile, LngLat, LngLatBbox
>>> ut.bounds(1, 1, 1)
LngLatBbox(west=0, south=-85.0511287798066, east=180, north=0)
>>> t = ut.Tile(1, 2, 3)
>>> t
Tile(x=1, y=2, z=3)
>>> t.x, t.y, t.z
(1, 2, 3)
>>> x, y, z = t
>>> (x, y, z)
(1, 2, 3)
>>> list(ut.tiles(*ut.bounds(1, 1, 1), 3))
[Tile(x=4, y=4, z=3), Tile(x=4, y=5, z=3), Tile(x=4, y=6, z=3), Tile(x=4, y=7, z=3), Tile(x=5, y=4, z=3), Tile(x=5, y=5, z=3), Tile(x=5, y=6, z=3), Tile(x=5, y=7, z=3), Tile(x=6, y=4, z=3), Tile(x=6, y=5, z=3), Tile(x=6, y=6, z=3), Tile(x=6, y=7, z=3), Tile(x=7, y=4, z=3), Tile(x=7, y=5, z=3), Tile(x=7, y=6, z=3), Tile(x=7, y=7, z=3)]
>>> t
Tile(x=1, y=2, z=3)
>>> t.parent()
Tile(x=0, y=1, z=2)
>>> t.children()
[Tile(x=2, y=4, z=4), Tile(x=3, y=4, z=4), Tile(x=3, y=5, z=4), Tile(x=2, y=5, z=4)]
>>> t.bounds()
LngLatBbox(west=-135, south=40.97989806962013, east=-90, north=66.51326044311186)
>>> t.ul()
LngLat(lng=-135, lat=66.51326044311186)
>>> t.asdict()
{'x': 1, 'y': 2, 'z': 3}
>>> t.center()
LngLat(lng=-112.5, lat=53.74657925636599)
>>> ~t
Tile(x=1, y=5, z=3)
>>> t.valid() # check if tile is valid
True
>>> ut.Tile(1000, 1231234124, 2).valid() # invalid tile
False
>>> t.pmtileid() # return the pmtileid of the tile
34
>>> ut.Tile.from_pmtileid(34) # create a tile from pmtileid
Tile(x=1, y=2, z=3)
>>> t.json_arr() # json-array string
'[1, 2, 3]'
>>> t.json_obj() # json-object string
'{"x":1,"y":2,"z":3}'
>>> t.fmt_zxy() # format tile as z/x/y
'3/1/2'
>>> t.fmt_zxy_ext('png') # format tile as z/x/y.ext
'3/1/2.png'
>>> t == (1, 2, 3) # compare with tuple
True
>>> t == (1, 2, 2234234) # compare with tuple
False
About
Why?
I use mercantile regularly and wished it were a bit more ergonomic, had type annotations, and was faster, but overall it’s a great library.
This was an excuse to learn some more rust as well as pyo3.
Do I/you REALLY need a rust-port of mercantile?
I don’t know, decide for yourself. utiles
is certainly faster than mercantile
for some things (see benchmarks below)
Is it really a drop in replacement for mercantile?
Not quite, but it’s close. utiles doesn’t throw the same exceptions as mercantile, instead it throws ValueError
’s and
TypeError
’s.
There might be other differences, but I have been using it instead of mercantile for a bit now and it works pretty decent, tho I am open to suggestions!
Benchmarks (WIP)
---------------------------------------------------------------------------------------------------- benchmark 'quadkey': 12 tests -----------------------------------------------------------------------------------------------------
Name (time in ns) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_quadkey_bench[utiles-(0, 0, 0)] 199.9942 (1.0) 47,100.0021 (8.78) 284.7909 (1.0) 315.1058 (6.70) 299.9950 (1.06) 100.0008 (>1000.0) 966;1164 3,511.3476 (1.0) 38911 1
test_quadkey_bench[utiles-(1, 1, 1)] 252.6316 (1.26) 5,363.1581 (1.0) 293.9171 (1.03) 47.0478 (1.0) 284.2108 (1.0) 10.5264 (>1000.0)2884;35689 3,402.3204 (0.97) 196079 19
test_quadkey_bench[utiles-(1, 0, 1)] 299.9950 (1.50) 86,300.0023 (16.09) 397.2831 (1.39) 383.5726 (8.15) 399.9958 (1.41) 0.0073 (1.0) 1451;22409 2,517.0967 (0.72) 99010 1
test_quadkey_bench[mercantile-(0, 0, 0)] 599.9973 (3.00) 28,200.0037 (5.26) 821.2744 (2.88) 301.0209 (6.40) 799.9988 (2.81) 0.0073 (1.0) 658;21559 1,217.6198 (0.35) 69445 1
test_quadkey_bench[utiles-(1, 40, 7)] 599.9973 (3.00) 136,899.9947 (25.53) 758.0325 (2.66) 676.4311 (14.38) 699.9981 (2.46) 0.0073 (1.0) 565;29079 1,319.2047 (0.38) 108696 1
test_quadkey_bench[utiles-(486, 332, 10)] 749.9999 (3.75) 8,055.0002 (1.50) 838.5705 (2.94) 137.5439 (2.92) 824.9997 (2.90) 23.7496 (>1000.0) 1445;4742 1,192.5056 (0.34) 63695 20
test_quadkey_bench[mercantile-(1, 0, 1)] 799.9988 (4.00) 104,300.0011 (19.45) 1,015.6996 (3.57) 539.0831 (11.46) 1,000.0003 (3.52) 0.0073 (1.0) 1217;51791 984.5431 (0.28) 119048 1
test_quadkey_bench[mercantile-(1, 1, 1)] 799.9988 (4.00) 75,999.9966 (14.17) 1,047.5805 (3.68) 419.8019 (8.92) 1,000.0003 (3.52) 100.0008 (>1000.0) 3366;4074 954.5806 (0.27) 166667 1
test_quadkey_bench[utiles-(486, 332, 20)] 1,299.9953 (6.50) 83,399.9948 (15.55) 1,545.1801 (5.43) 461.2615 (9.80) 1,499.9969 (5.28) 100.0008 (>1000.0)8793;17328 647.1738 (0.18) 163935 1
test_quadkey_bench[mercantile-(1, 40, 7)] 1,599.9976 (8.00) 110,599.9982 (20.62) 1,789.4247 (6.28) 711.1950 (15.12) 1,799.9992 (6.33) 100.0008 (>1000.0) 1599;2703 558.8388 (0.16) 116280 1
test_quadkey_bench[mercantile-(486, 332, 10)] 1,999.9934 (10.00) 117,000.0032 (21.82) 2,353.1110 (8.26) 768.5591 (16.34) 2,300.0030 (8.09) 200.0015 (>1000.0) 1917;2168 424.9693 (0.12) 117648 1
test_quadkey_bench[mercantile-(486, 332, 20)] 3,199.9953 (16.00) 66,100.0013 (12.32) 3,601.3369 (12.65) 567.1348 (12.05) 3,599.9983 (12.67) 100.0080 (>1000.0) 1479;4347 277.6747 (0.08) 97088 1
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------- benchmark 'tiles': 2 tests ---------------------------------------------------------------------------------------------
Name (time in us) Min Max Mean StdDev Median IQR Outliers OPS Rounds Iterations
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_tiles_gen_bench[utiles] 239.3000 (1.0) 1,597.3000 (1.0) 308.5684 (1.0) 130.3316 (1.0) 267.2000 (1.0) 16.5000 (1.0) 312;559 3,240.7721 (1.0) 3232 1
test_tiles_gen_bench[mercantile] 1,349.9000 (5.64) 7,159.2000 (4.48) 1,798.2186 (5.83) 779.7610 (5.98) 1,526.7000 (5.71) 149.6250 (9.07) 66;111 556.1059 (0.17) 601 1
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------- benchmark 'ul': 12 tests ------------------------------------------------------------------------------------------------------
Name (time in ns) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_ul_bench[utiles-(1, 1, 1)] 204.3478 (1.0) 7,160.8697 (1.0) 263.7100 (1.0) 125.3400 (1.00) 221.7392 (1.0) 26.0868 (1.30) 17101;28014 3,792.0436 (1.0) 169492 23
test_ul_bench[utiles-(1, 0, 1)] 229.9999 (1.13) 10,579.9998 (1.48) 273.2589 (1.04) 124.7846 (1.0) 250.0001 (1.13) 20.0002 (1.0) 9266;14360 3,659.5327 (0.97) 188680 20
test_ul_bench[utiles-(1, 40, 7)] 229.9999 (1.13) 42,870.0001 (5.99) 311.4689 (1.18) 188.2129 (1.51) 255.0001 (1.15) 35.0003 (1.75) 16764;39465 3,210.5932 (0.85) 200000 20
test_ul_bench[utiles-(486, 332, 20)] 229.9999 (1.13) 65,699.9997 (9.17) 318.4368 (1.21) 243.5307 (1.95) 259.9998 (1.17) 35.0003 (1.75) 11008;36596 3,140.3404 (0.83) 178572 20
test_ul_bench[utiles-(0, 0, 0)] 299.9950 (1.47) 33,899.9962 (4.73) 349.3773 (1.32) 205.0577 (1.64) 300.0023 (1.35) 100.0008 (5.00) 618;618 2,862.2349 (0.75) 70423 1
test_ul_bench[utiles-(486, 332, 10)] 299.9950 (1.47) 57,999.9978 (8.10) 403.1283 (1.53) 400.2343 (3.21) 399.9958 (1.80) 100.0008 (5.00) 2013;20449 2,480.5998 (0.65) 192308 1
test_ul_bench[mercantile-(0, 0, 0)] 999.9931 (4.89) 206,099.9977 (28.78) 1,296.5665 (4.92) 1,201.7776 (9.63) 1,200.0019 (5.41) 100.0008 (5.00) 387;2129 771.2678 (0.20) 45872 1
test_ul_bench[mercantile-(1, 0, 1)] 999.9931 (4.89) 166,500.0018 (23.25) 1,288.3700 (4.89) 712.6090 (5.71) 1,299.9953 (5.86) 100.0008 (5.00) 2119;3450 776.1746 (0.20) 147059 1
test_ul_bench[mercantile-(1, 1, 1)] 1,000.0003 (4.89) 102,799.9970 (14.36) 1,253.0401 (4.75) 570.2565 (4.57) 1,200.0019 (5.41) 100.0008 (5.00) 2957;3697 798.0590 (0.21) 144928 1
test_ul_bench[mercantile-(1, 40, 7)] 1,000.0003 (4.89) 89,599.9983 (12.51) 1,263.1955 (4.79) 586.9464 (4.70) 1,200.0019 (5.41) 100.0008 (5.00) 1775;2965 791.6431 (0.21) 166667 1
test_ul_bench[mercantile-(486, 332, 10)] 1,099.9938 (5.38) 90,200.0029 (12.60) 1,327.0801 (5.03) 536.7494 (4.30) 1,299.9953 (5.86) 100.0008 (5.00) 6813;7956 753.5340 (0.20) 135136 1
test_ul_bench[mercantile-(486, 332, 20)] 1,099.9938 (5.38) 107,300.0021 (14.98) 1,264.2361 (4.79) 594.6154 (4.77) 1,200.0019 (5.41) 100.0008 (5.00) 1522;2265 790.9915 (0.21) 123457 1
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TODO:
- benchmark against mercantile
-
Split library into
utiles
(rust lib) andutiles-python
(python/pip package)? - Re-write cli in rust with clap?
- Maybe:
- [] Mbtiles support for the python lib??
- [] Reading/writing mvt files?
Related Tools & Resources
Mapping
- OSGeo/gdal - Geospatial Data Abstraction Library - a monster of a library
- rasterio/rasterio - pythonic GDAL bindings and much more!
- felt/tippecanoe - A tool for building vector tilesets from large collections of GeoJSON features.
- onthegomap/planetiler - Flexible tool to build planet-scale vector tilesets from OpenStreetMap data fast
- mapbox/mercantile - python map tiling library - what
utiles
started as a port of - mapbox/supermercado - mercantile extension(s) - utiles is able to do much of what supermercado can do
- turfjs/turf - A modular geospatial engine written in JavaScript and TypeScript
- maplibre/martin - PostGIS/mbtiles/pmtiles server and tile generator + mbtiles utils
Font Glyphs & Sprites
- stadiamaps/sdf_font_tools - A set of tools for generating SDF fonts for use with MapLibre/Mapbox
- jessekrubin/pbfont - js/ts font glyph decoding/encoding/combining
- flother/spreet - A tool to generate sprite sheets from SVGs
Frontend
- maplibre/maplibre-gl-js - The open-source fork of Mapbox GL JS.
- onthegomap/maplibre-contour - A MapLibre plugin for rendering contour lines
- visgl/deck.gl - WebGL2 powered visualization Framework
- visgl/react-map-gl - React + Maplibre/Mapbox
Specs
- mapbox/mbtiles-spec - The MBTiles specification
- mapbox/tilejson-spec - The TileJSON specification
- mapbox/vector-tile-spec - The vector tile specification
Reference
Definitions/Glossary
textiles: jsonl
/ndjson
text file with each line containing tile-array-json (e.g. [x, y, z]
) or tile-object-json (e.g. {x: x, y: y, z: z}
).
Definitions
yup: in the context of web-map-tiles yup
means “y-up”; z/x/y tile servers serve tiles with y-down
coordinates, while mbtiles
and geopackage
files store tiles as y-up
. Converting between y
and yup
is done by yup = 2^z - y - 1
where z
is the zoom level. Converting in a sqlite
database can be done like this:
SELECT zoom_level AS z,
tile_column AS x,
(2^zoom_level - tile_row - 1) AS y,
tile_row AS yup,
FROM tiles;
zoom-level: Map zoom level 0 - 30
tile: A tile is a square image of a specific zoom level, typically 256x256 pixels. Tiles are used to display map data at different zoom levels.
zbox: Utiles name for a tile-bounding-box at a zoom level - defines zoom, min-x, min-y, max-x, max-y for querying tiles
tilejson: A JSON object that describes a tile set, including its name, description, and the URL template for accessing tiles. TileJSON is used to provide metadata about a tile set.
textiles: utiles name for an ndjson/jsonl file containing tiles as arrays or objects (e.g. [x, y, z]
or {x: x, y: y, z: z}
)
REF
ZOOM LEVELS
zoom info
zoom | ntiles | total | rowcol_range | max_rowcol |
---|---|---|---|---|
0 | 1 | 1 | 0 | 1 |
1 | 4 | 5 | 1 | 2 |
2 | 16 | 21 | 3 | 4 |
3 | 64 | 85 | 7 | 8 |
4 | 256 | 341 | 15 | 16 |
5 | 1_024 | 1_365 | 31 | 32 |
6 | 4_096 | 5_461 | 63 | 64 |
7 | 16_384 | 21_845 | 127 | 128 |
8 | 65_536 | 87_381 | 255 | 256 |
9 | 262_144 | 349_525 | 511 | 512 |
10 | 1_048_576 | 1_398_101 | 1_023 | 1_024 |
11 | 4_194_304 | 5_592_405 | 2_047 | 2_048 |
12 | 16_777_216 | 22_369_621 | 4_095 | 4_096 |
13 | 67_108_864 | 89_478_485 | 8_191 | 8_192 |
14 | 268_435_456 | 357_913_941 | 16_383 | 16_384 |
15 | 1_073_741_824 | 1_431_655_765 | 32_767 | 32_768 |
16 | 4_294_967_296 | 5_726_623_061 | 65_535 | 65_536 |
17 | 17_179_869_184 | 22_906_492_245 | 131_071 | 131_072 |
18 | 68_719_476_736 | 91_625_968_981 | 262_143 | 262_144 |
19 | 274_877_906_944 | 366_503_875_925 | 524_287 | 524_288 |
20 | 1_099_511_627_776 | 1_466_015_503_701 | 1_048_575 | 1_048_576 |
21 | 4_398_046_511_104 | 5_864_062_014_805 | 2_097_151 | 2_097_152 |
22 | 17_592_186_044_416 | 23_456_248_059_221 | 4_194_303 | 4_194_304 |
23 | 70_368_744_177_664 | 93_824_992_236_885 | 8_388_607 | 8_388_608 |
24 | 281_474_976_710_656 | 375_299_968_947_541 | 16_777_215 | 16_777_216 |
25 | 1_125_899_906_842_624 | 1_501_199_875_790_165 | 33_554_431 | 33_554_432 |
26 | 4_503_599_627_370_496 | 6_004_799_503_160_661 | 67_108_863 | 67_108_864 |
27 | 18_014_398_509_481_984 | 24_019_198_012_642_645 | 134_217_727 | 134_217_728 |
28 | 72_057_594_037_927_936 | 96_076_792_050_570_581 | 268_435_455 | 268_435_456 |
29 | 288_230_376_151_711_744 | 384_307_168_202_282_325 | 536_870_911 | 536_870_912 |
30 | 1_152_921_504_606_846_976 | 1_537_228_672_809_129_301 | 1_073_741_823 | 1_073_741_824 |
31 | 4_611_686_018_427_387_904 | 6_148_914_691_236_517_205 | 2_147_483_647 | 2_147_483_648 |
Zoom levels
zoom ntiles total rowcol_range max_rowcol
0 0 1 1 0 1
1 1 4 5 1 2
2 2 16 21 3 4
3 3 64 85 7 8
4 4 256 341 15 16
5 5 1024 1365 31 32
6 6 4096 5461 63 64
7 7 16384 21845 127 128
8 8 65536 87381 255 256
9 9 262144 349525 511 512
10 10 1048576 1398101 1023 1024
11 11 4194304 5592405 2047 2048
12 12 16777216 22369621 4095 4096
13 13 67108864 89478485 8191 8192
14 14 268435456 357913941 16383 16384
15 15 1073741824 1431655765 32767 32768
16 16 4294967296 5726623061 65535 65536
17 17 17179869184 22906492245 131071 131072
18 18 68719476736 91625968981 262143 262144
19 19 274877906944 366503875925 524287 524288
20 20 1099511627776 1466015503701 1048575 1048576
21 21 4398046511104 5864062014805 2097151 2097152
22 22 17592186044416 23456248059221 4194303 4194304
23 23 70368744177664 93824992236885 8388607 8388608
24 24 281474976710656 375299968947541 16777215 16777216
25 25 1125899906842624 1501199875790165 33554431 33554432
26 26 4503599627370496 6004799503160661 67108863 67108864
27 27 18014398509481984 24019198012642645 134217727 134217728
28 28 72057594037927936 96076792050570581 268435455 268435456
29 29 288230376151711744 384307168202282325 536870911 536870912
30 30 1152921504606846976 1537228672809129301 1073741823 1073741824
31 31 4611686018427387904 6148914691236517205 2147483647 2147483648
json
[
{
"max_rowcol": 1,
"ntiles": 1,
"rowcol_range": 0,
"total": 1,
"zoom": 0
},
{
"max_rowcol": 2,
"ntiles": 4,
"rowcol_range": 1,
"total": 5,
"zoom": 1
},
{
"max_rowcol": 4,
"ntiles": 16,
"rowcol_range": 3,
"total": 21,
"zoom": 2
},
{
"max_rowcol": 8,
"ntiles": 64,
"rowcol_range": 7,
"total": 85,
"zoom": 3
},
{
"max_rowcol": 16,
"ntiles": 256,
"rowcol_range": 15,
"total": 341,
"zoom": 4
},
{
"max_rowcol": 32,
"ntiles": 1024,
"rowcol_range": 31,
"total": 1365,
"zoom": 5
},
{
"max_rowcol": 64,
"ntiles": 4096,
"rowcol_range": 63,
"total": 5461,
"zoom": 6
},
{
"max_rowcol": 128,
"ntiles": 16384,
"rowcol_range": 127,
"total": 21845,
"zoom": 7
},
{
"max_rowcol": 256,
"ntiles": 65536,
"rowcol_range": 255,
"total": 87381,
"zoom": 8
},
{
"max_rowcol": 512,
"ntiles": 262144,
"rowcol_range": 511,
"total": 349525,
"zoom": 9
},
{
"max_rowcol": 1024,
"ntiles": 1048576,
"rowcol_range": 1023,
"total": 1398101,
"zoom": 10
},
{
"max_rowcol": 2048,
"ntiles": 4194304,
"rowcol_range": 2047,
"total": 5592405,
"zoom": 11
},
{
"max_rowcol": 4096,
"ntiles": 16777216,
"rowcol_range": 4095,
"total": 22369621,
"zoom": 12
},
{
"max_rowcol": 8192,
"ntiles": 67108864,
"rowcol_range": 8191,
"total": 89478485,
"zoom": 13
},
{
"max_rowcol": 16384,
"ntiles": 268435456,
"rowcol_range": 16383,
"total": 357913941,
"zoom": 14
},
{
"max_rowcol": 32768,
"ntiles": 1073741824,
"rowcol_range": 32767,
"total": 1431655765,
"zoom": 15
},
{
"max_rowcol": 65536,
"ntiles": 4294967296,
"rowcol_range": 65535,
"total": 5726623061,
"zoom": 16
},
{
"max_rowcol": 131072,
"ntiles": 17179869184,
"rowcol_range": 131071,
"total": 22906492245,
"zoom": 17
},
{
"max_rowcol": 262144,
"ntiles": 68719476736,
"rowcol_range": 262143,
"total": 91625968981,
"zoom": 18
},
{
"max_rowcol": 524288,
"ntiles": 274877906944,
"rowcol_range": 524287,
"total": 366503875925,
"zoom": 19
},
{
"max_rowcol": 1048576,
"ntiles": 1099511627776,
"rowcol_range": 1048575,
"total": 1466015503701,
"zoom": 20
},
{
"max_rowcol": 2097152,
"ntiles": 4398046511104,
"rowcol_range": 2097151,
"total": 5864062014805,
"zoom": 21
},
{
"max_rowcol": 4194304,
"ntiles": 17592186044416,
"rowcol_range": 4194303,
"total": 23456248059221,
"zoom": 22
},
{
"max_rowcol": 8388608,
"ntiles": 70368744177664,
"rowcol_range": 8388607,
"total": 93824992236885,
"zoom": 23
},
{
"max_rowcol": 16777216,
"ntiles": 281474976710656,
"rowcol_range": 16777215,
"total": 375299968947541,
"zoom": 24
},
{
"max_rowcol": 33554432,
"ntiles": 1125899906842624,
"rowcol_range": 33554431,
"total": 1501199875790165,
"zoom": 25
},
{
"max_rowcol": 67108864,
"ntiles": 4503599627370496,
"rowcol_range": 67108863,
"total": 6004799503160661,
"zoom": 26
},
{
"max_rowcol": 134217728,
"ntiles": 18014398509481984,
"rowcol_range": 134217727,
"total": 24019198012642645,
"zoom": 27
},
{
"max_rowcol": 268435456,
"ntiles": 72057594037927936,
"rowcol_range": 268435455,
"total": 96076792050570581,
"zoom": 28
},
{
"max_rowcol": 536870912,
"ntiles": 288230376151711744,
"rowcol_range": 536870911,
"total": 384307168202282325,
"zoom": 29
},
{
"max_rowcol": 1073741824,
"ntiles": 1152921504606846976,
"rowcol_range": 1073741823,
"total": 1537228672809129301,
"zoom": 30
},
{
"max_rowcol": 2147483648,
"ntiles": 4611686018427387904,
"rowcol_range": 2147483647,
"total": 6148914691236517205,
"zoom": 31
}
]
CHANGELOG
0.7.4 (unreleased)
- all
allow
lints moved toexpect
- docs website
- Updated several dependencies
- several minor versions
json-patch
v4
- Clippy fixes
- useless conversions
- const functions
- pyo3 v0.24.x
- frozen py structs
0.7.3 (2025-02-11)
- minor updates and re-jiggering
0.7.2 (2025-01-14)
utiles webpify
andutiles-oxipng
commands now show correct size difference if/when the size of a tiles-db is larger than it was previously- fix axum 8 new routing paths
utiles-pyo3
children now accept kwarg boolzorder
:zorder
returns quadkey ordering:top-left
,top-right
,bottom-left
,bottom-right
- For some reason (I do not know why)
mercantile
and@mapbox/tilebelt
both return children in the order oftop-left
,top-right
,bottom-right
,bottom-left
which I call ‘d-ordering’
cli
- format string
{projwin}
and{projwin_web}
changed to return
- format string
0.7.1 (2025-01-09)
- fix axum 8 new routing paths
0.7.0 (2025-01-09)
- NO UNWRAPPING! there is no unwrapping in utiles!
- updated
thiserror
to v2 - remove
gil-refs
pyo3 feature from python lib pyo3
v0.23.x- supermercado compatible
edges
andburn
cli commands added as well a s rust lib functions (obviously) shapes
andfeature
functions for tile produce polygons that now DO follow the right-hand-rule; exterior rings are clockwisesimplify
/merge
function(s) optimized for faster merging and WAY less memory usage- Parent methods now returns
None
ifz<=0
- New command(s):
agg-hash
command that computes theagg-tiles-hash
of a tiles-db as standardized by the martin/maplibre team (this supports more hash-types;xxh3
appears to be the fastest and what utiles will likely default to if notxxh64
)commands
list all available commands (including hidden/dev/unimplemented commands)enumerate
list xyz tiles in db(s) similar totippecanoe-enumerate
; for tippecanoe compatibility use--tippecanoe
/-t
sqlite
/db
sub-command group withvac
/analyze
commands and will likely contain future pure sqlite util(e)s… these could totally be shell scripts, but they’re nice to have on das-windowsheader
/head
command that prints the json of a sqlite db header (which has come in handy for weird dbs that use old code to write out sqlite dbs (yes I have seen this))vac
/vacuum
command that vacuums a sqlite db (optionally into a new db)analyze
command that analyzes a sqlite db (basically the same as doingsqlite3 database.sqlite "PRAGMA analyze;"
)
copy
andtouch
- Now supports
flat
/norm
(normalized)/hash
(flat-with-hash) formats as standardized by the martin/maplibre people. Should also work with non-martin-conforming mbtiles schemas (appears to for me)
- Now supports
- Dev/hidden commands:
webpify
command that converts all non-webp raster-tiles to webp (lossless only due to image-crate not supporting lossy encoding…)oxipng
command that optimizes png(s) in mbtiles db(s) usingoxipng
crate
- figured out how to make async tile-stream(s)
- Removed even more
unwrap
usages - lager/logging/tracing is reloadable from python; using the new fancy
std::sync::LazyLock
(yay) - lint/copy overhaul
- Added
--page-size
to vacuum command - Using
json-patch
for metadata updates - Allow setting metadata value(s) from file if no value is provided (
-
/--
) for stdin - Figured out how to put the caller-site (eg
pyo3
in the cli help so you (likely me) can tell which utiles you are calling) - python:
- Added
TileFmts
string formatter object Lager
singleton that can toggle tracing format and level (WIP)
- Added
0.6.1 (2024-07-01)
- Fix calling
utiles.ut_cli
multiple times causing tracing-subscriber crash
0.6.0 (2024-06-28)
- Upgrade pyo3 to
v0.22.0
– had to add signatures to all fns with optional args/kwargs - Update python dev deps
- Added
{bbox}
,{projwin}
,{bbox_web}
and{projwin_web}
format tokens to tile-formatter (those projwins are handy for gdaling)
0.5.1 (2024-06-19)
- Fixed backpressure issue when
unpyramiding
directory to mbtiles; the loading of tiles was happening too fast and could cause memory issues on large tile-pyramids… (this was previously not an issue b/c I would run those jobs on my work machine which had 512gb or ram, but that machine died… RIP titus) - Write out
metadata.json
whenpyramid-ing
mbtiles to directory if the metadata of the mbtiles does not contain duplicate keys (which it should not) - Limit jobs/concurrency when
pyramid-ing
mbtiles to directory to 4 (if not specified by--jobs
/-j
option) to prevent nuking machines
0.5.0 (2024-06-14)
- Moved metadata structs and tools from
utiles-core
toutiles
utiles-python
- Refactoring and reorganizing of code
- Fixed comparison of LngLat obj
- Using rust lib for
python -m utiles
file size formatting
clippy::pedantic
- Many changes on the road to
clippy::pedantic
utiles-core
is almost fully pedanticutiles
is becoming pedanticutiles-python
is not very pedantic yet
- Many changes on the road to
- Testing:
- More tests added (mostly testing w/ python)
- Added test mbtiles file
osm-standard.0z4.mbtiles
- fmt-str command and option
--fmt
addedtiles
command; allows string formatting of json-tiles:
Format json-tiles format-string
fmt-tokens:
`{json_arr}`/`{json}` -> [x, y, z]
`{json_obj}`/`{obj}` -> {x: x, y: y, z: z}
`{quadkey}`/`{qk}` -> quadkey string
`{pmtileid}`/`{pmid}` -> pmtile-id
`{x}` -> x tile coord
`{y}` -> y tile coord
`{z}` -> z/zoom level
`{-y}`/`{yup}` -> y tile coord flipped/tms
`{zxy}` -> z/x/y
Example:
> echo "[486, 332, 10]" | utiles fmtstr
[486, 332, 10]
> echo "[486, 332, 10]" | utiles fmtstr --fmt "{x},{y},{z}"
486,332,10
> echo "[486, 332, 10]" | utiles fmt --fmt "SELECT * FROM tiles WHERE zoom_level = {z} AND tile_column = {x} AND tile_row = {y};"
SELECT * FROM tiles WHERE zoom_level = 10 AND tile_column = 486 AND tile_row = 332;
0.4.1 (2024-04-04)
- Fixed problem with python tile
__richcmp__
not handling invalid tiles and non-tile-like objs
0.4.0 (2024-03-28)
- Updated to pyo3
v0.21.0
- Cli help messages cleaned up
- General spring cleaning!
- Hid the
utiles tilejson
cli aliastrader-joes
0.3.1 (2024-01-30)
- Minor bug fixes
0.3.0 (2024-01-16)
- Expanded utiles cli with several more commands
0.2.0 (2023-11-10)
- Converted cli to rust as an exercise in learning clap
- Moved old click cli to
utiles._legacy.cli
- Added tilejson/tj command to rust cli to write out tilejson files for mbtiles
- Added meta command to rust cli to write out json of metadata table for mbtiles
0.1.0 (2023-10-27)
- Drop python 3.7 (was good knowing you)
- Update pyo3 to 0.20.0
- Added rasterio/rio entry points (‘utiles’ and ‘ut’ alias bc why type
rio utiles
overrio ut
)
0.0.2
- Added
__len__
to TilesGenerator for pbars