Skip to main content

oxigdal_vrt/
lib.rs

1//! OxiGDAL VRT Driver - Pure Rust VRT (Virtual Raster) Support
2//!
3//! This crate provides a pure Rust implementation of GDAL's VRT (Virtual Raster)
4//! format, enabling efficient multi-file processing and on-the-fly transformations.
5//!
6//! # VRT Format
7//!
8//! VRT (Virtual Raster) is an XML-based format that references other raster files
9//! without copying data. This enables:
10//!
11//! - **Mosaicking**: Combine multiple tiles into a single virtual dataset
12//! - **Subsetting**: Extract specific bands from multi-band rasters
13//! - **Transformation**: Apply on-the-fly scaling, offset, and pixel functions
14//! - **Windowing**: Create virtual subsets of large rasters
15//!
16//! # Features
17//!
18//! - `std` (default) - Enable standard library support
19//! - `async` - Enable async I/O support
20//!
21//! # Examples
22//!
23//! ## Create a Simple VRT Mosaic
24//!
25//! ```rust,no_run
26//! use oxigdal_vrt::VrtBuilder;
27//!
28//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
29//! let vrt = VrtBuilder::new()
30//!     .add_tile("/data/tile1.tif", 0, 0, 512, 512)?
31//!     .add_tile("/data/tile2.tif", 512, 0, 512, 512)?
32//!     .add_tile("/data/tile3.tif", 0, 512, 512, 512)?
33//!     .add_tile("/data/tile4.tif", 512, 512, 512, 512)?
34//!     .build_file("mosaic.vrt")?;
35//!
36//! println!("Created VRT: {}x{}", vrt.raster_x_size, vrt.raster_y_size);
37//! # Ok(())
38//! # }
39//! ```
40//!
41//! ## Read from a VRT
42//!
43//! ```rust,no_run
44//! use oxigdal_vrt::VrtReader;
45//!
46//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
47//! let reader = VrtReader::open("mosaic.vrt")?;
48//! println!("VRT dimensions: {}x{}", reader.width(), reader.height());
49//! println!("Bands: {}", reader.band_count());
50//!
51//! // Read a band (lazy evaluation - only reads from source files as needed)
52//! let band_data = reader.read_band(1)?;
53//! # Ok(())
54//! # }
55//! ```
56//!
57//! ## Create a Multi-Band VRT
58//!
59//! ```rust,no_run
60//! use oxigdal_vrt::{VrtBuilder, VrtBand, VrtSource, SourceFilename};
61//! use oxigdal_core::types::RasterDataType;
62//!
63//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
64//! let mut builder = VrtBuilder::with_size(1024, 1024);
65//!
66//! // Band 1: Red
67//! let red_source = VrtSource::new(SourceFilename::absolute("/data/red.tif"), 1);
68//! let red_band = VrtBand::simple(1, RasterDataType::UInt8, red_source);
69//! builder = builder.add_band(red_band)?;
70//!
71//! // Band 2: Green
72//! let green_source = VrtSource::new(SourceFilename::absolute("/data/green.tif"), 1);
73//! let green_band = VrtBand::simple(2, RasterDataType::UInt8, green_source);
74//! builder = builder.add_band(green_band)?;
75//!
76//! // Band 3: Blue
77//! let blue_source = VrtSource::new(SourceFilename::absolute("/data/blue.tif"), 1);
78//! let blue_band = VrtBand::simple(3, RasterDataType::UInt8, blue_source);
79//! builder = builder.add_band(blue_band)?;
80//!
81//! let vrt = builder.build_file("rgb.vrt")?;
82//! # Ok(())
83//! # }
84//! ```
85//!
86//! ## Use Mosaic Builder for Grid Layout
87//!
88//! ```rust,no_run
89//! use oxigdal_vrt::MosaicBuilder;
90//!
91//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
92//! let mosaic = MosaicBuilder::new(256, 256)
93//!     .add_tile("/tile_0_0.tif")?
94//!     .next_column()
95//!     .add_tile("/tile_1_0.tif")?
96//!     .next_row()
97//!     .add_tile("/tile_0_1.tif")?
98//!     .next_column()
99//!     .add_tile("/tile_1_1.tif")?
100//!     .with_srs("EPSG:4326")
101//!     .build_file("grid.vrt")?;
102//! # Ok(())
103//! # }
104//! ```
105//!
106//! # Architecture
107//!
108//! The VRT driver is organized into several modules:
109//!
110//! - [`error`] - Error types for VRT operations
111//! - [`source`] - Source raster references and windowing
112//! - [`band`] - Virtual band configuration
113//! - [`dataset`] - VRT dataset definition
114//! - [`xml`] - XML parser and writer
115//! - [`builder`] - Fluent builder API
116//! - [`reader`] - Lazy reader with caching
117//! - [`mosaic`] - Mosaicking and compositing logic
118
119#![warn(missing_docs)]
120#![warn(clippy::all)]
121// Pedantic disabled to reduce noise - default clippy::all is sufficient
122// #![warn(clippy::pedantic)]
123#![deny(clippy::unwrap_used)]
124#![cfg_attr(test, allow(clippy::expect_used))]
125#![allow(clippy::module_name_repetitions)]
126#![allow(clippy::missing_errors_doc)]
127
128pub mod band;
129pub mod builder;
130pub mod dataset;
131pub mod error;
132pub mod mosaic;
133pub mod reader;
134pub mod source;
135pub mod xml;
136
137// Re-export commonly used types
138pub use band::{ColorEntry, ColorTable, PixelFunction, VrtBand};
139pub use builder::{MosaicBuilder, VrtBuilder};
140pub use dataset::{VrtDataset, VrtMetadata, VrtSubclass};
141pub use error::{Result, VrtError};
142pub use mosaic::{BlendMode, CompositeParams, MosaicCompositor, MosaicPlanner};
143pub use reader::{SourceDataset, VrtReader};
144pub use source::{PixelRect, SourceFilename, SourceProperties, SourceWindow, VrtSource};
145pub use xml::{VrtXmlParser, VrtXmlWriter};
146
147/// Checks if data looks like a VRT file
148///
149/// # Examples
150///
151/// ```
152/// use oxigdal_vrt::is_vrt;
153///
154/// let vrt_data = b"<VRTDataset rasterXSize=\"512\" rasterYSize=\"512\">";
155/// assert!(is_vrt(vrt_data));
156///
157/// let not_vrt = b"GIF89a";
158/// assert!(!is_vrt(not_vrt));
159/// ```
160#[must_use]
161pub fn is_vrt(data: &[u8]) -> bool {
162    if data.len() < 12 {
163        return false;
164    }
165
166    // Check for XML declaration or VRTDataset tag
167    let start = std::str::from_utf8(&data[..200.min(data.len())]).unwrap_or("");
168    start.contains("<?xml") && start.contains("<VRTDataset") || start.starts_with("<VRTDataset")
169}
170
171/// VRT driver version
172pub const VERSION: &str = env!("CARGO_PKG_VERSION");
173
174/// VRT driver name
175pub const DRIVER_NAME: &str = "VRT";
176
177/// VRT driver description
178pub const DRIVER_DESCRIPTION: &str = "Virtual Raster";
179
180#[cfg(test)]
181mod tests {
182    use super::*;
183
184    #[test]
185    fn test_is_vrt() {
186        let vrt_xml =
187            b"<?xml version=\"1.0\"?>\n<VRTDataset rasterXSize=\"512\" rasterYSize=\"512\">";
188        assert!(is_vrt(vrt_xml));
189
190        let vrt_no_decl = b"<VRTDataset rasterXSize=\"512\" rasterYSize=\"512\">";
191        assert!(is_vrt(vrt_no_decl));
192
193        let not_vrt = b"GIF89a";
194        assert!(!is_vrt(not_vrt));
195
196        let tiff = b"\x49\x49\x2A\x00";
197        assert!(!is_vrt(tiff));
198    }
199
200    #[test]
201    fn test_version() {
202        assert!(!VERSION.is_empty());
203        assert_eq!(DRIVER_NAME, "VRT");
204    }
205}