1use crate::error::{OxiGdalError, Result};
28use crate::types::{ColorInterpretation, NoDataValue, PixelLayout, RasterDataType};
29
30use super::{BufferStatistics, RasterBuffer};
31
32#[derive(Debug, Clone)]
36pub struct MultiBandBuffer {
37 bands: Vec<RasterBuffer>,
39 colors: Vec<ColorInterpretation>,
41 nodata_overrides: Vec<Option<NoDataValue>>,
43 layout: PixelLayout,
45}
46
47impl MultiBandBuffer {
48 pub fn from_bands(bands: Vec<RasterBuffer>, colors: Vec<ColorInterpretation>) -> Result<Self> {
57 if bands.is_empty() {
58 return Err(OxiGdalError::InvalidParameter {
59 parameter: "bands",
60 message: "At least one band is required".to_string(),
61 });
62 }
63 if colors.len() != bands.len() {
64 return Err(OxiGdalError::InvalidParameter {
65 parameter: "colors",
66 message: format!(
67 "Color interpretation count ({}) must match band count ({})",
68 colors.len(),
69 bands.len()
70 ),
71 });
72 }
73
74 let w = bands[0].width();
75 let h = bands[0].height();
76 let dt = bands[0].data_type();
77
78 for (i, band) in bands.iter().enumerate().skip(1) {
79 if band.width() != w || band.height() != h {
80 return Err(OxiGdalError::InvalidParameter {
81 parameter: "bands",
82 message: format!(
83 "Band {} dimensions {}x{} differ from band 0 dimensions {}x{}",
84 i,
85 band.width(),
86 band.height(),
87 w,
88 h
89 ),
90 });
91 }
92 if band.data_type() != dt {
93 return Err(OxiGdalError::InvalidParameter {
94 parameter: "bands",
95 message: format!(
96 "Band {} data type {:?} differs from band 0 data type {:?}",
97 i,
98 band.data_type(),
99 dt
100 ),
101 });
102 }
103 }
104
105 let nodata_overrides = vec![None; bands.len()];
106
107 Ok(Self {
108 bands,
109 colors,
110 nodata_overrides,
111 layout: PixelLayout::BandSequential,
112 })
113 }
114
115 pub fn from_interleaved(
123 data: &[u8],
124 width: u64,
125 height: u64,
126 band_count: u32,
127 data_type: RasterDataType,
128 nodata: NoDataValue,
129 ) -> Result<Self> {
130 let pixel_size = data_type.size_bytes();
131 let expected = (width * height * band_count as u64 * pixel_size as u64) as usize;
132 if data.len() != expected {
133 return Err(OxiGdalError::InvalidParameter {
134 parameter: "data",
135 message: format!(
136 "Interleaved data size {} differs from expected {} ({}x{}x{}x{})",
137 data.len(),
138 expected,
139 width,
140 height,
141 band_count,
142 pixel_size
143 ),
144 });
145 }
146
147 let pixels = width * height;
148 let band_size = (pixels * pixel_size as u64) as usize;
149 let bc = band_count as usize;
150 let ps = pixel_size;
151
152 let mut band_buffers = Vec::with_capacity(bc);
153 for b in 0..bc {
154 let mut band_data = vec![0u8; band_size];
155 for pixel_idx in 0..(pixels as usize) {
156 let src_offset = pixel_idx * bc * ps + b * ps;
157 let dst_offset = pixel_idx * ps;
158 band_data[dst_offset..dst_offset + ps]
159 .copy_from_slice(&data[src_offset..src_offset + ps]);
160 }
161 band_buffers.push(RasterBuffer::new(
162 band_data, width, height, data_type, nodata,
163 )?);
164 }
165
166 let colors = default_color_interpretation(bc);
167
168 Ok(Self {
169 bands: band_buffers,
170 colors,
171 nodata_overrides: vec![None; bc],
172 layout: PixelLayout::BandInterleavedByPixel,
173 })
174 }
175
176 pub fn from_bsq(
182 data: &[u8],
183 width: u64,
184 height: u64,
185 band_count: u32,
186 data_type: RasterDataType,
187 nodata: NoDataValue,
188 ) -> Result<Self> {
189 let pixel_size = data_type.size_bytes();
190 let expected = (width * height * band_count as u64 * pixel_size as u64) as usize;
191 if data.len() != expected {
192 return Err(OxiGdalError::InvalidParameter {
193 parameter: "data",
194 message: format!(
195 "BSQ data size {} differs from expected {}",
196 data.len(),
197 expected
198 ),
199 });
200 }
201
202 let band_size = (width * height * pixel_size as u64) as usize;
203 let bc = band_count as usize;
204 let mut band_buffers = Vec::with_capacity(bc);
205
206 for b in 0..bc {
207 let start = b * band_size;
208 let band_data = data[start..start + band_size].to_vec();
209 band_buffers.push(RasterBuffer::new(
210 band_data, width, height, data_type, nodata,
211 )?);
212 }
213
214 let colors = default_color_interpretation(bc);
215
216 Ok(Self {
217 bands: band_buffers,
218 colors,
219 nodata_overrides: vec![None; bc],
220 layout: PixelLayout::BandSequential,
221 })
222 }
223
224 pub fn from_bil(
240 data: &[u8],
241 width: u64,
242 height: u64,
243 band_count: u32,
244 data_type: RasterDataType,
245 nodata: NoDataValue,
246 ) -> Result<Self> {
247 let pixel_size = data_type.size_bytes();
248 let bc = band_count as usize;
249 let w = width as usize;
250 let h = height as usize;
251 let expected = bc * h * w * pixel_size;
252 if data.len() != expected {
253 return Err(OxiGdalError::InvalidParameter {
254 parameter: "data",
255 message: format!(
256 "BIL data size {} differs from expected {} ({}x{}x{}x{})",
257 data.len(),
258 expected,
259 width,
260 height,
261 band_count,
262 pixel_size
263 ),
264 });
265 }
266
267 let band_byte_size = h * w * pixel_size;
269 let mut band_buffers: Vec<RasterBuffer> = Vec::with_capacity(bc);
270
271 for b in 0..bc {
272 let mut bsq_data = vec![0u8; band_byte_size];
273 for r in 0..h {
274 let bil_offset = (r * bc + b) * w * pixel_size;
276 let bsq_offset = r * w * pixel_size;
278 let row_bytes = w * pixel_size;
279 bsq_data[bsq_offset..bsq_offset + row_bytes]
280 .copy_from_slice(&data[bil_offset..bil_offset + row_bytes]);
281 }
282 band_buffers.push(RasterBuffer::new(
283 bsq_data, width, height, data_type, nodata,
284 )?);
285 }
286
287 let colors = default_color_interpretation(bc);
288
289 Ok(Self {
290 bands: band_buffers,
291 colors,
292 nodata_overrides: vec![None; bc],
293 layout: PixelLayout::BandInterleavedByLine,
294 })
295 }
296
297 #[must_use]
299 pub fn band_count(&self) -> u32 {
300 self.bands.len() as u32
301 }
302
303 #[must_use]
305 pub fn width(&self) -> u64 {
306 self.bands.first().map_or(0, |b| b.width())
307 }
308
309 #[must_use]
311 pub fn height(&self) -> u64 {
312 self.bands.first().map_or(0, |b| b.height())
313 }
314
315 #[must_use]
317 pub fn data_type(&self) -> RasterDataType {
318 self.bands
319 .first()
320 .map_or(RasterDataType::UInt8, |b| b.data_type())
321 }
322
323 #[must_use]
325 pub fn layout(&self) -> PixelLayout {
326 self.layout
327 }
328
329 pub fn set_band_nodata(&mut self, band: u32, nodata: NoDataValue) -> Result<()> {
331 let idx = band as usize;
332 if idx >= self.bands.len() {
333 return Err(OxiGdalError::InvalidParameter {
334 parameter: "band",
335 message: format!("Band index {} out of range (0..{})", band, self.bands.len()),
336 });
337 }
338 self.nodata_overrides[idx] = Some(nodata);
339 Ok(())
340 }
341
342 pub fn band(&self, band: u32) -> Result<BandRef<'_>> {
348 let idx = band as usize;
349 if idx >= self.bands.len() {
350 return Err(OxiGdalError::InvalidParameter {
351 parameter: "band",
352 message: format!("Band index {} out of range (0..{})", band, self.bands.len()),
353 });
354 }
355 Ok(BandRef {
356 index: band,
357 buffer: &self.bands[idx],
358 color: self.colors[idx],
359 nodata_override: self.nodata_overrides[idx],
360 })
361 }
362
363 pub fn band_mut(&mut self, band: u32) -> Result<&mut RasterBuffer> {
369 let idx = band as usize;
370 if idx >= self.bands.len() {
371 return Err(OxiGdalError::InvalidParameter {
372 parameter: "band",
373 message: format!("Band index {} out of range (0..{})", band, self.bands.len()),
374 });
375 }
376 Ok(&mut self.bands[idx])
377 }
378
379 #[must_use]
381 pub fn bands(&self) -> BandIterator<'_> {
382 BandIterator {
383 multi: self,
384 current: 0,
385 }
386 }
387
388 #[must_use]
392 pub fn to_interleaved(&self) -> Vec<u8> {
393 let ps = self.data_type().size_bytes();
394 let bc = self.bands.len();
395 let pixels = (self.width() * self.height()) as usize;
396 let mut out = vec![0u8; pixels * bc * ps];
397
398 for (b, band) in self.bands.iter().enumerate() {
399 let src = band.as_bytes();
400 for pixel_idx in 0..pixels {
401 let dst_off = pixel_idx * bc * ps + b * ps;
402 let src_off = pixel_idx * ps;
403 out[dst_off..dst_off + ps].copy_from_slice(&src[src_off..src_off + ps]);
404 }
405 }
406
407 out
408 }
409
410 #[must_use]
414 pub fn to_bsq(&self) -> Vec<u8> {
415 let mut out = Vec::with_capacity(self.bands.iter().map(|b| b.as_bytes().len()).sum());
416 for band in &self.bands {
417 out.extend_from_slice(band.as_bytes());
418 }
419 out
420 }
421
422 #[must_use]
431 pub fn to_bil(&self) -> Vec<u8> {
432 let bc = self.bands.len();
433 let pixel_size = self.data_type().size_bytes();
434 let h = self.height() as usize;
435 let w = self.width() as usize;
436 let total = bc * h * w * pixel_size;
437 let mut out = vec![0u8; total];
438
439 for (b, band) in self.bands.iter().enumerate() {
440 let src = band.as_bytes();
441 for r in 0..h {
442 let bil_offset = (r * bc + b) * w * pixel_size;
444 let bsq_offset = r * w * pixel_size;
446 let row_bytes = w * pixel_size;
447 out[bil_offset..bil_offset + row_bytes]
448 .copy_from_slice(&src[bsq_offset..bsq_offset + row_bytes]);
449 }
450 }
451
452 out
453 }
454
455 pub fn compute_all_statistics(&self) -> Result<Vec<BufferStatistics>> {
461 self.bands.iter().map(|b| b.compute_statistics()).collect()
462 }
463
464 #[must_use]
466 pub fn into_bands(self) -> Vec<RasterBuffer> {
467 self.bands
468 }
469}
470
471#[derive(Debug, Clone, Copy)]
473pub struct BandRef<'a> {
474 index: u32,
476 buffer: &'a RasterBuffer,
478 color: ColorInterpretation,
480 nodata_override: Option<NoDataValue>,
482}
483
484impl<'a> BandRef<'a> {
485 #[must_use]
487 pub fn index(&self) -> u32 {
488 self.index
489 }
490
491 #[must_use]
493 pub fn gdal_index(&self) -> u32 {
494 self.index + 1
495 }
496
497 #[must_use]
499 pub fn buffer(&self) -> &'a RasterBuffer {
500 self.buffer
501 }
502
503 #[must_use]
505 pub fn color(&self) -> ColorInterpretation {
506 self.color
507 }
508
509 #[must_use]
511 pub fn nodata(&self) -> NoDataValue {
512 self.nodata_override.unwrap_or(self.buffer.nodata())
513 }
514
515 pub fn as_slice<T: Copy + 'static>(&self) -> Result<&[T]> {
521 self.buffer.as_slice::<T>()
522 }
523}
524
525pub struct BandIterator<'a> {
530 multi: &'a MultiBandBuffer,
531 current: u32,
532}
533
534impl<'a> Iterator for BandIterator<'a> {
535 type Item = BandRef<'a>;
536
537 fn next(&mut self) -> Option<Self::Item> {
538 if self.current >= self.multi.band_count() {
539 return None;
540 }
541 let idx = self.current as usize;
542 let band = BandRef {
543 index: self.current,
544 buffer: &self.multi.bands[idx],
545 color: self.multi.colors[idx],
546 nodata_override: self.multi.nodata_overrides[idx],
547 };
548 self.current += 1;
549 Some(band)
550 }
551
552 fn size_hint(&self) -> (usize, Option<usize>) {
553 let remaining = (self.multi.band_count() - self.current) as usize;
554 (remaining, Some(remaining))
555 }
556}
557
558impl ExactSizeIterator for BandIterator<'_> {}
559
560fn default_color_interpretation(band_count: usize) -> Vec<ColorInterpretation> {
562 match band_count {
563 1 => vec![ColorInterpretation::Gray],
564 3 => vec![
565 ColorInterpretation::Red,
566 ColorInterpretation::Green,
567 ColorInterpretation::Blue,
568 ],
569 4 => vec![
570 ColorInterpretation::Red,
571 ColorInterpretation::Green,
572 ColorInterpretation::Blue,
573 ColorInterpretation::Alpha,
574 ],
575 _ => vec![ColorInterpretation::Undefined; band_count],
576 }
577}
578
579#[cfg(test)]
580mod tests {
581 use super::*;
582
583 #[test]
584 fn test_multi_band_from_bands() {
585 let r = RasterBuffer::zeros(100, 100, RasterDataType::UInt8);
586 let g = RasterBuffer::zeros(100, 100, RasterDataType::UInt8);
587 let b = RasterBuffer::zeros(100, 100, RasterDataType::UInt8);
588
589 let multi = MultiBandBuffer::from_bands(
590 vec![r, g, b],
591 vec![
592 ColorInterpretation::Red,
593 ColorInterpretation::Green,
594 ColorInterpretation::Blue,
595 ],
596 )
597 .expect("should create multi-band buffer");
598
599 assert_eq!(multi.band_count(), 3);
600 assert_eq!(multi.width(), 100);
601 assert_eq!(multi.height(), 100);
602 assert_eq!(multi.data_type(), RasterDataType::UInt8);
603 }
604
605 #[test]
606 fn test_band_iterator() {
607 let bands: Vec<_> = (0..4)
608 .map(|_| RasterBuffer::zeros(50, 50, RasterDataType::Float32))
609 .collect();
610 let colors = vec![
611 ColorInterpretation::Red,
612 ColorInterpretation::Green,
613 ColorInterpretation::Blue,
614 ColorInterpretation::Alpha,
615 ];
616
617 let multi = MultiBandBuffer::from_bands(bands, colors).expect("should create");
618
619 let collected: Vec<_> = multi.bands().collect();
620 assert_eq!(collected.len(), 4);
621 assert_eq!(collected[0].index(), 0);
622 assert_eq!(collected[0].gdal_index(), 1);
623 assert_eq!(collected[0].color(), ColorInterpretation::Red);
624 assert_eq!(collected[3].color(), ColorInterpretation::Alpha);
625 }
626
627 #[test]
628 fn test_band_iterator_exact_size() {
629 let multi = MultiBandBuffer::from_bands(
630 vec![
631 RasterBuffer::zeros(10, 10, RasterDataType::UInt8),
632 RasterBuffer::zeros(10, 10, RasterDataType::UInt8),
633 ],
634 vec![ColorInterpretation::Gray, ColorInterpretation::Alpha],
635 )
636 .expect("should create");
637
638 let iter = multi.bands();
639 assert_eq!(iter.len(), 2);
640 }
641
642 #[test]
643 fn test_multi_band_empty_error() {
644 let result = MultiBandBuffer::from_bands(vec![], vec![]);
645 assert!(result.is_err());
646 }
647
648 #[test]
649 fn test_multi_band_dimension_mismatch() {
650 let a = RasterBuffer::zeros(100, 100, RasterDataType::UInt8);
651 let b = RasterBuffer::zeros(50, 50, RasterDataType::UInt8);
652
653 let result = MultiBandBuffer::from_bands(
654 vec![a, b],
655 vec![ColorInterpretation::Gray, ColorInterpretation::Alpha],
656 );
657 assert!(result.is_err());
658 }
659
660 #[test]
661 fn test_multi_band_type_mismatch() {
662 let a = RasterBuffer::zeros(100, 100, RasterDataType::UInt8);
663 let b = RasterBuffer::zeros(100, 100, RasterDataType::Float32);
664
665 let result = MultiBandBuffer::from_bands(
666 vec![a, b],
667 vec![ColorInterpretation::Gray, ColorInterpretation::Alpha],
668 );
669 assert!(result.is_err());
670 }
671
672 #[test]
673 fn test_multi_band_color_count_mismatch() {
674 let a = RasterBuffer::zeros(100, 100, RasterDataType::UInt8);
675
676 let result = MultiBandBuffer::from_bands(
677 vec![a],
678 vec![ColorInterpretation::Red, ColorInterpretation::Green],
679 );
680 assert!(result.is_err());
681 }
682
683 #[test]
684 fn test_band_access() {
685 let mut buf = RasterBuffer::zeros(10, 10, RasterDataType::UInt8);
686 buf.set_pixel(5, 5, 42.0).expect("should set");
687
688 let multi = MultiBandBuffer::from_bands(vec![buf], vec![ColorInterpretation::Gray])
689 .expect("should create");
690
691 let band = multi.band(0).expect("should get band");
692 assert_eq!(band.buffer().get_pixel(5, 5).expect("should get"), 42.0);
693 }
694
695 #[test]
696 fn test_band_out_of_range() {
697 let multi = MultiBandBuffer::from_bands(
698 vec![RasterBuffer::zeros(10, 10, RasterDataType::UInt8)],
699 vec![ColorInterpretation::Gray],
700 )
701 .expect("should create");
702
703 assert!(multi.band(1).is_err());
704 }
705
706 #[test]
707 fn test_from_interleaved_roundtrip() {
708 let data = vec![
710 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, ];
715
716 let multi = MultiBandBuffer::from_interleaved(
717 &data,
718 2,
719 2,
720 3,
721 RasterDataType::UInt8,
722 NoDataValue::None,
723 )
724 .expect("should create from interleaved");
725
726 assert_eq!(multi.band_count(), 3);
727 assert_eq!(multi.width(), 2);
728 assert_eq!(multi.height(), 2);
729 assert_eq!(multi.layout(), PixelLayout::BandInterleavedByPixel);
730
731 let r_band = multi.band(0).expect("should get");
733 assert_eq!(r_band.as_slice::<u8>().expect("slice"), &[10, 40, 70, 100]);
734
735 let g_band = multi.band(1).expect("should get");
737 assert_eq!(g_band.as_slice::<u8>().expect("slice"), &[20, 50, 80, 110]);
738
739 let b_band = multi.band(2).expect("should get");
741 assert_eq!(b_band.as_slice::<u8>().expect("slice"), &[30, 60, 90, 120]);
742
743 let interleaved = multi.to_interleaved();
745 assert_eq!(interleaved, data);
746 }
747
748 #[test]
749 fn test_from_bsq_roundtrip() {
750 let data = vec![
752 10, 40, 70, 100, 20, 50, 80, 110, 30, 60, 90, 120, ];
756
757 let multi =
758 MultiBandBuffer::from_bsq(&data, 2, 2, 3, RasterDataType::UInt8, NoDataValue::None)
759 .expect("should create from BSQ");
760
761 assert_eq!(multi.band_count(), 3);
762 assert_eq!(multi.layout(), PixelLayout::BandSequential);
763
764 let r_band = multi.band(0).expect("should get");
765 assert_eq!(r_band.as_slice::<u8>().expect("slice"), &[10, 40, 70, 100]);
766
767 let bsq = multi.to_bsq();
768 assert_eq!(bsq, data);
769 }
770
771 #[test]
772 fn test_compute_all_statistics() {
773 let mut r = RasterBuffer::zeros(2, 2, RasterDataType::Float32);
774 r.set_pixel(0, 0, 1.0).expect("set");
775 r.set_pixel(1, 0, 2.0).expect("set");
776 r.set_pixel(0, 1, 3.0).expect("set");
777 r.set_pixel(1, 1, 4.0).expect("set");
778
779 let multi = MultiBandBuffer::from_bands(vec![r], vec![ColorInterpretation::Gray])
780 .expect("should create");
781
782 let stats = multi.compute_all_statistics().expect("should compute");
783 assert_eq!(stats.len(), 1);
784 assert!((stats[0].min - 1.0).abs() < 1e-6);
785 assert!((stats[0].max - 4.0).abs() < 1e-6);
786 assert!((stats[0].mean - 2.5).abs() < 1e-6);
787 }
788
789 #[test]
790 fn test_band_nodata_override() {
791 let buf = RasterBuffer::zeros(5, 5, RasterDataType::Float32);
792 let mut multi = MultiBandBuffer::from_bands(vec![buf], vec![ColorInterpretation::Gray])
793 .expect("should create");
794
795 let band = multi.band(0).expect("get");
797 assert_eq!(band.nodata(), NoDataValue::None);
798
799 multi
801 .set_band_nodata(0, NoDataValue::Float(-9999.0))
802 .expect("should set");
803
804 let band = multi.band(0).expect("get");
805 assert_eq!(band.nodata(), NoDataValue::Float(-9999.0));
806 }
807
808 #[test]
809 fn test_band_mut() {
810 let buf = RasterBuffer::zeros(10, 10, RasterDataType::UInt8);
811 let mut multi = MultiBandBuffer::from_bands(vec![buf], vec![ColorInterpretation::Gray])
812 .expect("should create");
813
814 let band = multi.band_mut(0).expect("should get mut");
815 band.set_pixel(0, 0, 99.0).expect("should set");
816
817 let band = multi.band(0).expect("should get");
818 assert_eq!(band.buffer().get_pixel(0, 0).expect("should get"), 99.0);
819 }
820
821 #[test]
822 fn test_into_bands() {
823 let r = RasterBuffer::zeros(10, 10, RasterDataType::UInt8);
824 let g = RasterBuffer::zeros(10, 10, RasterDataType::UInt8);
825
826 let multi = MultiBandBuffer::from_bands(
827 vec![r, g],
828 vec![ColorInterpretation::Gray, ColorInterpretation::Alpha],
829 )
830 .expect("should create");
831
832 let bands = multi.into_bands();
833 assert_eq!(bands.len(), 2);
834 }
835
836 #[test]
837 fn test_from_bil_roundtrip() {
838 let bands = 2usize;
841 let height = 3usize;
842 let width = 4usize;
843 let mut bil: Vec<u8> = Vec::new();
845 for row in 0..height {
846 for band in 0..bands {
847 for col in 0..width {
848 bil.push(((band * 100 + row * 10 + col) & 0xFF) as u8);
849 }
850 }
851 }
852 let buf = MultiBandBuffer::from_bil(
853 &bil,
854 width as u64,
855 height as u64,
856 bands as u32,
857 RasterDataType::UInt8,
858 NoDataValue::None,
859 )
860 .expect("should create from BIL");
861 let back = buf.to_bil();
862 assert_eq!(bil, back, "BIL roundtrip failed");
863 }
864
865 #[test]
866 fn test_from_bil_to_bsq_equivalence() {
867 let (bands, height, width) = (2usize, 2usize, 3usize);
869 let mut bsq_data: Vec<u8> = Vec::new();
870 for band in 0..bands {
871 for row in 0..height {
872 for col in 0..width {
873 bsq_data.push((band * 10 + row * 3 + col) as u8);
874 }
875 }
876 }
877 let mut bil_data: Vec<u8> = vec![0; bands * height * width];
878 for band in 0..bands {
879 for row in 0..height {
880 for col in 0..width {
881 let bsq_idx = band * height * width + row * width + col;
882 let bil_idx = row * bands * width + band * width + col;
883 bil_data[bil_idx] = bsq_data[bsq_idx];
884 }
885 }
886 }
887 let from_bil = MultiBandBuffer::from_bil(
888 &bil_data,
889 width as u64,
890 height as u64,
891 bands as u32,
892 RasterDataType::UInt8,
893 NoDataValue::None,
894 )
895 .expect("should create from BIL");
896 let bsq_out = from_bil.to_bsq();
897 assert_eq!(bsq_data, bsq_out, "BSQ equivalence failed");
898 }
899
900 #[test]
901 fn test_from_bil_mismatched_size() {
902 let data: Vec<u8> = vec![0; 5];
904 let result =
905 MultiBandBuffer::from_bil(&data, 4, 3, 2, RasterDataType::UInt8, NoDataValue::None);
906 assert!(result.is_err(), "expected error for size mismatch");
907 }
908
909 #[test]
910 fn test_from_bil_various_types() {
911 for &(bands, height, width) in &[(2usize, 3usize, 4usize), (3usize, 2usize, 5usize)] {
913 let mut bil_u8: Vec<u8> = Vec::new();
915 for row in 0..height {
916 for band in 0..bands {
917 for col in 0..width {
918 bil_u8.push(((band * 100 + row * 10 + col) & 0xFF) as u8);
919 }
920 }
921 }
922 let buf = MultiBandBuffer::from_bil(
923 &bil_u8,
924 width as u64,
925 height as u64,
926 bands as u32,
927 RasterDataType::UInt8,
928 NoDataValue::None,
929 )
930 .expect("u8 from_bil should succeed");
931 let back = buf.to_bil();
932 assert_eq!(
933 bil_u8, back,
934 "u8 BIL roundtrip failed for {}x{}x{}",
935 bands, height, width
936 );
937
938 let mut bil_u16_raw: Vec<u8> = Vec::new();
940 for row in 0..height {
941 for band in 0..bands {
942 for col in 0..width {
943 let v: u16 = (band * 1000 + row * 10 + col) as u16;
944 bil_u16_raw.extend_from_slice(&v.to_ne_bytes());
945 }
946 }
947 }
948 let buf_u16 = MultiBandBuffer::from_bil(
949 &bil_u16_raw,
950 width as u64,
951 height as u64,
952 bands as u32,
953 RasterDataType::UInt16,
954 NoDataValue::None,
955 )
956 .expect("u16 from_bil should succeed");
957 let back_u16 = buf_u16.to_bil();
958 assert_eq!(
959 bil_u16_raw, back_u16,
960 "u16 BIL roundtrip failed for {}x{}x{}",
961 bands, height, width
962 );
963
964 let mut bil_f32_raw: Vec<u8> = Vec::new();
966 for row in 0..height {
967 for band in 0..bands {
968 for col in 0..width {
969 let v: f32 = (band * 100 + row * 10 + col) as f32 + 0.5;
970 bil_f32_raw.extend_from_slice(&v.to_ne_bytes());
971 }
972 }
973 }
974 let buf_f32 = MultiBandBuffer::from_bil(
975 &bil_f32_raw,
976 width as u64,
977 height as u64,
978 bands as u32,
979 RasterDataType::Float32,
980 NoDataValue::None,
981 )
982 .expect("f32 from_bil should succeed");
983 let back_f32 = buf_f32.to_bil();
984 assert_eq!(
985 bil_f32_raw, back_f32,
986 "f32 BIL roundtrip failed for {}x{}x{}",
987 bands, height, width
988 );
989 }
990 }
991
992 #[test]
993 fn test_default_color_interpretation() {
994 let colors_1 = default_color_interpretation(1);
995 assert_eq!(colors_1, vec![ColorInterpretation::Gray]);
996
997 let colors_3 = default_color_interpretation(3);
998 assert_eq!(
999 colors_3,
1000 vec![
1001 ColorInterpretation::Red,
1002 ColorInterpretation::Green,
1003 ColorInterpretation::Blue,
1004 ]
1005 );
1006
1007 let colors_4 = default_color_interpretation(4);
1008 assert_eq!(
1009 colors_4,
1010 vec![
1011 ColorInterpretation::Red,
1012 ColorInterpretation::Green,
1013 ColorInterpretation::Blue,
1014 ColorInterpretation::Alpha,
1015 ]
1016 );
1017
1018 let colors_5 = default_color_interpretation(5);
1019 assert!(
1020 colors_5
1021 .iter()
1022 .all(|c| *c == ColorInterpretation::Undefined)
1023 );
1024 }
1025}