The Rust GDAL Cookbook

This book is a Rust adaptation of the excellent Python GDAL/OGR Cookbook.

First steps

The Rust GDAL bindings consist of two crates, gdal and gdal-sys. The former contains high-level, idiomatic APIs, while the latter exposes the C API almost unchanged. Since the high-level bindings are incomplete, at times you will need to drop down to gdal-sys. When that happens, a familiarity with the GDAL C API will be very useful.

And if you want to expand the gdal API, pull requests are always appreciated!

Linking with GDAL

gdal-sys does not compile GDAL from source, so it has to be available on your system.

On Linux, that usually means installing a GDAL development package (gdal-devel, libgdal-dev or gdal). If you are an advanced user, you can use the GDAL_INCLUDE_DIR, GDAL_LIB_DIR and GDAL_STATIC environment variables to control the linking.

On Windows and MacOS, you will need to acquire or build GDAL. The environment variables mentioned above work, but setting GDAL_HOME, or even using WSL, might be easier for Windows users.

Generating the bindings

The gdal crate bundles bindings for some versions of GDAL, but if you have a newer one, you can enable the bindgen feature.

Checking the GDAL version

Once you've got everything set up, run cargo add gdal and try the following code:

use gdal::version::VersionInfo;

fn main() {
    println!("{}", gdal::version_info("VERSION_NUM"));
    // 3060200
    println!("{}", VersionInfo::release_name());
    // 3.6.2
}

Setting an error handler

The following example installs an error handle and emits an error. You can notice that there is no API available in gdal, so it uses the gdal-sys crate, at the cost of a lot of ceremony.

use std::ffi::CString;

use gdal::{config, errors::CplErrType};
use gdal_sys::CPLErr;

fn error_handler(class: CplErrType, number: i32, message: &str) {
    let class = match class {
        CplErrType::None => "[NONE]",
        CplErrType::Debug => "[DEBUG]",
        CplErrType::Warning => "[WARN]",
        CplErrType::Failure => "[ERROR]",
        CplErrType::Fatal => "[FATAL]",
    };
    eprintln!("{class} [{number}] {message}");
}

fn main() {
    config::set_error_handler(error_handler);
    unsafe {
        let message = CString::new("test error").unwrap();
        gdal_sys::CPLError(CPLErr::CE_Debug, 2, message.as_ptr());
        // [DEBUG] [2] test error
    }
    config::remove_error_handler();
}

Geometry

Create a Point

use gdal::{errors, vector::Geometry};
use gdal_sys::OGRwkbGeometryType;

fn main() -> errors::Result<()> {
    let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?;
    point.add_point_2d((1198054.34, 648493.09));

    println!("{}", point.wkt()?);
    // POINT (1198054.34 648493.09)

    Ok(())
}

Create a Linestring

use gdal::{errors, vector::Geometry};
use gdal_sys::OGRwkbGeometryType;

fn main() -> errors::Result<()> {
    let mut line_string = Geometry::empty(OGRwkbGeometryType::wkbLineString)?;
    line_string.add_point_2d((1116651.439379124, 637392.6969887456));
    line_string.add_point_2d((1188804.0108498496, 652655.7409537067));
    line_string.add_point_2d((1226730.3625203592, 634155.0816022386));
    line_string.add_point_2d((1281307.30760719, 636467.6640211721));

    println!("{}", line_string.wkt()?);

    Ok(())
}

Create a Polygon

use gdal::{errors, vector::Geometry};
use gdal_sys::OGRwkbGeometryType;

fn main() -> errors::Result<()> {
    let mut ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?;
    ring.add_point_2d((1179091.1646903288, 712782.8838459781));
    ring.add_point_2d((1161053.0218226474, 667456.2684348812));
    ring.add_point_2d((1214704.933941905, 641092.8288590391));
    ring.add_point_2d((1228580.428455506, 682719.3123998424));
    ring.add_point_2d((1218405.0658121984, 721108.1805541387));
    ring.add_point_2d((1179091.1646903288, 712782.8838459781));

    let mut poly = Geometry::empty(OGRwkbGeometryType::wkbPolygon)?;
    poly.add_geometry(ring)?;

    println!("{}", poly.wkt()?);

    Ok(())
}

Create a Polygon with holes

use gdal::{errors, vector::Geometry};
use gdal_sys::OGRwkbGeometryType;

