Quick start guide to get you up and running with OxiGDAL in minutes.
- Rust 1.85 or later
- Cargo package manager
- Git (optional, for examples)
rustc --version
cargo --versionIf not installed, follow rustup.rs
cargo new oxigdal-demo
cd oxigdal-demoAdd these to your Cargo.toml:
[dependencies]
oxigdal-core = "0.1"
oxigdal-geotiff = "0.1"
tokio = { version = "1", features = ["full"] }Create your first program by editing src/main.rs:
use oxigdal_core::io::FileDataSource;
use oxigdal_geotiff::GeoTiffReader;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("OxiGDAL Hello World!");
// Open a GeoTIFF file
let source = FileDataSource::open("sample.tif")?;
let reader = GeoTiffReader::open(source)?;
// Print basic information
println!("File: sample.tif");
println!(" Width: {} pixels", reader.width());
println!(" Height: {} pixels", reader.height());
println!(" Bands: {}", reader.band_count());
if let Some(gt) = reader.geo_transform() {
println!(" GeoTransform: {:?}", gt);
}
if let Some(epsg) = reader.epsg_code() {
println!(" EPSG Code: {}", epsg);
}
Ok(())
}Build and run:
cargo run --release
# Output:
# OxiGDAL Hello World!
# File: sample.tif
# Width: 512 pixels
# Height: 512 pixels
# Bands: 1
# GeoTransform: ...
# EPSG Code: 4326use oxigdal_core::io::FileDataSource;
use oxigdal_geotiff::GeoTiffReader;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let source = FileDataSource::open("elevation.tif")?;
let reader = GeoTiffReader::open(source)?;
// Read all tiles into a single buffer
let buffer = reader.read_tile_buffer(0, 0, 0)?;
// Get raster information
println!("Data type: {:?}", buffer.data_type());
println!("Size: {}x{}", buffer.width(), buffer.height());
// Calculate statistics
let stats = buffer.compute_statistics()?;
println!("Min: {:.2}, Max: {:.2}", stats.min, stats.max);
println!("Mean: {:.2}, StdDev: {:.2}", stats.mean, stats.std_dev);
// Access individual pixels
let pixel_value = buffer.get_pixel(100, 100)?;
println!("Pixel at (100, 100): {}", pixel_value);
Ok(())
}use oxigdal_core::io::FileDataSource;
use oxigdal_geotiff::GeoTiffReader;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let source = FileDataSource::open("large_file.tif")?;
let reader = GeoTiffReader::open(source)?;
// Read full raster
let full_buffer = reader.read_tile_buffer(0, 0, 0)?;
// Extract a window (x, y, width, height)
let window = full_buffer.window(100, 100, 256, 256)?;
println!("Window size: {}x{}", window.width(), window.height());
println!("Window mean: {}", window.compute_statistics()?.mean);
Ok(())
}fn main() -> Result<(), Box<dyn std::error::Error>> {
let source = FileDataSource::open("image.tif")?;
let reader = GeoTiffReader::open(source)?;
let buffer = reader.read_tile_buffer(0, 0, 0)?;
let mut sum = 0.0;
let mut count = 0;
// Iterate over all pixels
for pixel in buffer.iter() {
sum += pixel;
count += 1;
}
let mean = sum / count as f64;
println!("Calculated mean: {}", mean);
Ok(())
}use oxigdal_core::buffer::RasterBuffer;
use oxigdal_core::types::{RasterDataType, GeoTransform, BoundingBox};
use oxigdal_geotiff::writer::{GeoTiffWriter, GeoTiffWriterOptions};
use std::fs::File;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a simple raster
let width = 512u32;
let height = 512u32;
let mut buffer = RasterBuffer::zeros(width, height, RasterDataType::Float32);
// Fill with data
for y in 0..height {
for x in 0..width {
let value = (x as f64 / width as f64 + y as f64 / height as f64) * 100.0;
buffer.set_pixel(x, y, value)?;
}
}
// Create output file
let file = File::create("output.tif")?;
// Set up writer options
let bbox = BoundingBox::new(-180.0, -90.0, 180.0, 90.0)?;
let geo_transform = GeoTransform::from_bounds(&bbox, width, height)?;
let options = GeoTiffWriterOptions {
geo_transform: Some(geo_transform),
epsg_code: Some(4326), // WGS84
..Default::default()
};
// Write file
let writer = GeoTiffWriter::new(file, options)?;
writer.write_buffer(&buffer)?;
println!("Written output.tif");
Ok(())
}use geojson::GeoJson;
use std::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let geojson_str = fs::read_to_string("data.geojson")?;
let geojson = geojson_str.parse::<GeoJson>()?;
if let GeoJson::FeatureCollection(fc) = geojson {
println!("Features: {}", fc.features.len());
for feature in &fc.features {
if let Some(props) = &feature.properties {
println!("Properties: {:?}", props);
}
if let Some(geom) = &feature.geometry {
println!("Geometry type: {}", geom.value);
}
}
}
Ok(())
}use geo::geometry::{Point, LineString, Polygon};
use geo::{Area, Contains, Distance};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a point
let point = Point::new(0.0, 0.0);
// Create a polygon
let poly = Polygon::new(
LineString::from(vec![
(0.0, 0.0),
(10.0, 0.0),
(10.0, 10.0),
(0.0, 10.0),
(0.0, 0.0),
]),
vec![],
);
// Geometric operations
println!("Polygon area: {}", poly.unsigned_area());
println!("Contains point: {}", poly.contains(&point));
println!("Distance from point: {}", poly.exterior_ring_distance(&point));
Ok(())
}use oxigdal_core::io::FileDataSource;
use oxigdal_core::buffer::RasterBuffer;
use oxigdal_core::types::RasterDataType;
use oxigdal_geotiff::GeoTiffReader;
fn calculate_ndvi(nir_path: &str, red_path: &str)
-> Result<RasterBuffer, Box<dyn std::error::Error>>
{
// Read NIR band
let nir_source = FileDataSource::open(nir_path)?;
let nir_reader = GeoTiffReader::open(nir_source)?;
let nir = nir_reader.read_tile_buffer(0, 0, 0)?;
// Read RED band
let red_source = FileDataSource::open(red_path)?;
let red_reader = GeoTiffReader::open(red_source)?;
let red = red_reader.read_tile_buffer(0, 0, 0)?;
// Calculate NDVI
let mut ndvi = RasterBuffer::zeros(
nir.width(),
nir.height(),
RasterDataType::Float32
);
for y in 0..nir.height() {
for x in 0..nir.width() {
let n = nir.get_pixel(x, y)?;
let r = red.get_pixel(x, y)?;
let ndvi_val = (n - r) / (n + r + 1e-10);
ndvi.set_pixel(x, y, ndvi_val)?;
}
}
Ok(ndvi)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let ndvi = calculate_ndvi("nir.tif", "red.tif")?;
println!("NDVI calculated: {}x{}", ndvi.width(), ndvi.height());
Ok(())
}use oxigdal_core::io::FileDataSource;
use oxigdal_geotiff::GeoTiffReader;
use oxigdal_algorithms::resample::{Resampling, ResampleOptions};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Read input
let source = FileDataSource::open("high_res.tif")?;
let reader = GeoTiffReader::open(source)?;
let buffer = reader.read_tile_buffer(0, 0, 0)?;
// Resample to lower resolution
let options = ResampleOptions {
width: 256,
height: 256,
resampling: Resampling::Bilinear,
};
let resampled = buffer.resample(&options)?;
println!("Resampled to {}x{}", resampled.width(), resampled.height());
Ok(())
}use oxigdal_proj::Projection;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Define source and destination CRS
let from = Projection::from_epsg(4326)?; // WGS84 (lat/lon)
let to = Projection::from_epsg(3857)?; // Web Mercator
// Transform a point
let (lon, lat) = (10.0, 20.0);
let (x, y) = from.transform_point(lon, lat, &to)?;
println!("WGS84: ({}, {})", lon, lat);
println!("Web Mercator: ({}, {})", x, y);
Ok(())
}use oxigdal_cloud::backends::HttpBackend;
use oxigdal_cloud::retry::RetryConfig;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let retry_config = RetryConfig::default();
let http = HttpBackend::new(retry_config);
// Fetch remote GeoTIFF
let url = "https://example.com/data/imagery.tif";
let data = http.get(url).await?;
println!("Downloaded {} bytes", data.len());
Ok(())
}use rayon::prelude::*;
use oxigdal_core::io::FileDataSource;
use oxigdal_geotiff::GeoTiffReader;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let source = FileDataSource::open("large_image.tif")?;
let reader = GeoTiffReader::open(source)?;
let buffer = reader.read_tile_buffer(0, 0, 0)?;
// Process image in parallel tiles
let tile_size = 256u32;
let num_tiles_x = (buffer.width() + tile_size - 1) / tile_size;
let num_tiles_y = (buffer.height() + tile_size - 1) / tile_size;
let results: Vec<_> = (0..num_tiles_y)
.flat_map(|ty| (0..num_tiles_x).map(move |tx| (tx, ty)))
.par_iter()
.map(|(tx, ty)| {
let x = tx * tile_size;
let y = ty * tile_size;
let w = std::cmp::min(tile_size, buffer.width() - x);
let h = std::cmp::min(tile_size, buffer.height() - y);
// Process this tile
(x, y, w, h)
})
.collect();
println!("Processed {} tiles in parallel", results.len());
Ok(())
}All OxiGDAL operations return Result<T, OxiGdalError>. Use the ? operator for ergonomic error propagation:
fn process_file(path: &str) -> Result<(), Box<dyn std::error::Error>> {
let source = FileDataSource::open(path)?; // ? unwraps or propagates error
let reader = GeoTiffReader::open(source)?;
let buffer = reader.read_tile_buffer(0, 0, 0)?;
Ok(())
}
fn main() {
match process_file("input.tif") {
Ok(()) => println!("Success!"),
Err(e) => eprintln!("Error: {}", e),
}
}Recommended organization for larger projects:
my_gis_app/
├── Cargo.toml
├── src/
│ ├── main.rs # Application entry point
│ ├── lib.rs # Reusable library code
│ ├── raster/
│ │ ├── mod.rs
│ │ ├── processing.rs # Raster operations
│ │ └── stats.rs # Statistics
│ ├── vector/
│ │ ├── mod.rs
│ │ └── operations.rs # Vector operations
│ └── io/
│ ├── mod.rs
│ ├── readers.rs # File readers
│ └── writers.rs # File writers
├── tests/
│ └── integration_tests.rs
├── examples/
│ ├── ndvi.rs
│ ├── reproject.rs
│ └── cloud_fetch.rs
└── data/
└── sample.tif
Enable specific features for your use case:
[dependencies]
oxigdal-core = { version = "0.1", features = ["std", "arrow"] }
oxigdal-geotiff = "0.1"
oxigdal-cloud = { version = "0.1", features = ["s3", "http"] }
oxigdal-algorithms = { version = "0.1", features = ["simd"] }# Development build (faster compilation)
cargo build
# Release build (optimized for speed)
cargo build --release
# With native CPU optimizations
RUSTFLAGS="-C target-cpu=native" cargo build --release
# With SIMD support
RUSTFLAGS="-C target-feature=+avx2" cargo build --release# Run all tests
cargo test
# Run tests with output
cargo test -- --nocapture
# Run specific test
cargo test test_ndvi
# Run tests in release mode
cargo test --release
# Run tests with all features
cargo test --all-featuresPrint debugging information:
use oxigdal_core::io::FileDataSource;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let source = FileDataSource::open("image.tif")?;
// Print debug info
dbg!(&source);
Ok(())
}Run with debug output:
RUST_LOG=debug cargo run-
Read the Migration Guides
-
Explore the Examples
- Check the
examples/directory in the repository - Try the tutorial examples
- Check the
-
Learn More
-
Get Help
- Read the Troubleshooting Guide
- Check GitHub Issues
- Join COOLJAPAN Community
- Official Documentation: https://docs.rs/oxigdal
- Rust Book: https://doc.rust-lang.org/book/
- Geospatial Standards: https://www.ogc.org/
- GDAL API Reference: https://gdal.org/api/
Happy geospatial computing with OxiGDAL!