Skip to content

Commit

Permalink
Merge #285
Browse files Browse the repository at this point in the history
285: add raster mask methods r=lnicola a=jdroenner

- [ x ] I agree to follow the project's [code of conduct](https://github.com/georust/gdal/blob/master/CODE_OF_CONDUCT.md).
- [ x ] I added an entry to `CHANGES.md` if knowledge of this change could be valuable to users.
---



Co-authored-by: Johannes Drönner <droenner@informatik.uni-marburg.de>
Co-authored-by: Johannes Drönner <jdroenner@users.noreply.github.com>
  • Loading branch information
3 people committed Aug 27, 2022
2 parents 257b95c + cc4dbb6 commit 2e063a7
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Expand Up @@ -63,6 +63,10 @@

- <https://github.com/georust/gdal/pull/265>

- Add methods to access raster masks and get raster mask flags. (`open_mask_band`, `create_mask_band`, and `mask_flags`).

- <https://github.com/georust/gdal/pull/285>

- Remove `PartialEq` from `GdalError`

- <https://github.com/georust/gdal/pull/286>
Expand Down
66 changes: 66 additions & 0 deletions src/raster/rasterband.rs
Expand Up @@ -50,6 +50,37 @@ fn map_resample_alg(alg: &ResampleAlg) -> u32 {
}
}

/// Wrapper type for gdal mask flags.
/// From the GDAL docs:
/// - `GMF_ALL_VALID`(0x01): There are no invalid pixels, all mask values will be 255. When used this will normally be the only flag set.
/// - `GMF_PER_DATASET`(0x02): The mask band is shared between all bands on the dataset.
/// - `GMF_ALPHA`(0x04): The mask band is actually an alpha band and may have values other than 0 and 255.
/// - `GMF_NODATA`(0x08): Indicates the mask is actually being generated from nodata values. (mutually exclusive of `GMF_ALPHA`)
pub struct GdalMaskFlags(i32);

impl GdalMaskFlags {
const GMF_ALL_VALID: i32 = 0x01;
const GMF_PER_DATASET: i32 = 0x02;
const GMF_ALPHA: i32 = 0x04;
const GMF_NODATA: i32 = 0x08;

pub fn is_all_valid(&self) -> bool {
self.0 & Self::GMF_ALL_VALID != 0
}

pub fn is_per_dataset(&self) -> bool {
self.0 & Self::GMF_PER_DATASET != 0
}

pub fn is_alpha(&self) -> bool {
self.0 & Self::GMF_ALPHA != 0
}

pub fn is_nodata(&self) -> bool {
self.0 & Self::GMF_NODATA != 0
}
}

/// Extra options used to read a raster.
///
/// For documentation, see `gdal_sys::GDALRasterIOExtraArg`.
Expand Down Expand Up @@ -498,6 +529,41 @@ impl<'a> RasterBand<'a> {

_string(str_ptr)
}

/// Read the band mask flags for a GDAL `RasterBand`.
pub fn mask_flags(&self) -> Result<GdalMaskFlags> {
let band_mask_flags = unsafe { gdal_sys::GDALGetMaskFlags(self.c_rasterband) };

Ok(GdalMaskFlags(band_mask_flags))
}

/// Create a new mask band for the layer.
/// `shared_between_all_bands` indicates if all bands of the dataset use the same mask.
pub fn create_mask_band(&mut self, shared_between_all_bands: bool) -> Result<()> {
let flags = if shared_between_all_bands {
GdalMaskFlags::GMF_PER_DATASET // It is the only valid flag here.
} else {
0x00
};

let rv = unsafe { gdal_sys::GDALCreateMaskBand(self.c_rasterband, flags) };
if rv != 0 {
return Err(_last_cpl_err(rv));
};
Ok(())
}

/// Open the mask-`Rasterband`
pub fn open_mask_band(&self) -> Result<RasterBand> {
unsafe {
let mask_band_ptr = gdal_sys::GDALGetMaskBand(self.c_rasterband);
if mask_band_ptr.is_null() {
return Err(_last_null_pointer_err("GDALGetMaskBand"));
}
let mask_band = RasterBand::from_c_rasterband(self.dataset, mask_band_ptr);
Ok(mask_band)
}
}
}

impl<'a> MajorObject for RasterBand<'a> {
Expand Down
32 changes: 32 additions & 0 deletions src/raster/tests.rs
Expand Up @@ -406,6 +406,38 @@ fn test_read_raster_as() {
assert_eq!(rb.band_type(), GDALDataType::GDT_Byte);
}

#[test]
fn mask_flags() {
let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
let rb = dataset.rasterband(1).unwrap();
let mask_flags = rb.mask_flags().unwrap();
assert!(!mask_flags.is_nodata());
assert!(!mask_flags.is_alpha());
assert!(!mask_flags.is_per_dataset());
assert!(mask_flags.is_all_valid());
}

#[test]
fn open_mask_band() {
let dataset = Dataset::open(fixture!("tinymarble.png")).unwrap();
let rb = dataset.rasterband(1).unwrap();
let mb = rb.open_mask_band().unwrap();
let mask_values = mb.read_as::<u8>((20, 30), (2, 3), (2, 3), None).unwrap();
assert_eq!(mask_values.data, [255u8; 6])
}

#[test]
fn create_mask_band() {
let driver = Driver::get_by_name("MEM").unwrap();
let dataset = driver.create("", 20, 10, 1).unwrap();
let mut rb = dataset.rasterband(1).unwrap();
rb.create_mask_band(false).unwrap();

let mb = rb.open_mask_band().unwrap();
let mask_values = mb.read_as::<u8>((0, 0), (20, 10), (20, 10), None).unwrap();
assert_eq!(mask_values.data, [0; 200])
}

#[test]
#[cfg(feature = "ndarray")]
fn test_read_raster_as_array() {
Expand Down

0 comments on commit 2e063a7

Please sign in to comment.