fn main() -> errors::Result<()> {
    let mut outer_ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?;
    outer_ring.add_point_2d((1154115.274565847, 686419.4442701361));
    outer_ring.add_point_2d((1154115.274565847, 653118.2574374934));
    outer_ring.add_point_2d((1165678.1866605144, 653118.2574374934));
    outer_ring.add_point_2d((1165678.1866605144, 686419.4442701361));
    outer_ring.add_point_2d((1154115.274565847, 686419.4442701361));

    let mut inner_ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?;
    inner_ring.add_point_2d((1149490.1097279799, 691044.6091080031));
    inner_ring.add_point_2d((1149490.1097279799, 648030.5761158396));
    inner_ring.add_point_2d((1191579.1097525698, 648030.5761158396));
    inner_ring.add_point_2d((1191579.1097525698, 691044.6091080031));
    inner_ring.add_point_2d((1149490.1097279799, 691044.6091080031));

    let mut poly = Geometry::empty(OGRwkbGeometryType::wkbPolygon)?;
    poly.add_geometry(outer_ring)?;
    poly.add_geometry(inner_ring)?;

    println!("{}", poly.wkt()?);

    Ok(())
}

Create a MultiPoint

use gdal::{errors, vector::Geometry};
use gdal_sys::OGRwkbGeometryType;

fn main() -> errors::Result<()> {
    let mut multi_point = Geometry::empty(OGRwkbGeometryType::wkbMultiPoint)?;

    let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?;
    point.add_point_2d((1251243.7361610543, 598078.7958668759));
    multi_point.add_geometry(point)?;

    let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?;
    point.add_point_2d((1240605.8570339603, 601778.9277371694));
    multi_point.add_geometry(point)?;

    let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?;
    point.add_point_2d((1250318.7031934808, 606404.0925750365));
    multi_point.add_geometry(point)?;

    println!("{}", multi_point.wkt()?);

    Ok(())
}

Create a MultiPolygon

use gdal::{errors, vector::Geometry};
use gdal_sys::OGRwkbGeometryType;

fn main() -> errors::Result<()> {
    let mut multi_polygon = Geometry::empty(OGRwkbGeometryType::wkbMultiPolygon)?;

    let mut ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?;
    ring.add_point_2d((1204067.0548148106, 634617.5980860253));
    ring.add_point_2d((1204067.0548148106, 620742.1035724243));
    ring.add_point_2d((1215167.4504256917, 620742.1035724243));
    ring.add_point_2d((1215167.4504256917, 634617.5980860253));
    ring.add_point_2d((1204067.0548148106, 634617.5980860253));

    let mut poly = Geometry::empty(OGRwkbGeometryType::wkbPolygon)?;
    poly.add_geometry(ring)?;
    multi_polygon.add_geometry(poly)?;

    let mut ring = Geometry::empty(OGRwkbGeometryType::wkbLinearRing)?;
    ring.add_point_2d((1179553.6811741155, 647105.5431482664));
    ring.add_point_2d((1179553.6811741155, 626292.3013778647));
    ring.add_point_2d((1194354.20865529, 626292.3013778647));
    ring.add_point_2d((1194354.20865529, 647105.5431482664));
    ring.add_point_2d((1179553.6811741155, 647105.5431482664));

    let mut poly = Geometry::empty(OGRwkbGeometryType::wkbPolygon)?;
    poly.add_geometry(ring)?;
    multi_polygon.add_geometry(poly)?;

    println!("{}", multi_polygon.wkt()?);

    Ok(())
}

Create a GeometryCollection

use gdal::{errors, vector::Geometry};
use gdal_sys::OGRwkbGeometryType;

fn main() -> errors::Result<()> {
    let mut geometry_collection = Geometry::empty(OGRwkbGeometryType::wkbGeometryCollection)?;

    let mut point = Geometry::empty(OGRwkbGeometryType::wkbPoint)?;
    point.add_point_2d((-122.23, 47.09));
    geometry_collection.add_geometry(point)?;

    let mut line_string = Geometry::empty(OGRwkbGeometryType::wkbLineString)?;
    line_string.add_point_2d((-122.60, 47.14));
    line_string.add_point_2d((-122.48, 47.23));
    geometry_collection.add_geometry(line_string)?;

    println!("{}", geometry_collection.wkt()?);

    Ok(())
}

Create a Geometry from WKT

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkt = "POINT (1120351.5712494177 741921.4223245403)";
    let point = Geometry::from_wkt(&wkt)?;

    let (x, y, _) = point.get_point(0);
    println!("{x} {y}");
    // 1120351.5712494177 741921.4223245403

    Ok(())
}

Create a Geometry from GeoJSON

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkt = r#"{"type":"Point","coordinates":[108420.33,753808.59]}"#;
    let point = Geometry::from_geojson(&wkt)?;

    let (x, y, _) = point.get_point(0);
    println!("{x} {y}");
    // 108420.33 753808.59

    Ok(())
}

Create a Geometry from GML

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkt = r#"<gml:Point xmlns:gml="http://www.opengis.net/gml"><gml:coordinates>108420.33,753808.59</gml:coordinates></gml:Point>""#;
    let point = Geometry::from_gml(&wkt)?;

    let (x, y, _) = point.get_point(0);
    println!("{x} {y}");
    // 108420.33 753808.59

    Ok(())
}

