Skip to main content

oxigdal_node/
lib.rs

1//! Node.js bindings for OxiGDAL
2//!
3//! This crate provides comprehensive Node.js bindings for the OxiGDAL ecosystem,
4//! enabling pure Rust geospatial processing from JavaScript/TypeScript with
5//! zero-copy Buffer integration and full async/await support.
6//!
7//! # Features
8//!
9//! - **Raster I/O**: Read and write GeoTIFF, COG, and other raster formats
10//! - **Vector I/O**: GeoJSON support with full geometry operations
11//! - **Algorithms**: Resampling, terrain analysis, calculator, statistics
12//! - **Async/Await**: Promise-based async operations for I/O and processing
13//! - **Buffer Integration**: Zero-copy data transfer with Node.js Buffers
14//! - **TypeScript**: Comprehensive TypeScript definitions included
15//!
16//! # Example Usage
17//!
18//! ```javascript
19//! const oxigdal = require('@oxigdal/node');
20//!
21//! // Open a raster file
22//! const dataset = oxigdal.openRaster('input.tif');
23//! console.log(`Size: ${dataset.width}x${dataset.height}`);
24//!
25//! // Read a band
26//! const band = dataset.readBand(0);
27//! const stats = band.statistics();
28//! console.log(`Mean: ${stats.mean}, StdDev: ${stats.stddev}`);
29//!
30//! // Compute hillshade
31//! const hillshade = oxigdal.hillshade(band, 315, 45, 1.0);
32//!
33//! // Save result
34//! const output = oxigdal.createRaster(dataset.width, dataset.height, 1, 'uint8');
35//! output.writeBand(0, hillshade);
36//! output.save('hillshade.tif');
37//! ```
38//!
39//! # Async Example
40//!
41//! ```javascript
42//! const oxigdal = require('@oxigdal/node');
43//!
44//! async function processRaster() {
45//!   const dataset = await oxigdal.openRasterAsync('input.tif');
46//!   const band = dataset.readBand(0);
47//!   const slope = await oxigdal.slopeAsync(band, 1.0, false);
48//!
49//!   const output = oxigdal.createRaster(dataset.width, dataset.height, 1, 'float32');
50//!   output.writeBand(0, slope);
51//!   await oxigdal.saveRasterAsync(output, 'slope.tif');
52//! }
53//!
54//! processRaster().catch(console.error);
55//! ```
56
57#![warn(missing_docs)]
58#![warn(clippy::all)]
59#![deny(clippy::unwrap_used)]
60#![allow(clippy::module_name_repetitions)]
61
62mod algorithms;
63mod async_ops;
64mod buffer;
65mod error;
66mod raster;
67mod vector;
68
69use napi_derive::napi;
70
71/// Returns the version of OxiGDAL
72#[napi]
73pub fn version() -> String {
74    oxigdal_core::VERSION.to_string()
75}
76
77/// Returns the OxiGDAL name
78#[napi]
79pub fn name() -> String {
80    "OxiGDAL Node.js Bindings".to_string()
81}
82
83/// Module information
84#[napi(object)]
85pub struct ModuleInfo {
86    /// Version string
87    pub version: String,
88    /// Module name
89    pub name: String,
90    /// Build information
91    pub build_info: String,
92    /// Supported formats
93    pub formats: Vec<String>,
94}
95
96/// Returns module information
97#[napi]
98pub fn get_info() -> ModuleInfo {
99    ModuleInfo {
100        version: oxigdal_core::VERSION.to_string(),
101        name: "OxiGDAL Node.js Bindings".to_string(),
102        build_info: format!(
103            "Built with Rust {} on {}",
104            env!("CARGO_PKG_RUST_VERSION"),
105            std::env::consts::OS
106        ),
107        formats: vec![
108            "GeoTIFF".to_string(),
109            "COG".to_string(),
110            "GeoJSON".to_string(),
111        ],
112    }
113}
114
115/// Data type constants
116#[napi(object)]
117pub struct DataTypes {
118    /// Unsigned 8-bit integer
119    pub uint8: String,
120    /// Signed 16-bit integer
121    pub int16: String,
122    /// Unsigned 16-bit integer
123    pub uint16: String,
124    /// Signed 32-bit integer
125    pub int32: String,
126    /// Unsigned 32-bit integer
127    pub uint32: String,
128    /// 32-bit floating point
129    pub float32: String,
130    /// 64-bit floating point
131    pub float64: String,
132}
133
134/// Returns available data types
135#[napi]
136pub fn get_data_types() -> DataTypes {
137    DataTypes {
138        uint8: "uint8".to_string(),
139        int16: "int16".to_string(),
140        uint16: "uint16".to_string(),
141        int32: "int32".to_string(),
142        uint32: "uint32".to_string(),
143        float32: "float32".to_string(),
144        float64: "float64".to_string(),
145    }
146}
147
148/// Resampling method constants
149#[napi(object)]
150pub struct ResamplingMethods {
151    /// Nearest neighbor (fast, preserves exact values)
152    pub nearest_neighbor: String,
153    /// Bilinear interpolation (smooth, good for continuous data)
154    pub bilinear: String,
155    /// Bicubic interpolation (high quality, slower)
156    pub bicubic: String,
157    /// Lanczos resampling (highest quality, expensive)
158    pub lanczos: String,
159}
160
161/// Returns available resampling methods
162#[napi]
163pub fn get_resampling_methods() -> ResamplingMethods {
164    ResamplingMethods {
165        nearest_neighbor: "NearestNeighbor".to_string(),
166        bilinear: "Bilinear".to_string(),
167        bicubic: "Bicubic".to_string(),
168        lanczos: "Lanczos".to_string(),
169    }
170}
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175
176    #[test]
177    fn test_version() {
178        let ver = version();
179        assert!(!ver.is_empty());
180    }
181
182    #[test]
183    fn test_info() {
184        let info = get_info();
185        assert!(!info.version.is_empty());
186        assert!(!info.formats.is_empty());
187    }
188
189    #[test]
190    fn test_data_types() {
191        let types = get_data_types();
192        assert_eq!(types.uint8, "uint8");
193        assert_eq!(types.float32, "float32");
194    }
195}