geonative_processing/raster/
pixel.rs1use geonative_core::raster::{Band, PixelType};
16
17pub fn read(band: &Band, col: usize, row: usize, width: usize) -> Option<f64> {
22 let idx = row * width + col;
23 let dtype = band.descriptor.dtype;
24 let bpp = dtype.size_bytes();
25 let off = idx * bpp;
26 if off + bpp > band.data.len() {
27 return None;
28 }
29 let bytes = &band.data[off..off + bpp];
30 Some(match dtype {
31 PixelType::U8 => bytes[0] as f64,
32 PixelType::I8 => (bytes[0] as i8) as f64,
33 PixelType::U16 => u16::from_le_bytes([bytes[0], bytes[1]]) as f64,
34 PixelType::I16 => i16::from_le_bytes([bytes[0], bytes[1]]) as f64,
35 PixelType::U32 => u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as f64,
36 PixelType::I32 => i32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as f64,
37 PixelType::F32 => f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as f64,
38 PixelType::F64 => f64::from_le_bytes([
39 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
40 ]),
41 _ => return None,
44 })
45}
46
47pub fn write(band: &mut Band, col: usize, row: usize, width: usize, value: f64) -> bool {
51 let idx = row * width + col;
52 let dtype = band.descriptor.dtype;
53 let bpp = dtype.size_bytes();
54 let off = idx * bpp;
55 if off + bpp > band.data.len() {
56 return false;
57 }
58 match dtype {
59 PixelType::U8 => {
60 band.data[off] = value.round().clamp(0.0, u8::MAX as f64) as u8;
61 }
62 PixelType::I8 => {
63 band.data[off] = (value.round().clamp(i8::MIN as f64, i8::MAX as f64) as i8) as u8;
64 }
65 PixelType::U16 => {
66 let v = value.round().clamp(0.0, u16::MAX as f64) as u16;
67 band.data[off..off + 2].copy_from_slice(&v.to_le_bytes());
68 }
69 PixelType::I16 => {
70 let v = value.round().clamp(i16::MIN as f64, i16::MAX as f64) as i16;
71 band.data[off..off + 2].copy_from_slice(&v.to_le_bytes());
72 }
73 PixelType::U32 => {
74 let v = value.round().clamp(0.0, u32::MAX as f64) as u32;
75 band.data[off..off + 4].copy_from_slice(&v.to_le_bytes());
76 }
77 PixelType::I32 => {
78 let v = value.round().clamp(i32::MIN as f64, i32::MAX as f64) as i32;
79 band.data[off..off + 4].copy_from_slice(&v.to_le_bytes());
80 }
81 PixelType::F32 => {
82 band.data[off..off + 4].copy_from_slice(&(value as f32).to_le_bytes());
83 }
84 PixelType::F64 => {
85 band.data[off..off + 8].copy_from_slice(&value.to_le_bytes());
86 }
87 _ => return false,
88 }
89 true
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use geonative_core::raster::BandDescriptor;
96
97 fn u8_band(width: usize, height: usize) -> Band {
98 Band::new(
99 BandDescriptor::new(Some("v".into()), PixelType::U8),
100 vec![0u8; width * height],
101 )
102 }
103
104 #[test]
105 fn round_trip_u8() {
106 let mut b = u8_band(4, 4);
107 assert!(write(&mut b, 1, 2, 4, 42.0));
108 assert_eq!(read(&b, 1, 2, 4), Some(42.0));
109 }
110
111 #[test]
112 fn u8_clamps() {
113 let mut b = u8_band(2, 2);
114 write(&mut b, 0, 0, 2, 300.0); assert_eq!(read(&b, 0, 0, 2), Some(255.0));
116 write(&mut b, 1, 0, 2, -5.0); assert_eq!(read(&b, 1, 0, 2), Some(0.0));
118 }
119
120 #[test]
121 fn round_trip_f32() {
122 let mut b = Band::new(
123 BandDescriptor::new(Some("v".into()), PixelType::F32),
124 vec![0u8; 4 * 4 * 4],
125 );
126 write(&mut b, 2, 3, 4, std::f64::consts::PI);
127 let got = read(&b, 2, 3, 4).unwrap();
128 assert!((got - std::f64::consts::PI).abs() < 1e-6);
129 }
130
131 #[test]
132 fn round_trip_i16_negative() {
133 let mut b = Band::new(
134 BandDescriptor::new(Some("v".into()), PixelType::I16),
135 vec![0u8; 2 * 2 * 2],
136 );
137 write(&mut b, 0, 0, 2, -1234.0);
138 assert_eq!(read(&b, 0, 0, 2), Some(-1234.0));
139 }
140}