From fbd9aff9aacfa2b82992767df0fd532ce2ff4572 Mon Sep 17 00:00:00 2001 From: Barugon Date: Fri, 13 May 2022 12:09:00 -0700 Subject: [PATCH 1/2] Squashed commit of the following: commit 147809c573e3029703ba03b9753e67c64f6fd466 Merge: 6e63f0f b0ebd1d Author: Barugon Date: Fri May 13 10:46:52 2022 -0700 Merge branch 'master' into barugon/color_table commit 6e63f0ff16a5ff3ac2e75d87dfba6525d5ee3301 Merge: 4e75d8d d8aa19a Author: Barugon Date: Fri May 13 00:43:18 2022 -0700 Merge branch 'master' into barugon/color_table commit 4e75d8d3011f0fee67c195815fe17a2384df4edd Merge: 9362add 8cb6e92 Author: Barugon Date: Wed Apr 20 09:50:59 2022 -0700 Merge branch 'master' into barugon/color_table commit 9362addbb1afe611183afd1a44c56d05415b4d6e Author: Barugon Date: Wed Feb 16 18:12:35 2022 -0800 Export some necessary items commit 1f7b73d18c13596c7f7eedee8b1eb07fb2c60a62 Merge: d2d0df4 6cb085a Author: Barugon Date: Sat Feb 12 17:40:50 2022 -0800 Merge branch 'master' into barugon/color_table commit d2d0df427741a4d272cbc2a6c861adc2343feb80 Author: Barugon Date: Sat Feb 12 17:37:30 2022 -0800 Merge branch 'master' into barugon/color_table commit 4b91e3de2eda1f2edada281185f7539bbce9b2c7 Author: Barugon Date: Mon Feb 7 05:27:15 2022 -0800 Better casting in entry_count commit df40642a36b05b05d31859d693c7aae4348f4882 Author: Barugon Date: Mon Feb 7 05:25:12 2022 -0800 Have entry count return usize Make index usize for entry and entry_as_rgb commit 7b3dbc2622859cbd4ee8b0ed12f8e3f72f88667c Author: Barugon Date: Mon Jan 31 06:41:15 2022 -0800 Add PR link commit 293878ea8c31102719f178616586ccf4e2b07497 Author: Barugon Date: Mon Jan 31 06:35:48 2022 -0800 Use unreachable macro commit 2b74b7e9f9a470a432b135d1bea489d68c5e782f Merge: 67423e5 8d347ba Author: Barugon Date: Sun Jan 30 20:39:34 2022 -0800 Merge branch 'master' into barugon/color_table commit 67423e5d20c677770ff774d145af773ba302804e Author: Barugon Date: Sun Jan 30 20:31:52 2022 -0800 Add enumerations for color types commit 04b1b4937d5b348833fa70727d831ce245f5d9a7 Author: Barugon Date: Thu Jan 27 23:01:31 2022 -0800 Implement color table test commit 3d9be87295253ddb9a1b2e0b474fa7bd446f1d65 Author: Barugon Date: Thu Jan 27 23:01:18 2022 -0800 Add geo-tiff for color table testing commit 0a1769dfa320c94326983d6abee0f21725ac1b56 Author: Barugon Date: Thu Jan 27 08:35:01 2022 -0800 Add doc comment for ColorTable Remove raster_band method commit 6c618b498d3fe1bf9b97b906af701afd5f5e577e Author: Barugon Date: Tue Jan 25 15:59:42 2022 -0800 Note changes in Unreleased section commit 1e75ff3fbfa97f3f07ea56752209893759f002ae Author: Barugon Date: Tue Jan 25 15:44:33 2022 -0800 Implement ColorTable struct Add color_table method to RasterBand --- CHANGES.md | 4 + fixtures/test_color_table.tif | Bin 0 -> 22639 bytes src/raster/mod.rs | 5 +- src/raster/rasterband.rs | 154 +++++++++++++++++++++++++++++++++- src/raster/tests.rs | 40 +++++++++ 5 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 fixtures/test_color_table.tif diff --git a/CHANGES.md b/CHANGES.md index d43bd3a3..375e7a8c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -27,6 +27,10 @@ - +- Add a `ColorTable` struct and `RasterBand::color_table` method + + - + ## 0.12 - Bump Rust edition to 2021 diff --git a/fixtures/test_color_table.tif b/fixtures/test_color_table.tif new file mode 100644 index 0000000000000000000000000000000000000000..082c5c40aa1577bf2ce9f76f82c4294bb8a6e9bb GIT binary patch literal 22639 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 M^Z)yDKXc;$0c-k8fdBvi literal 0 HcmV?d00001 diff --git a/src/raster/mod.rs b/src/raster/mod.rs index 8c04d7b2..2a524508 100644 --- a/src/raster/mod.rs +++ b/src/raster/mod.rs @@ -5,7 +5,10 @@ mod rasterize; mod types; mod warp; -pub use rasterband::{Buffer, ByteBuffer, ColorInterpretation, RasterBand, ResampleAlg}; +pub use rasterband::{ + Buffer, ByteBuffer, CmykEntry, ColorEntry, ColorInterpretation, ColorTable, GrayEntry, + HlsEntry, PaletteInterpretation, RasterBand, ResampleAlg, RgbaEntry, +}; pub use rasterize::{rasterize, BurnSource, MergeAlgorithm, OptimizeMode, RasterizeOptions}; pub use types::{GDALDataType, GdalType}; pub use warp::reproject; diff --git a/src/raster/rasterband.rs b/src/raster/rasterband.rs index 2ae3cbfe..f913d271 100644 --- a/src/raster/rasterband.rs +++ b/src/raster/rasterband.rs @@ -4,8 +4,8 @@ use crate::metadata::Metadata; use crate::raster::{GDALDataType, GdalType}; use crate::utils::{_last_cpl_err, _last_null_pointer_err, _string}; use gdal_sys::{ - self, CPLErr, GDALColorInterp, GDALMajorObjectH, GDALRWFlag, GDALRasterBandH, - GDALRasterIOExtraArg, + self, CPLErr, GDALColorEntry, GDALColorInterp, GDALColorTableH, GDALMajorObjectH, + GDALPaletteInterp, GDALRWFlag, GDALRasterBandH, GDALRasterIOExtraArg, }; use libc::c_int; use std::ffi::CString; @@ -421,6 +421,15 @@ impl<'a> RasterBand<'a> { Ok(()) } + /// Get the color table for this band if it has one. + pub fn color_table(&self) -> Option { + let c_color_table = unsafe { gdal_sys::GDALGetRasterColorTable(self.c_rasterband) }; + if c_color_table.is_null() { + return None; + } + Some(ColorTable::from_c_color_table(c_color_table, self)) + } + /// Returns the scale of this band if set. pub fn scale(&self) -> Option { let mut pb_success = 1; @@ -612,3 +621,144 @@ impl ColorInterpretation { _string(rv) } } + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum PaletteInterpretation { + Gray, + Rgba, + Cmyk, + Hls, +} + +impl PaletteInterpretation { + fn from_c_int(palette_interpretation: GDALPaletteInterp::Type) -> Self { + match palette_interpretation { + GDALPaletteInterp::GPI_Gray => Self::Gray, + GDALPaletteInterp::GPI_RGB => Self::Rgba, + GDALPaletteInterp::GPI_CMYK => Self::Cmyk, + GDALPaletteInterp::GPI_HLS => Self::Hls, + _ => unreachable!("GDAL has implemented a new type of `GDALPaletteInterp`"), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct GrayEntry { + pub g: i16, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct RgbaEntry { + pub r: i16, + pub g: i16, + pub b: i16, + pub a: i16, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct CmykEntry { + pub c: i16, + pub m: i16, + pub y: i16, + pub k: i16, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct HlsEntry { + pub h: i16, + pub l: i16, + pub s: i16, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ColorEntry { + Gray(GrayEntry), + Rgba(RgbaEntry), + Cmyk(CmykEntry), + Hls(HlsEntry), +} + +/// Color table for raster bands that use the PaletteIndex color interpretation. +/// +/// This object carries the lifetime of the raster band that +/// contains it. This is necessary to prevent the raster band +/// from being dropped before the color table. +pub struct ColorTable<'a> { + palette_interpretation: PaletteInterpretation, + c_color_table: GDALColorTableH, + _raster_band: &'a RasterBand<'a>, +} + +impl<'a> ColorTable<'a> { + fn from_c_color_table(c_color_table: GDALColorTableH, raster_band: &'a RasterBand<'a>) -> Self { + let interp_index = unsafe { gdal_sys::GDALGetPaletteInterpretation(c_color_table) }; + ColorTable { + palette_interpretation: PaletteInterpretation::from_c_int(interp_index), + c_color_table, + _raster_band: raster_band, + } + } + + /// How the values of this color table are interpreted. + pub fn palette_interpretation(&self) -> PaletteInterpretation { + self.palette_interpretation + } + + /// Get the number of color entries in this color table. + pub fn entry_count(&self) -> usize { + unsafe { gdal_sys::GDALGetColorEntryCount(self.c_color_table) as usize } + } + + /// Get a color entry. + pub fn entry(&self, index: usize) -> Option { + let color_entry = unsafe { + let c_color_entry = gdal_sys::GDALGetColorEntry(self.c_color_table, index as i32); + if c_color_entry.is_null() { + return None; + } + *c_color_entry + }; + match self.palette_interpretation { + PaletteInterpretation::Gray => Some(ColorEntry::Gray(GrayEntry { g: color_entry.c1 })), + PaletteInterpretation::Rgba => Some(ColorEntry::Rgba(RgbaEntry { + r: color_entry.c1, + g: color_entry.c2, + b: color_entry.c3, + a: color_entry.c4, + })), + PaletteInterpretation::Cmyk => Some(ColorEntry::Cmyk(CmykEntry { + c: color_entry.c1, + m: color_entry.c2, + y: color_entry.c3, + k: color_entry.c4, + })), + PaletteInterpretation::Hls => Some(ColorEntry::Hls(HlsEntry { + h: color_entry.c1, + l: color_entry.c2, + s: color_entry.c3, + })), + } + } + + /// Get a color entry as RGB. + pub fn entry_as_rgb(&self, index: usize) -> Option { + let mut color_entry = GDALColorEntry { + c1: 0, + c2: 0, + c3: 0, + c4: 0, + }; + if unsafe { + gdal_sys::GDALGetColorEntryAsRGB(self.c_color_table, index as i32, &mut color_entry) + } == 0 + { + return None; + } + Some(RgbaEntry { + r: color_entry.c1, + g: color_entry.c2, + b: color_entry.c3, + a: color_entry.c4, + }) + } +} diff --git a/src/raster/tests.rs b/src/raster/tests.rs index a8d64711..65da3653 100644 --- a/src/raster/tests.rs +++ b/src/raster/tests.rs @@ -706,3 +706,43 @@ fn test_rasterband_unit() { assert_eq!(rasterband.unit(), "m".to_string()); } + +#[test] +fn test_color_table() { + use crate::raster::rasterband::{ColorEntry, PaletteInterpretation}; + + // Raster containing one band. + let dataset = Dataset::open(fixture!("test_color_table.tif")).expect("open failure"); + assert_eq!(dataset.raster_count(), 1); + + // Band is PaletteIndex. + let band = dataset.rasterband(1).expect("rasterband failure"); + assert_eq!( + band.color_interpretation(), + ColorInterpretation::PaletteIndex + ); + + // Color table is RGB. + let color_table = band.color_table().unwrap(); + assert_eq!( + color_table.palette_interpretation(), + PaletteInterpretation::Rgba + ); + + // Color table has 256 entries. + let entry_count = color_table.entry_count(); + assert_eq!(entry_count, 256); + + // Check that entry and entry_as_rgb are the same. + for index in 0..entry_count { + if let ColorEntry::Rgba(entry) = color_table.entry(index).unwrap() { + let rgb_entry = color_table.entry_as_rgb(index).unwrap(); + assert_eq!(entry.r, rgb_entry.r); + assert_eq!(entry.g, rgb_entry.g); + assert_eq!(entry.b, rgb_entry.b); + assert_eq!(entry.a, rgb_entry.a); + } else { + panic!(); + } + } +} From 73f5fcde2d039e2975c6f55392bf303781b6f740 Mon Sep 17 00:00:00 2001 From: Barugon Date: Sat, 14 May 2022 01:02:32 -0700 Subject: [PATCH 2/2] Use PhantomData in ColorTable --- src/raster/rasterband.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/raster/rasterband.rs b/src/raster/rasterband.rs index f913d271..d0e28ffc 100644 --- a/src/raster/rasterband.rs +++ b/src/raster/rasterband.rs @@ -9,6 +9,7 @@ use gdal_sys::{ }; use libc::c_int; use std::ffi::CString; +use std::marker::PhantomData; #[cfg(feature = "ndarray")] use ndarray::Array2; @@ -427,7 +428,7 @@ impl<'a> RasterBand<'a> { if c_color_table.is_null() { return None; } - Some(ColorTable::from_c_color_table(c_color_table, self)) + Some(ColorTable::from_c_color_table(c_color_table)) } /// Returns the scale of this band if set. @@ -686,16 +687,16 @@ pub enum ColorEntry { pub struct ColorTable<'a> { palette_interpretation: PaletteInterpretation, c_color_table: GDALColorTableH, - _raster_band: &'a RasterBand<'a>, + phantom_raster_band: PhantomData<&'a RasterBand<'a>>, } impl<'a> ColorTable<'a> { - fn from_c_color_table(c_color_table: GDALColorTableH, raster_band: &'a RasterBand<'a>) -> Self { + fn from_c_color_table(c_color_table: GDALColorTableH) -> Self { let interp_index = unsafe { gdal_sys::GDALGetPaletteInterpretation(c_color_table) }; ColorTable { palette_interpretation: PaletteInterpretation::from_c_int(interp_index), c_color_table, - _raster_band: raster_band, + phantom_raster_band: PhantomData, } }