This is the multi-page printable view of this section. .
Guides
Task-oriented guides for the capabilities most applications compose.
1 - Styling and band math
The same TileStyle model serves the Rust API and the example server’s query
string. Styles are validated before expensive COG reads and rendering work.
Common recipes
Natural-color RGB from three bands:
Single-band color ramp:
Percentile stretch:
Average downsampling and bilinear reprojection:
Stretch behavior
For non-U8 data, the effective value range is selected in this order:
- Explicit
rescale=min,maxvalues. - The requested
stretchmode. stretch=stddev&sigma=2.0when neither is present.
U8 RGB data keeps its 0–255 fast path. Dataset statistics come from embedded
STATISTICS_* tags when present; otherwise the highest overview is sampled
once and the estimate is memoized.
Arithmetic expressions
expression computes one derived output band. Band references are 1-indexed:
This NDVI formula is only correct when band 5 is near-infrared and band 4 is
red in the selected COG. The library does not infer spectral roles from band
numbers; verify the asset metadata and adjust the references before using the
formula. A pre-rendered STAC visual asset is not automatically suitable for
this example.
When used in a URL, percent-encode / and +:
The grammar supports finite decimal numbers, parentheses, binary +, -,
*, /, and unary -. Multiplication and division bind more tightly than
addition and subtraction. Scientific notation is not supported.
expression is mutually exclusive with bidx and color_formula, and it
accepts at most one rescale range. Nodata inputs, division by zero, and other
non-finite results become transparent pixels. Input is bounded to 4096 bytes,
256 tokens, and 128 nesting levels.
Color formulas
The supported rio-color subset applies operations from left to right:
gammasigmoidalsaturation
For example:
Percent-encode spaces when the formula is placed in a URL query string.
2 - Mosaics and STAC
The default-enabled mosaic Cargo feature adds MosaicTiler and the
MosaicSource trait; applications that do not need mosaics can disable default
features. Because that also disables proj, use
--no-default-features --features proj when general CRS transformation is
still required. The source maps a tile coordinate to assets; the tiler opens
and warps those assets, reduces overlapping pixels, and renders the composite
once.
MosaicJSON
Run the embedded example or pass a MosaicJSON file:
The parser accepts MosaicJSON 0.0.3. Its quadkey index is defined in
WebMercatorQuad; using a MosaicJSON source with WorldCRS84Quad returns a
query error.
Connect the example server to a file at startup:
Tiles are then available under /mosaic/tiles/....
Pixel selection
| Strategy | Behavior |
|---|---|
First | First valid pixel wins; stops early after the tile is fully covered. |
Highest | Maximum value in the first output band per pixel across every asset. |
Lowest | Minimum value in the first output band per pixel across every asset. |
Mean | Streaming mean of valid samples; constant memory in asset count. |
Median | Median of valid samples; retains every contributing image until completion. |
“First output band” is internal index 0; user-facing bidx values remain
1-indexed.
MosaicConfig defaults to 8 assets processed concurrently per chunk, an
opened-reader capacity of 256 in each MosaicTiler reader pool, and a hard cap
of 64 assets per requested tile. When the cap is exceeded, the tiler logs a
warning and keeps the first assets in source-provided order. Configure all
three limits through the builder:
Keep the asset cap enabled for untrusted or low-zoom indexes to prevent fetch amplification. Choose a deterministic source order when truncation would affect visual correctness.
STAC demo
Enable stac and provide all three startup settings:
The API, collection, and asset key are fixed at process startup. HTTP query parameters cannot turn the demo into an arbitrary STAC or COG proxy.
After startup, open http://127.0.0.1:8080/maplibre. When STAC is configured, the MapLibre viewer selects mosaic mode by default and lets you verify the configured collection without guessing a tile coordinate.
HTTP asset policy
The default policy allows public and private HTTP(S) assets but blocks
loopback, link-local, and cloud-metadata destinations. Use
HttpAccessPolicy::strict() for fully untrusted documents: it requires HTTPS
and also blocks private address ranges. permissive() should be reserved for
operator-controlled asset lists.
The example server uses the default policy and does not expose an environment
override. A service that accepts untrusted mosaic or STAC documents should
construct MosaicTiler itself and pass strict() through the builder as shown
above.
Presigned query strings are redacted from mosaic errors and log messages. The access policy is a URL-resolution guard, not a complete outbound proxy sandbox. Applications still own client timeouts, redirect policy, egress firewalling, document-size limits, and any logging they add around the library.
3 - Production operation
Share one cache
The default decoded-block cache budget is 512 MiB. A server with many readers
should inject the same Arc<BlockCache> into every reader and mosaic. Give
each distinct COG a stable source ID so cache entries cannot collide.
This budget covers resident decoded blocks in the cache, not total process
RSS. In-flight compressed bytes, decode and warp buffers, encoded responses,
reader metadata, and mosaic reducer state are additional memory. In particular,
Median retains every contributing image until reduction completes.
The library does not enforce a global request-concurrency limit, so a hard RSS bound cannot be derived from cache capacity alone. Bound concurrent tile requests at the server or gateway, keep per-tile asset fan-out finite, and size the container from load tests that include the largest source windows and output tile sizes you permit.
Use BlockCache::stats() to observe:
hitsandmissesdecodedandfetchedentriesresident_bytes
Useful derived signals include hit ratio, fetched-to-decoded amplification, and resident bytes divided by the configured budget.
Bound CPU work
Decode, stitch, warp, mosaic reduction, render, and encode are CPU-heavy.
They run in spawn_blocking behind CpuLimiter. Non-mosaic CogReader and
Tiler instances accept a caller-owned limiter. MosaicTiler shares one
internal limiter across its assets and final render, but does not accept the
non-mosaic limiter. Defaults follow the host’s available parallelism and clamp
zero to one permit.
Tiler::new reuses the limiter carried by its reader:
The example server’s CPU accounting depends on the path. A command-line default
COG uses separate reader-decode and tiler-render limiters, so those phases can
overlap. Lazily selected local datasets reuse one AppState limiter sized to
the larger configured value. MosaicTiler owns another shared limiter. Treat
the two environment values as component tuning, not as a universal
process-wide CPU cap. For non-mosaic readers and tilers, wire one
library-level CpuLimiter through every component that supports injection.
Current MosaicTiler owns an internal shared limiter and does not expose a
builder hook for injecting the non-mosaic limiter. A strict numeric CPU-job cap
across mixed mosaic and single-COG traffic is therefore unsupported today.
External request concurrency provides useful coarse backpressure, but is not
equivalent to one shared permit budget.
Do not lower tile concurrency preemptively. Measure P95 latency and CPU contention first; an unnecessarily small limit adds queueing to every tile.
Tune access patterns
- Increase cache capacity for multi-dataset servers or wide pan/zoom sessions.
- Prefer ZSTD-compressed COGs over DEFLATE when read latency matters.
- The example server prefetches a one-block ring by default. Set
ASYNC_GEOTIFF_PREFETCH_RING=0when extra object-store GETs are undesirable. - Keep
MosaicConfig::max_assets_per_tilebounded for untrusted indexes.
Export traces and metrics
Tiler::tile and CogReader::read_window emit tracing spans. Connect a
tracing-opentelemetry layer in the application when OTLP traces are needed.
The library intentionally takes no OpenTelemetry dependency.
Record request count, latency, error count, and the Ok(None) rate at the HTTP
or application boundary. Poll cache statistics separately for memory and
fetch behavior.
Protect remote access
Use a strict HttpAccessPolicy when mosaic or STAC documents are not trusted.
Configure credentials on an object_store instance rather than embedding them
in asset identifiers. Avoid logging raw presigned URLs at application
boundaries outside the library.