Skip to content

This is the multi-page printable view of this section. .

Return to the regular view of this page.

Get started

Install dependencies, run the example server, and render a tile through the library.

Follow the shortest path from a fresh checkout to a visible map tile.

1 - Requirements

Rust, system libraries, and optional documentation tooling.

Library and examples

  • Rust 1.88 or newer, matching Cargo.toml.
  • The default feature set requires system libproj 9.x.
  • Git is required when working from the repository.

On macOS:

brew install proj

On Debian or Ubuntu:

sudo apt install libproj-dev libsqlite3-dev libtiff-dev clang

On other platforms, install libproj with the platform’s supported package manager or build without the default features. The project does not currently provide platform-specific Windows installation commands.

If you only need same-CRS tiles or the built-in EPSG:4326 ↔ EPSG:3857 fast path, build without the default features:

cargo build --no-default-features

Documentation site

The OINK site under website/ requires Go 1.27 or newer and Hugo Extended 0.165.0 or newer. Hugo must report extended in its version string.

go version
hugo version

The library itself does not depend on Hugo or Go.

2 - Quick start

Run the example server and request your first rendered tile.

Clone and run

git clone https://github.com/mapseekai/async-geotiff-rs.git
cd async-geotiff-rs
COG_URL='https://raw.githubusercontent.com/cogeotiff/rio-tiler/0b08b7f35a8b639cee2f35a0cb565034f7b55bfd/tests/fixtures/cog.tif'
cargo run --release --example serve -- "$COG_URL"

The pinned 800 KiB rio-tiler fixture is a public, range-capable COG intended for tests and first-run verification. Replace it with your own COG after the smoke test. The server listens on 127.0.0.1:8080 by default and prints the available viewer and tile URLs when startup completes.

Open one of the included viewers:

The viewer automatically centers on the opened dataset and is the most reliable visual smoke test. You can also request the world tile directly:

curl --fail --output tile.png \
  'http://127.0.0.1:8080/tiles/WebMercatorQuad/0/0/0.png'

Success produces a PNG file that you can open in any image viewer. A valid tile coordinate outside the source extent returns HTTP 204 instead of a synthetic blank image; if that happens, use one of the included viewers to request an in-bounds tile at the dataset’s calculated center and zoom.

Browse local files

Run the server without a URL to discover data/*.tif and data/*.tiff files:

mkdir -p data
cp /path/to/example.tif data/
cargo run --release --example serve

The viewers then display a dataset switcher.

Optional formats

PNG is always available. Enable WebP and JPEG explicitly:

cargo run --release --features webp,jpeg --example serve -- \
  https://example.com/cog.tif

The /formats endpoint reports only the encoders compiled into the running binary.

3 - Library usage

Open a COG and render a tile directly from Rust.

The repository currently sets publish = false, so another local project uses a path dependency while developing. Create the application next to the clone, then replace the relative path if your directories differ:

# Starting inside the async-geotiff-rs checkout:
cd ..
cargo new async-geotiff-demo
cd async-geotiff-demo
[dependencies]
async-geotiff = { path = "../async-geotiff-rs" }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

To avoid the system libproj dependency while retaining the mosaic APIs used by the example server, set default-features = false, features = ["mosaic"] on the path dependency. General CRS transformations will then be unavailable.

Render one tile

use std::sync::Arc;

use async_geotiff::io::cog::CogReader;
use async_geotiff::style::TileStyle;
use async_geotiff::tiler::Tiler;
use async_geotiff::tms::{TileCoord, TileMatrixSet};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let url = "https://raw.githubusercontent.com/cogeotiff/rio-tiler/0b08b7f35a8b639cee2f35a0cb565034f7b55bfd/tests/fixtures/cog.tif";
    let reader = Arc::new(
        CogReader::builder()
            .source_id(url)
            .open_http(url)
            .await?,
    );
    let tiler = Tiler::new(reader);
    let style = TileStyle::from_query("colormap_name=viridis&rescale=0,3000")?;
    let coord = TileCoord {
        tms: TileMatrixSet::WebMercatorQuad,
        z: 0,
        x: 0,
        y: 0,
    };

    if let Some(bytes) = tiler.tile(coord, &style).await? {
        std::fs::write("tile.png", bytes)?;
    } else {
        eprintln!("tile is outside the dataset or projection domain");
    }
    Ok(())
}

TileStyle::from_query accepts the same query string used by the example HTTP server, without the leading ?. Save the example as src/main.rs, then run cargo run. The pinned URL is a small, range-capable test COG; replace it after verifying the integration.

Share memory and CPU budgets

For multiple COGs, create one block cache and give every reader a stable, distinct source ID:

use std::sync::Arc;

use async_geotiff::io::block_cache::BlockCache;
use async_geotiff::io::cache::CacheConfig;
use async_geotiff::io::cog::CogReader;

let cache = Arc::new(BlockCache::new(CacheConfig::default()));

let first = CogReader::builder()
    .source_id("scene-a")
    .block_cache(Arc::clone(&cache))
    .open_http("https://example.com/a.tif")
    .await?;

let second = CogReader::builder()
    .source_id("scene-b")
    .block_cache(Arc::clone(&cache))
    .open_http("https://example.com/b.tif")
    .await?;

Readers with the same cache share its default 512 MiB budget. The source ID is part of the cache key: reuse it only for the same logical COG.