diff --git a/.gitignore b/.gitignore index 0f7b4fb6..a7ddff29 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /target /.vscode /gdal-sys/target +/.idea # gtags GPATH diff --git a/CHANGES.md b/CHANGES.md index 5f1b66dc..da3b4e9c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,10 @@ ## Unreleased +- Added new content to README.md and root rust docs. + + - + ## 0.13 - Add prebuild bindings for GDAL 3.5 diff --git a/README.md b/README.md new file mode 100644 index 00000000..c9037739 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# GDAL + +[![Documentation](https://docs.rs/gdal/badge.svg)](https://docs.rs/gdal) +![Build Status](https://github.com/georust/gdal/workflows/CI/badge.svg) + +[GDAL](http://gdal.org/) is a translator and processing library for various raster and vector geospatial data formats. + +This crate provides safe, idiomatic [Rust](http://www.rust-lang.org/) bindings for GDAL. + +## Capabilities + +GDAL is an incredibly powerful library. For a general understanding of its capabilities, a good place to get started is the [GDAL User-oriented documentation](https://gdal.org/user/index.html). These features include: + +* Opening raster and vector file formats for reading/writing +* Translating between file formats +* Reading and writing metadata in raster and vector datasets +* Accessing raster bands and their metadata +* Reading and writing geospatial coordinate system and projection values +* Warping (resampling and re-projecting) between coordinate systems + +## Documentation + +This crate's [API documentation](https://docs.rs/crate/gdal) is hosted on [docs.rs](https://docs.rs). + +The Rust documentation is currently a work in progress, and may not cover requisite details on parameter semantics, value interpretation, etc. +Therefore, the authoritative documentation is that of GDAL in the form of its [C](https://gdal.org/api/index.html#c-api) and [C++](https://gdal.org/api/index.html#id3) APIs. +The former is technically what this crate calls, but the latter is usually more clear and better documented. + +## Usage + +This crate provides high-level, idiomatic Rust bindings for GDAL. +To do that, it uses [`gdal-sys`](gdal-sys) internally, a low-level interface to the GDAL C library, which is generated using [`bindgen`](https://rust-lang.github.io/rust-bindgen/). +Using the `gdal-sys` crate directly is normally not needed, but it can be useful in order to call APIs that have not yet been exposed in `gdal`. + +Building this crate assumes a compatible version of GDAL is installed with the corresponding header files and shared libraries. +This repository includes pre-generated bindings for GDAL 2.4 through 3.5 (see the`gdal-sys/prebuilt-bindings` directory). +If you're compiling against a later version of GDAL, you can enable the `bindgen` feature flag to have new bindings generated on the fly. + +## Community + +This crate is part of the expansive (and expanding!) [`georust`](https://georust.org/) organization. Come join our discussions on [Discord](https://discord.gg/Fp2aape)! + +## Contributing + +This crate continues to evolve, and PRs are welcome. Make sure you are comfortable with the [Code of Conduct](CODE_OF_CONDUCT.md) and [License](LICENSE.txt) before submitting a PR. + +## License + +This library is released under the [MIT license](http://opensource.org/licenses/MIT) \ No newline at end of file diff --git a/Readme.md b/Readme.md deleted file mode 100644 index d4177ad8..00000000 --- a/Readme.md +++ /dev/null @@ -1,18 +0,0 @@ -# gdal - -[![Documentation](https://docs.rs/gdal/badge.svg)](https://docs.rs/gdal) -![Build Status](https://github.com/georust/gdal/workflows/CI/badge.svg) - -[GDAL](http://gdal.org/) bindings for [Rust](http://www.rust-lang.org/). - -So far, you can: - -* open a raster dataset for reading/writing -* get size and number of bands -* get/set projection and geo-transform -* read and write raster data -* warp between datasets -* read and write vector data -* access metadata - -Many raster and vector functions are not available. Patches welcome :) diff --git a/src/cpl.rs b/src/cpl.rs index a9e3abfe..93278b43 100644 --- a/src/cpl.rs +++ b/src/cpl.rs @@ -1,3 +1,8 @@ +//! GDAL Common Portability Library Functions +//! +//! This module provides safe access to a subset of the [GDAL CPL functions](https://gdal.org/api/cpl.html). +//! + use std::ffi::CString; use std::ptr; diff --git a/src/errors.rs b/src/errors.rs index 24a3571f..7a081f9b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,3 +1,5 @@ +//! GDAL Error Types + use libc::c_int; use thiserror::Error; diff --git a/src/lib.rs b/src/lib.rs index 90a5908a..6eed654d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,25 +1,175 @@ -//! [GDAL](http://gdal.org/) bindings for Rust. +#![crate_name = "gdal"] +#![crate_type = "lib"] +#![doc = include_str!("../README.md")] + +//! ## Examples //! -//! A high-level API to access the GDAL library, for vector and raster data. +//! ### Raster //! -//! ## Use +//! This example shows opening a raster [`Dataset`] and using a few of the data access methods. +//! The GDAL [Raster Data Model](https://gdal.org/user/raster_data_model.html) document provides +//! details on the various constructs involved, as this example only touches the surface. //! +//! ```rust, no_run +//! // `Dataset` is required for opening files. `Metadata` is required to enable reading of some +//! // general information properties, such as `description`. +//! use gdal::{Dataset, Metadata}; +//! # fn main() -> gdal::errors::Result<()> { +//! // The `Dataset::open` function is used to open all datasets, regardless of type. +//! // There's a `Dataset:open_ex` variant which provides some additional options. +//! let dataset = Dataset::open("fixtures/tinymarble.tif")?; +//! // The `description` property for a `Dataset` is often (but not necessarily) the file name +//! println!("Dataset description: {}", dataset.description()?); +//! let band_count = dataset.raster_count(); +//! println!("Number of bands: {band_count}"); +//! // Beware! In GDAL, band indexes are 1-based! +//! for i in 1..=band_count { +//! println!(" Band {i}"); +//! let band = dataset.rasterband(i)?; +//! // Depending on the file, the description field may be the empty string :( +//! println!(" Description: '{}'", band.description()?); +//! // In GDAL, all no-data values are coerced to floating point types, regardless of the +//! // underlying pixel type. +//! println!(" No-data value: {:?}", band.no_data_value()); +//! println!(" Pixel data type: {}", band.band_type()); +//! // Scale and offset are often used with integral pixel types to convert between pixel value +//! // to some physical unit (e.g. watts per square meter per steradian) +//! println!(" Scale: {:?}", band.scale()); +//! println!(" Offset: {:?}", band.offset()); +//! // In GDAL you can read arbitrary regions of the raster, and have them up- or down-sampled +//! // when the output buffer size is different from the read size. The terminology GDAL +//! // uses takes getting used to. All parameters here are in pixel coordinates. +//! // Also note, tuples are in `(x, y)`/`(cols, rows)` order. +//! // `window` is the (x, y) coordinate of the upper left corner of the region to read. +//! let window = (20, 30); +//! // `window_size` is the amount to read `(cols, rows)` +//! let window_size = (2, 3); +//! // `size` is the output buffer size. If this is different from `window_size`, then +//! // the `resample_alg` parameter below becomes relevant. +//! let size = (2, 3); +//! // Options here include `NearestNeighbor` (default), `Bilinear`, `Cubic`, etc. +//! let resample_alg = None; +//! // Note the `u8` type parameter. GDAL will convert the native pixel type to whatever is +//! // specified here... which may or may not be right for your use case! +//! let rv = band.read_as::(window, window_size, size, resample_alg)?; +//! // `Rasterband::read_as` returns a `Buffer` struct, which contains the shape of the output +//! // `(cols, rows)` and a `Vec<_>` containing the pixel values. +//! println!(" Data size: {:?}", rv.size); +//! println!(" Data values: {:?}", rv.data); +//! } +//! # Ok(()) +//! # } //! ``` -//! use std::path::Path; -//! use gdal::Dataset; -//! use gdal::vector::LayerAccess; //! -//! let dataset = Dataset::open(Path::new("fixtures/roads.geojson")).unwrap(); -//! let mut layer = dataset.layer(0).unwrap(); -//! for feature in layer.features() { -//! let highway_field = feature.field("highway").unwrap().unwrap(); -//! let geometry = feature.geometry(); -//! println!("{} {}", highway_field.into_string().unwrap(), geometry.wkt().unwrap()); +//! The resulting output is: +//! +//! ```text +//! Dataset description: fixtures/tinymarble.tif +//! Number of bands: 3 +//! Band 1 +//! Description: '' +//! No-data value: None +//! Pixel data type: 1 +//! Scale: None +//! Offset: None +//! Data size: (2, 3) +//! Data values: [47, 74, 77, 118, 98, 122] +//! Band 2 +//! Description: '' +//! No-data value: None +//! Pixel data type: 1 +//! Scale: None +//! Offset: None +//! Data size: (2, 3) +//! Data values: [50, 79, 77, 118, 95, 119] +//! Band 3 +//! Description: '' +//! No-data value: None +//! Pixel data type: 1 +//! Scale: None +//! Offset: None +//! Data size: (2, 3) +//! Data values: [71, 94, 79, 115, 77, 98] +//! ``` +//! +//! +//! ### Vector +//! +//! This example opens a vector [`Dataset`] and iterates over the various levels of structure within it. +//! The GDAL vector data model is quite sophisticated, so please refer to the GDAL +//! [Vector Data Model](https://gdal.org/user/vector_data_model.html) document for specifics. +//! +//! ```rust, no_run +//! use gdal::{Dataset, Metadata}; +//! // The `LayerAccess` trait enables reading of vector specific fields from the `Dataset`. +//! use gdal::vector::LayerAccess; +//! # fn main() -> gdal::errors::Result<()> { +//! use gdal::errors::GdalError; +//! use gdal::vector::geometry_type_to_name; +//! let dataset = Dataset::open("fixtures/roads.geojson")?; +//! println!("Dataset description: {}", dataset.description()?); +//! let layer_count = dataset.layer_count(); +//! println!("Number of layers: {layer_count}"); +//! // Unlike raster bands, layers are zero-based +//! for l in 0..layer_count { +//! // We have to get a mutable borrow on the layer because the `Layer::features` iterator +//! // requires it. +//! let mut layer = dataset.layer(l)?; +//! let feature_count = layer.feature_count(); +//! println!(" Layer {l}, name='{}', features={}", layer.name(), feature_count); +//! for feature in layer.features() { +//! // The fid is important in cases where the vector dataset is large can you +//! // need random access. +//! let fid = feature.fid().unwrap_or(0); +//! // Summarize the geometry +//! let geometry = feature.geometry(); +//! let geom_type = geometry_type_to_name(geometry.geometry_type()); +//! let geom_len = geometry.get_point_vec().len(); +//! println!(" Feature fid={fid:?}, geometry_type='{geom_type}', geometry_len={geom_len}"); +//! // Get all the available fields and print their values +//! for field in feature.fields() { +//! let name = field.0; +//! let value = field.1.and_then(|f| f.into_string()).unwrap_or("".into()); +//! println!(" {name}={value}"); +//! } +//! } //! } +//! # Ok(()) +//! # } +//! ``` +//! +//! The resulting (truncated) output looks like this: +//! +//! ```text +//! Dataset description: fixtures/roads.geojson +//! Number of layers: 1 +//! Layer 0, name='roads', features=21 +//! Feature fid=236194095, geometry_type='Line String', geometry_len=3 +//! kind=path +//! sort_key= +//! is_link=no +//! is_tunnel=no +//! is_bridge=no +//! railway= +//! highway=footway +//! Feature fid=236194098, geometry_type='Line String', geometry_len=3 +//! kind=path +//! sort_key= +//! is_link=no +//! is_tunnel=no +//! is_bridge=no +//! railway= +//! highway=footway +//! Feature fid=236194101, geometry_type='Line String', geometry_len=4 +//! kind=path +//! sort_key= +//! is_link=no +//! is_tunnel=no +//! is_bridge=no +//! railway= +//! highway=footway +//! ... //! ``` - -#![crate_name = "gdal"] -#![crate_type = "lib"] pub use version::version_info; diff --git a/src/programs/mod.rs b/src/programs/mod.rs index 72d860b8..b60d233c 100644 --- a/src/programs/mod.rs +++ b/src/programs/mod.rs @@ -1 +1,3 @@ +//! Rust implementations of [GDAL Programs](https://gdal.org/programs/index.html) + pub mod raster; diff --git a/src/spatial_ref/mod.rs b/src/spatial_ref/mod.rs index b54cbff4..3108e7ec 100644 --- a/src/spatial_ref/mod.rs +++ b/src/spatial_ref/mod.rs @@ -1,3 +1,7 @@ +//! GDAL Spatial Reference System Functions +//! +//! https://gdal.org/api/ogr_srs_api.html + mod srs; pub use gdal_sys::OGRAxisOrientation; diff --git a/src/version.rs b/src/version.rs index b44d80d0..d839cd31 100644 --- a/src/version.rs +++ b/src/version.rs @@ -1,3 +1,7 @@ +//! GDAL Version Information Functions +//! +//! See [`GDALVersionInfo`](https://gdal.org/api/raster_c_api.html#_CPPv415GDALVersionInfoPKc) for details. + use crate::utils::_string; use std::ffi::CString; diff --git a/src/vsi.rs b/src/vsi.rs index 4f1db596..df12080c 100644 --- a/src/vsi.rs +++ b/src/vsi.rs @@ -1,3 +1,9 @@ +//! GDAL Virtual File System Library Functions +//! +//! This module provides safe access to a subset of the [GDAL VSI Functions](https://gdal.org/doxygen/cpl__vsi_8h.html). +//! See [GDAL Virtual File Systems document](https://gdal.org/user/virtual_file_systems.html) for details. +//! + use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::path::{Path, PathBuf};