diff --git a/CHANGES.md b/CHANGES.md index a5a31b79..6f4541a6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,9 @@ ## Unreleased +- Added `no_data_value_u64`, `set_no_data_value_u64`, `no_data_value_i64` and `set_no_data_value_i64` to `RasterBand`. + - + - **Breaking** Removed `RasterCreationOption`and replaced usages of `[RasterCreationOption]` with `RasterCreationOptions`, a type alias for `CplStringList`. - diff --git a/src/raster/rasterband.rs b/src/raster/rasterband.rs index 105dab87..693aefa9 100644 --- a/src/raster/rasterband.rs +++ b/src/raster/rasterband.rs @@ -685,7 +685,7 @@ impl<'a> RasterBand<'a> { None } - /// Set the no data value of this band. + /// Sets the no-data value of this band. /// /// If `no_data` is `None`, any existing no-data value is deleted. pub fn set_no_data_value(&mut self, no_data: Option) -> Result<()> { @@ -702,6 +702,101 @@ impl<'a> RasterBand<'a> { } } + /// Fetch the no-data value for this band. + /// + /// This method should ONLY be called on bands whose data type is `UInt64`. + /// + /// The no data value returned is 'raw', meaning that it has no offset and scale applied. + /// + /// # Returns + /// No-data value as `Some(i64)` if no-data value exists, `None` otherwise. + /// + /// # Notes + /// See also: [`GDALGetRasterNoDataValueAsUInt64`](https://gdal.org/api/raster_c_api.html#_CPPv432GDALGetRasterNoDataValueAsUInt6415GDALRasterBandHPi) + #[cfg(all(major_ge_3, minor_ge_5))] + pub fn no_data_value_u64(&self) -> Option { + let mut pb_success = 1; + let no_data = unsafe { + gdal_sys::GDALGetRasterNoDataValueAsUInt64(self.c_rasterband, &mut pb_success) + }; + if pb_success == 1 { + return Some(no_data); + } + None + } + + /// Sets the no-data value for a `UInt64` band. + /// + /// This method should ONLY be called on bands whose data type is `UInt64`. + /// + /// If `no_data` is `None`, any existing no-data value is deleted. + /// + /// # Notes + /// See also: + /// [`GDALSetRasterNoDataValueAsUInt64`](https://gdal.org/api/raster_c_api.html#_CPPv432GDALSetRasterNoDataValueAsUInt6415GDALRasterBandH8uint64_t), + /// [`GDALDeleteRasterNoDataValue`](https://gdal.org/api/raster_c_api.html#_CPPv427GDALDeleteRasterNoDataValue15GDALRasterBandH) + #[cfg(all(major_ge_3, minor_ge_5))] + pub fn set_no_data_value_u64(&mut self, no_data: Option) -> Result<()> { + let rv = if let Some(no_data) = no_data { + unsafe { gdal_sys::GDALSetRasterNoDataValueAsUInt64(self.c_rasterband, no_data) } + } else { + unsafe { gdal_sys::GDALDeleteRasterNoDataValue(self.c_rasterband) } + }; + + if rv != CPLErr::CE_None { + Err(_last_cpl_err(rv)) + } else { + Ok(()) + } + } + + /// Fetch the no-data value for this band. + /// + /// This method should ONLY be called on bands whose data type is `Int64`. + /// + /// The no data value returned is 'raw', meaning that it has no offset and scale applied. + /// + /// # Returns + /// No-data value as `Some(i64)` if no-data value exists, `None` otherwise. + /// + /// # Notes + /// See also: [`GDALGetRasterNoDataValueAsInt64`](https://gdal.org/api/gdalrasterband_cpp.html#_CPPv4N14GDALRasterBand21GetNoDataValueAsInt64EPi) + #[cfg(all(major_ge_3, minor_ge_5))] + pub fn no_data_value_i64(&self) -> Option { + let mut pb_success = 1; + let no_data = unsafe { + gdal_sys::GDALGetRasterNoDataValueAsInt64(self.c_rasterband, &mut pb_success) + }; + if pb_success == 1 { + return Some(no_data); + } + None + } + + /// Sets the no-data value for a `Int64` band. + /// + /// This method should ONLY be called on bands whose data type is `Int64`. + /// + /// If `no_data` is `None`, any existing no-data value is deleted. + /// + /// # Notes + /// See also: + /// [`GDALSetRasterNoDataValueAsInt64`](https://gdal.org/api/raster_c_api.html#_CPPv431GDALSetRasterNoDataValueAsInt6415GDALRasterBandH7int64_t), + /// [`GDALDeleteRasterNoDataValue`](https://gdal.org/api/raster_c_api.html#_CPPv427GDALDeleteRasterNoDataValue15GDALRasterBandH) + #[cfg(all(major_ge_3, minor_ge_5))] + pub fn set_no_data_value_i64(&mut self, no_data: Option) -> Result<()> { + let rv = if let Some(no_data) = no_data { + unsafe { gdal_sys::GDALSetRasterNoDataValueAsInt64(self.c_rasterband, no_data) } + } else { + unsafe { gdal_sys::GDALDeleteRasterNoDataValue(self.c_rasterband) } + }; + + if rv != CPLErr::CE_None { + Err(_last_cpl_err(rv)) + } else { + Ok(()) + } + } /// Returns the color interpretation of this band. pub fn color_interpretation(&self) -> ColorInterpretation { let interp_index = unsafe { gdal_sys::GDALGetRasterColorInterpretation(self.c_rasterband) }; diff --git a/src/raster/tests.rs b/src/raster/tests.rs index 23094c81..a9313fbc 100644 --- a/src/raster/tests.rs +++ b/src/raster/tests.rs @@ -1,4 +1,5 @@ use crate::dataset::Dataset; +use crate::errors::Result; use crate::metadata::Metadata; use crate::raster::rasterband::ResampleAlg; use crate::raster::{ @@ -424,16 +425,43 @@ fn test_get_rasterband() { } #[test] -fn test_get_no_data_value() { - let dataset = Dataset::open(fixture("tinymarble.tif")).unwrap(); - let rasterband = dataset.rasterband(1).unwrap(); +fn test_get_no_data_value() -> Result<()> { + let dataset = Dataset::open(fixture("tinymarble.tif"))?; + let rasterband = dataset.rasterband(1)?; let no_data_value = rasterband.no_data_value(); assert!(no_data_value.is_none()); - // let dataset = Dataset::open(fixture!("bluemarble.tif")).unwrap(); - // let rasterband = dataset.get_rasterband(1).unwrap(); - // let no_data_value = rasterband.get_no_data_value(); - // assert_eq!(no_data_value, Some(0.0)); + let dataset = Dataset::open(fixture("labels.tif"))?; + let rasterband = dataset.rasterband(1)?; + let no_data_value = rasterband.no_data_value(); + assert_eq!(no_data_value, Some(255.0)); + Ok(()) +} + +#[test] +#[cfg(all(major_ge_3, minor_ge_5))] +fn test_no_data_value_i64() -> Result<()> { + let driver = DriverManager::get_driver_by_name("MEM")?; + let ds = driver.create_with_band_type::("test_no_data_value_i64", 1, 1, 1)?; + let mut rasterband = ds.rasterband(1)?; + assert_eq!(rasterband.no_data_value_i64(), None); + rasterband.set_no_data_value_i64(Some(i64::MIN))?; + assert_eq!(rasterband.no_data_value_i64(), Some(i64::MIN)); + + Ok(()) +} + +#[test] +#[cfg(all(major_ge_3, minor_ge_5))] +fn test_no_data_value_u64() -> Result<()> { + let driver = DriverManager::get_driver_by_name("MEM")?; + let ds = driver.create_with_band_type::("test_no_data_value_u64", 1, 1, 1)?; + let mut rasterband = ds.rasterband(1)?; + assert_eq!(rasterband.no_data_value_u64(), None); + rasterband.set_no_data_value_u64(Some(u64::MAX))?; + assert_eq!(rasterband.no_data_value_u64(), Some(u64::MAX)); + + Ok(()) } #[test]