Create a Geometry from WKB

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkb = [
        0x00, 0x80, 0x00, 0x00, 0x01, 0x41, 0x32, 0x47, 0xe6, 0x57, 0x0a, 0x3d, 0x71, 0x41, 0x23,
        0xca, 0x5a, 0x2e, 0x14, 0x7a, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    ];
    let point = Geometry::from_wkb(&wkb)?;

    let (x, y, _) = point.get_point(0);
    println!("{x} {y}");
    // 1198054.34 648493.09

    Ok(())
}

Count points in a Geometry

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkt = "LINESTRING (1181866.263593049 615654.4222507705, 1205917.1207499576 623979.7189589312, 1227192.8790041457 643405.4112779726, 1224880.2965852122 665143.6860159477)";
    let line_string = Geometry::from_wkt(&wkt)?;

    let count = line_string.point_count();
    println!("Geometry has {count} points");
    // Geometry has 4 points

    Ok(())
}

Count geometries in a Geometry

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkt = "MULTIPOINT (1181866.263593049 615654.4222507705, 1205917.1207499576 623979.7189589312, 1227192.8790041457 643405.4112779726, 1224880.2965852122 665143.6860159477)";
    let points = Geometry::from_wkt(&wkt)?;

    let count = points.geometry_count();
    println!("Geometry has {count} geometries");
    // Geometry has 4 geometries

    Ok(())
}

Buffer a Geometry

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkt = "POINT (1198054.34 648493.09)";
    let point = Geometry::from_wkt(&wkt)?;

    let distance = 500.0;
    let poly = point.buffer(distance, 2)?;
    let poly_wkt = poly.wkt()?;
    println!("{wkt} buffered by {distance} is {poly_wkt}");
    // POINT (1198054.34 648493.09) buffered by 500 is POLYGON ((1198554.34 648493.09,1198407.89339059 648139.536609407,1198054.34 647993.09,1197700.78660941 648139.536609407,1197554.34 648493.09,1197700.78660941 648846.643390593,1198054.34 648993.09,1198407.89339059 648846.643390593,1198554.34 648493.09))

    Ok(())
}

Compute the area of a Geometry

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkt = "POLYGON ((1162440.5712740074 672081.4332727483, 1162440.5712740074 647105.5431482664, 1195279.2416228633 647105.5431482664, 1195279.2416228633 672081.4332727483, 1162440.5712740074 672081.4332727483))";
    let poly = Geometry::from_wkt(&wkt)?;

    let area = poly.area();
    println!("Area: {area:.2}");
    // 820175022.47

    Ok(())
}

Compute the length of a Geometry

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkt = "LINESTRING (1181866.263593049 615654.4222507705, 1205917.1207499576 623979.7189589312, 1227192.8790041457 643405.4112779726, 1224880.2965852122 665143.6860159477)";
    let line_string = Geometry::from_wkt(&wkt)?;

    let length = line_string.length();
    println!("Length: {length:.2}");
    // Length: 76121.94

    Ok(())
}

Get the type of a Geometry as a string

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkts = [
        "POINT (1198054.34 648493.09)",
        "LINESTRING (1181866.263593049 615654.4222507705, 1205917.1207499576 623979.7189589312, 1227192.8790041457 643405.4112779726, 1224880.2965852122 665143.6860159477)",
        "POLYGON ((1162440.5712740074 672081.4332727483, 1162440.5712740074 647105.5431482664, 1195279.2416228633 647105.5431482664, 1195279.2416228633 672081.4332727483, 1162440.5712740074 672081.4332727483))"
    ];

    for wkt in wkts {
        let geom = Geometry::from_wkt(wkt)?;
        println!("{}", geom.geometry_name());
    }
    // POINT
    // LINESTRING
    // POLYGON

    Ok(())
}

Compute the intersection of two Geometries

use gdal::{errors, vector::Geometry};

fn main() -> errors::Result<()> {
    let wkt_1 = "POLYGON ((1208064.271243039 624154.6783778917, 1208064.271243039 601260.9785661874, 1231345.9998651114 601260.9785661874, 1231345.9998651114 624154.6783778917, 1208064.271243039 624154.6783778917))";
    let wkt_2 = "POLYGON ((1199915.6662253144 633079.3410163528, 1199915.6662253144 614453.958118695, 1219317.1067437078 614453.958118695, 1219317.1067437078 633079.3410163528, 1199915.6662253144 633079.3410163528)))";

    let poly_1 = Geometry::from_wkt(wkt_1)?;
    let poly_2 = Geometry::from_wkt(wkt_2)?;
    if let Some(intersection) = poly_1.intersection(&poly_2) {
        let wkt = intersection.wkt()?;
        println!("{}", wkt);
    }
    // POLYGON ((1208064.27124304 624154.678377892,1219317.10674371 624154.678377892,1219317.10674371 614453.958118695,1208064.27124304 614453.958118695,1208064.27124304 624154.678377892))

    Ok(())
}