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)

GitHub crates.io version crates.io version PyPI PyPI - Python Version PyPI - Wheel

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

py-utiles


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
zoomntilestotalrowcol_rangemax_rowcol
01101
14512
2162134
3648578
42563411516
51_0241_3653132
64_0965_4616364
716_38421_845127128
865_53687_381255256
9262_144349_525511512
101_048_5761_398_1011_0231_024
114_194_3045_592_4052_0472_048
1216_777_21622_369_6214_0954_096
1367_108_86489_478_4858_1918_192
14268_435_456357_913_94116_38316_384
151_073_741_8241_431_655_76532_76732_768
164_294_967_2965_726_623_06165_53565_536
1717_179_869_18422_906_492_245131_071131_072
1868_719_476_73691_625_968_981262_143262_144
19274_877_906_944366_503_875_925524_287524_288
201_099_511_627_7761_466_015_503_7011_048_5751_048_576
214_398_046_511_1045_864_062_014_8052_097_1512_097_152
2217_592_186_044_41623_456_248_059_2214_194_3034_194_304
2370_368_744_177_66493_824_992_236_8858_388_6078_388_608
24281_474_976_710_656375_299_968_947_54116_777_21516_777_216
251_125_899_906_842_6241_501_199_875_790_16533_554_43133_554_432
264_503_599_627_370_4966_004_799_503_160_66167_108_86367_108_864
2718_014_398_509_481_98424_019_198_012_642_645134_217_727134_217_728
2872_057_594_037_927_93696_076_792_050_570_581268_435_455268_435_456
29288_230_376_151_711_744384_307_168_202_282_325536_870_911536_870_912
301_152_921_504_606_846_9761_537_228_672_809_129_3011_073_741_8231_073_741_824
314_611_686_018_427_387_9046_148_914_691_236_517_2052_147_483_6472_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

CommandDescription
aboutEcho info about utiles
agg-hashAggregate tile hashes for tiles-db
bounding-tileEcho bounding tile at zoom for bbox / geojson
burnBurn tiles from GeoJSON stream at zoom level (tile coverage)
childrenEcho children tiles of input tiles
commandslist all commands
copyCopy tiles from src -> dst
dbcontainsDetermine if mbtiles contains a latlong
devDevelopment/Playground command (hidden)
edgesEcho edge tiles from stream of xyz tiles
enumerateEnumerate tiles db
fmtstrFormat json-tiles [x, y, z] tiles w/ format-string
infoEcho mbtiles info/stats
lintLint mbtiles file(s) (wip)
mergeMerge tiles from stream removing parent tiles if children are present
metadataEcho metadata (table) as json arr/obj
metadata-setSet metadata key/value or from json file if key is fspath
neighborsEcho the neighbor tiles for input tiles
optimizeOptimize tiles-db
parentEcho parent tile of input tiles
pmtileidConverts tile(s) to/from pmtile-id/[x, y, z]
quadkeyConverts tiles to/from quadkey/[x, y, z]
rimrafrm-rf dirpath
serveutiles server (wip)
shapesEcho tiles as GeoJSON feature collections/sequences
sqlitesqlite utils/cmds
tilejsonEcho the tile.json for mbtiles file
tilesEcho tiles at zoom intersecting geojson bbox / feature / collection
touchCreate new mbtiles db w/ schema
updateUpdate mbtiles db
vacuumvacuum sqlite db inplace/into
webpifyConvert raster mbtiles to webp format
zxyifyzxyify/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)

PyPI Python Version from PEP 621 TOML Wheel

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) and utiles-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

Frontend

Specs

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
zoomntilestotalrowcol_rangemax_rowcol
01101
14512
2162134
3648578
42563411516
51_0241_3653132
64_0965_4616364
716_38421_845127128
865_53687_381255256
9262_144349_525511512
101_048_5761_398_1011_0231_024
114_194_3045_592_4052_0472_048
1216_777_21622_369_6214_0954_096
1367_108_86489_478_4858_1918_192
14268_435_456357_913_94116_38316_384
151_073_741_8241_431_655_76532_76732_768
164_294_967_2965_726_623_06165_53565_536
1717_179_869_18422_906_492_245131_071131_072
1868_719_476_73691_625_968_981262_143262_144
19274_877_906_944366_503_875_925524_287524_288
201_099_511_627_7761_466_015_503_7011_048_5751_048_576
214_398_046_511_1045_864_062_014_8052_097_1512_097_152
2217_592_186_044_41623_456_248_059_2214_194_3034_194_304
2370_368_744_177_66493_824_992_236_8858_388_6078_388_608
24281_474_976_710_656375_299_968_947_54116_777_21516_777_216
251_125_899_906_842_6241_501_199_875_790_16533_554_43133_554_432
264_503_599_627_370_4966_004_799_503_160_66167_108_86367_108_864
2718_014_398_509_481_98424_019_198_012_642_645134_217_727134_217_728
2872_057_594_037_927_93696_076_792_050_570_581268_435_455268_435_456
29288_230_376_151_711_744384_307_168_202_282_325536_870_911536_870_912
301_152_921_504_606_846_9761_537_228_672_809_129_3011_073_741_8231_073_741_824
314_611_686_018_427_387_9046_148_914_691_236_517_2052_147_483_6472_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 to expect
  • 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 and utiles-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 bool zorder:
    • 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 of top-left, top-right, bottom-right, bottom-left which I call ‘d-ordering’
  • cli
    • format string {projwin} and {projwin_web} changed to return space separated coords

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 and burn cli commands added as well a s rust lib functions (obviously)
  • shapes and feature functions for tile produce polygons that now DO follow the right-hand-rule; exterior rings are clockwise
  • simplify/merge function(s) optimized for faster merging and WAY less memory usage
  • Parent methods now returns None if z<=0
  • New command(s):
    • agg-hash command that computes the agg-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 not xxh64)
    • commands list all available commands (including hidden/dev/unimplemented commands)
    • enumerate list xyz tiles in db(s) similar to tippecanoe-enumerate; for tippecanoe compatibility use --tippecanoe/-t
    • sqlite/db sub-command group with vac/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-windows
      • header/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 doing sqlite3 database.sqlite "PRAGMA analyze;")
  • copy and touch
    • 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)
  • 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) using oxipng 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)

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 when pyramid-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 to utiles
  • 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 pedantic
    • utiles is becoming pedantic
    • utiles-python is not very pedantic yet
  • Testing:
    • More tests added (mostly testing w/ python)
    • Added test mbtiles file osm-standard.0z4.mbtiles
  • fmt-str command and option --fmt added tiles 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 alias trader-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 over rio ut)

0.0.2

  • Added __len__ to TilesGenerator for pbars