@@ -34,6 +34,13 @@ pub struct RasterBand<'a> {
3434 _dataset : PhantomData < & ' a Dataset > ,
3535}
3636
37+ struct RasterIoRequest {
38+ window : ( isize , isize ) ,
39+ window_size : ( usize , usize ) ,
40+ size : ( usize , usize ) ,
41+ e_resample_alg : Option < ResampleAlg > ,
42+ }
43+
3744impl < ' a > RasterBand < ' a > {
3845 pub ( crate ) fn new (
3946 api : & ' static GdalApi ,
@@ -66,36 +73,70 @@ impl<'a> RasterBand<'a> {
6673 // for which zeroed memory is a valid bit pattern.
6774 let mut data: Vec < T > = vec ! [ unsafe { std:: mem:: zeroed( ) } ; len] ;
6875
69- let resample_alg = e_resample_alg. unwrap_or ( ResampleAlg :: NearestNeighbour ) ;
70- let mut extra_arg = GDALRasterIOExtraArg {
71- eResampleAlg : resample_alg. to_gdal ( ) ,
72- ..GDALRasterIOExtraArg :: default ( )
73- } ;
76+ self . read_impl (
77+ RasterIoRequest {
78+ window,
79+ window_size,
80+ size,
81+ e_resample_alg,
82+ } ,
83+ data. as_mut_ptr ( ) as * mut std:: ffi:: c_void ,
84+ T :: gdal_ordinal ( ) ,
85+ ) ?;
7486
75- let rv = unsafe {
76- call_gdal_api ! (
77- self . api,
78- GDALRasterIOEx ,
79- self . c_rasterband,
80- GF_Read ,
81- i32 :: try_from( window. 0 ) ?,
82- i32 :: try_from( window. 1 ) ?,
83- i32 :: try_from( window_size. 0 ) ?,
84- i32 :: try_from( window_size. 1 ) ?,
85- data. as_mut_ptr( ) as * mut std:: ffi:: c_void,
86- i32 :: try_from( size. 0 ) ?,
87- i32 :: try_from( size. 1 ) ?,
88- T :: gdal_ordinal( ) ,
89- 0 , // nPixelSpace (auto)
90- 0 , // nLineSpace (auto)
91- & mut extra_arg
92- )
93- } ;
94- if rv != CE_None {
95- return Err ( self . api . last_cpl_err ( rv as u32 ) ) ;
87+ Ok ( Buffer :: new ( size, data) )
88+ }
89+
90+ /// Read a window of this band into a byte buffer using the band's native GDAL data type.
91+ ///
92+ /// The returned bytes use GDAL's in-memory representation for the current platform.
93+ /// If `e_resample_alg` is `None`, use nearest-neighbour resampling.
94+ pub fn read_as_bytes (
95+ & self ,
96+ window : ( isize , isize ) ,
97+ window_size : ( usize , usize ) ,
98+ size : ( usize , usize ) ,
99+ e_resample_alg : Option < ResampleAlg > ,
100+ ) -> Result < Vec < u8 > > {
101+ let len = self . expected_byte_len ( size) ?;
102+ let mut data = vec ! [ 0u8 ; len] ;
103+ self . read_into_bytes ( window, window_size, size, & mut data, e_resample_alg) ?;
104+ Ok ( data)
105+ }
106+
107+ /// Read a window of this band into a caller-provided byte buffer using the band's native
108+ /// GDAL data type.
109+ ///
110+ /// The buffer length must equal `size.0 * size.1 * band_type().byte_size()`.
111+ /// If `e_resample_alg` is `None`, use nearest-neighbour resampling.
112+ pub fn read_into_bytes (
113+ & self ,
114+ window : ( isize , isize ) ,
115+ window_size : ( usize , usize ) ,
116+ size : ( usize , usize ) ,
117+ data : & mut [ u8 ] ,
118+ e_resample_alg : Option < ResampleAlg > ,
119+ ) -> Result < ( ) > {
120+ let expected_len = self . expected_byte_len ( size) ?;
121+ if data. len ( ) != expected_len {
122+ return Err ( GdalError :: BadArgument ( format ! (
123+ "byte buffer length {} does not match expected size {} for raster window {:?}" ,
124+ data. len( ) ,
125+ expected_len,
126+ size
127+ ) ) ) ;
96128 }
97129
98- Ok ( Buffer :: new ( size, data) )
130+ self . read_impl (
131+ RasterIoRequest {
132+ window,
133+ window_size,
134+ size,
135+ e_resample_alg,
136+ } ,
137+ data. as_mut_ptr ( ) as * mut std:: ffi:: c_void ,
138+ self . c_band_type ( ) ,
139+ )
99140 }
100141
101142 /// Write a buffer to this raster band.
@@ -188,6 +229,44 @@ impl<'a> RasterBand<'a> {
188229 }
189230 }
190231
232+ /// Fetch the band's nodata value as `u64`.
233+ /// Return `None` if no nodata value is set.
234+ pub fn no_data_value_u64 ( & self ) -> Option < u64 > {
235+ let mut success: i32 = 0 ;
236+ let value = unsafe {
237+ call_gdal_api ! (
238+ self . api,
239+ GDALGetRasterNoDataValueAsUInt64 ,
240+ self . c_rasterband,
241+ & mut success
242+ )
243+ } ;
244+ if success != 0 {
245+ Some ( value)
246+ } else {
247+ None
248+ }
249+ }
250+
251+ /// Fetch the band's nodata value as `i64`.
252+ /// Return `None` if no nodata value is set.
253+ pub fn no_data_value_i64 ( & self ) -> Option < i64 > {
254+ let mut success: i32 = 0 ;
255+ let value = unsafe {
256+ call_gdal_api ! (
257+ self . api,
258+ GDALGetRasterNoDataValueAsInt64 ,
259+ self . c_rasterband,
260+ & mut success
261+ )
262+ } ;
263+ if success != 0 {
264+ Some ( value)
265+ } else {
266+ None
267+ }
268+ }
269+
191270 /// Set the band's nodata value.
192271 /// Pass `None` to clear any existing nodata value.
193272 pub fn set_no_data_value ( & self , value : Option < f64 > ) -> Result < ( ) > {
@@ -248,6 +327,57 @@ impl<'a> RasterBand<'a> {
248327 pub fn api ( & self ) -> & ' static GdalApi {
249328 self . api
250329 }
330+
331+ fn read_impl (
332+ & self ,
333+ request : RasterIoRequest ,
334+ data_ptr : * mut std:: ffi:: c_void ,
335+ buf_type : GDALDataType ,
336+ ) -> Result < ( ) > {
337+ let resample_alg = request
338+ . e_resample_alg
339+ . unwrap_or ( ResampleAlg :: NearestNeighbour ) ;
340+ let mut extra_arg = GDALRasterIOExtraArg {
341+ eResampleAlg : resample_alg. to_gdal ( ) ,
342+ ..GDALRasterIOExtraArg :: default ( )
343+ } ;
344+
345+ let rv = unsafe {
346+ call_gdal_api ! (
347+ self . api,
348+ GDALRasterIOEx ,
349+ self . c_rasterband,
350+ GF_Read ,
351+ i32 :: try_from( request. window. 0 ) ?,
352+ i32 :: try_from( request. window. 1 ) ?,
353+ i32 :: try_from( request. window_size. 0 ) ?,
354+ i32 :: try_from( request. window_size. 1 ) ?,
355+ data_ptr,
356+ i32 :: try_from( request. size. 0 ) ?,
357+ i32 :: try_from( request. size. 1 ) ?,
358+ buf_type,
359+ 0 ,
360+ 0 ,
361+ & mut extra_arg
362+ )
363+ } ;
364+ if rv != CE_None {
365+ return Err ( self . api . last_cpl_err ( rv as u32 ) ) ;
366+ }
367+
368+ Ok ( ( ) )
369+ }
370+
371+ fn expected_byte_len ( & self , size : ( usize , usize ) ) -> Result < usize > {
372+ let bytes_per_value = self . band_type ( ) . byte_size ( ) ;
373+ if bytes_per_value == 0 {
374+ return Err ( GdalError :: BadArgument (
375+ "Cannot read bytes for band with unknown GDAL data type" . to_string ( ) ,
376+ ) ) ;
377+ }
378+
379+ Ok ( size. 0 * size. 1 * bytes_per_value)
380+ }
251381}
252382
253383/// Return the actual block size for a block index.
@@ -285,7 +415,7 @@ mod tests {
285415 use crate :: driver:: DriverManager ;
286416 use crate :: gdal_dyn_bindgen:: * ;
287417 use crate :: global:: with_global_gdal_api;
288- use crate :: raster:: types:: ResampleAlg ;
418+ use crate :: raster:: types:: { Buffer , ResampleAlg } ;
289419
290420 fn fixture ( name : & str ) -> String {
291421 sedona_testing:: data:: test_raster ( name) . unwrap ( )
@@ -336,6 +466,102 @@ mod tests {
336466 . unwrap ( ) ;
337467 }
338468
469+ #[ test]
470+ fn test_read_raster_as_bytes_u8 ( ) {
471+ with_global_gdal_api ( |api| {
472+ let driver = DriverManager :: get_driver_by_name ( api, "MEM" ) . unwrap ( ) ;
473+ let dataset = driver. create_with_band_type :: < u8 > ( "" , 2 , 3 , 1 ) . unwrap ( ) ;
474+ let rasterband = dataset. rasterband ( 1 ) . unwrap ( ) ;
475+ let mut buffer = Buffer :: new ( ( 2 , 3 ) , vec ! [ 7u8 , 7 , 7 , 10 , 8 , 12 ] ) ;
476+ rasterband. write ( ( 0 , 0 ) , ( 2 , 3 ) , & mut buffer) . unwrap ( ) ;
477+
478+ let rv = rasterband
479+ . read_as_bytes ( ( 0 , 0 ) , ( 2 , 3 ) , ( 2 , 3 ) , None )
480+ . unwrap ( ) ;
481+ assert_eq ! ( rv, vec![ 7u8 , 7 , 7 , 10 , 8 , 12 ] ) ;
482+ } )
483+ . unwrap ( ) ;
484+ }
485+
486+ #[ test]
487+ fn test_read_raster_as_bytes_u16 ( ) {
488+ with_global_gdal_api ( |api| {
489+ let driver = DriverManager :: get_driver_by_name ( api, "MEM" ) . unwrap ( ) ;
490+ let dataset = driver. create_with_band_type :: < u16 > ( "" , 2 , 2 , 1 ) . unwrap ( ) ;
491+ let rasterband = dataset. rasterband ( 1 ) . unwrap ( ) ;
492+ let mut buffer = Buffer :: new ( ( 2 , 2 ) , vec ! [ 1u16 , 256 , 511 , 1024 ] ) ;
493+ rasterband. write ( ( 0 , 0 ) , ( 2 , 2 ) , & mut buffer) . unwrap ( ) ;
494+
495+ let rv = rasterband
496+ . read_as_bytes ( ( 0 , 0 ) , ( 2 , 2 ) , ( 2 , 2 ) , None )
497+ . unwrap ( ) ;
498+ let expected: Vec < u8 > = vec ! [ 1u16 , 256 , 511 , 1024 ]
499+ . into_iter ( )
500+ . flat_map ( |v| v. to_ne_bytes ( ) )
501+ . collect ( ) ;
502+ assert_eq ! ( rv, expected) ;
503+ } )
504+ . unwrap ( ) ;
505+ }
506+
507+ #[ test]
508+ fn test_read_into_bytes_matches_read_as_bytes ( ) {
509+ with_global_gdal_api ( |api| {
510+ let driver = DriverManager :: get_driver_by_name ( api, "MEM" ) . unwrap ( ) ;
511+ let dataset = driver. create_with_band_type :: < u16 > ( "" , 2 , 2 , 1 ) . unwrap ( ) ;
512+ let rasterband = dataset. rasterband ( 1 ) . unwrap ( ) ;
513+ let mut buffer = Buffer :: new ( ( 2 , 2 ) , vec ! [ 5u16 , 6 , 7 , 8 ] ) ;
514+ rasterband. write ( ( 0 , 0 ) , ( 2 , 2 ) , & mut buffer) . unwrap ( ) ;
515+
516+ let expected = rasterband
517+ . read_as_bytes ( ( 0 , 0 ) , ( 2 , 2 ) , ( 2 , 2 ) , None )
518+ . unwrap ( ) ;
519+ let mut actual = vec ! [ 0u8 ; expected. len( ) ] ;
520+ rasterband
521+ . read_into_bytes ( ( 0 , 0 ) , ( 2 , 2 ) , ( 2 , 2 ) , & mut actual, None )
522+ . unwrap ( ) ;
523+
524+ assert_eq ! ( actual, expected) ;
525+ } )
526+ . unwrap ( ) ;
527+ }
528+
529+ #[ test]
530+ fn test_read_into_bytes_with_wrong_len ( ) {
531+ with_global_gdal_api ( |api| {
532+ let driver = DriverManager :: get_driver_by_name ( api, "MEM" ) . unwrap ( ) ;
533+ let dataset = driver. create_with_band_type :: < u16 > ( "" , 2 , 2 , 1 ) . unwrap ( ) ;
534+ let rasterband = dataset. rasterband ( 1 ) . unwrap ( ) ;
535+ let mut data = vec ! [ 0u8 ; 7 ] ;
536+
537+ let err = rasterband
538+ . read_into_bytes ( ( 0 , 0 ) , ( 2 , 2 ) , ( 2 , 2 ) , & mut data, None )
539+ . unwrap_err ( ) ;
540+ assert ! ( matches!( err, crate :: errors:: GdalError :: BadArgument ( _) ) ) ;
541+ } )
542+ . unwrap ( ) ;
543+ }
544+
545+ #[ test]
546+ fn test_read_as_bytes_with_average_resample ( ) {
547+ with_global_gdal_api ( |api| {
548+ let driver = DriverManager :: get_driver_by_name ( api, "MEM" ) . unwrap ( ) ;
549+ let dataset = driver. create_with_band_type :: < u8 > ( "" , 4 , 4 , 1 ) . unwrap ( ) ;
550+ let rasterband = dataset. rasterband ( 1 ) . unwrap ( ) ;
551+ let mut buffer = Buffer :: new (
552+ ( 4 , 4 ) ,
553+ vec ! [ 1u8 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 ] ,
554+ ) ;
555+ rasterband. write ( ( 0 , 0 ) , ( 4 , 4 ) , & mut buffer) . unwrap ( ) ;
556+
557+ let rv = rasterband
558+ . read_as_bytes ( ( 0 , 0 ) , ( 4 , 4 ) , ( 2 , 2 ) , Some ( ResampleAlg :: Average ) )
559+ . unwrap ( ) ;
560+ assert_eq ! ( rv. len( ) , 4 ) ;
561+ } )
562+ . unwrap ( ) ;
563+ }
564+
339565 #[ test]
340566 fn test_get_no_data_value ( ) {
341567 with_global_gdal_api ( |api| {
@@ -369,4 +595,38 @@ mod tests {
369595 } )
370596 . unwrap ( ) ;
371597 }
598+
599+ #[ test]
600+ fn test_set_no_data_value_u64 ( ) {
601+ with_global_gdal_api ( |api| {
602+ let driver = DriverManager :: get_driver_by_name ( api, "MEM" ) . unwrap ( ) ;
603+ let dataset = driver. create_with_band_type :: < u64 > ( "" , 20 , 10 , 1 ) . unwrap ( ) ;
604+ let rasterband = dataset. rasterband ( 1 ) . unwrap ( ) ;
605+ let nodata = 9_007_199_254_740_993u64 ;
606+
607+ assert_eq ! ( rasterband. no_data_value_u64( ) , None ) ;
608+ assert ! ( rasterband. set_no_data_value_u64( Some ( nodata) ) . is_ok( ) ) ;
609+ assert_eq ! ( rasterband. no_data_value_u64( ) , Some ( nodata) ) ;
610+ assert ! ( rasterband. set_no_data_value_u64( None ) . is_ok( ) ) ;
611+ assert_eq ! ( rasterband. no_data_value_u64( ) , None ) ;
612+ } )
613+ . unwrap ( ) ;
614+ }
615+
616+ #[ test]
617+ fn test_set_no_data_value_i64 ( ) {
618+ with_global_gdal_api ( |api| {
619+ let driver = DriverManager :: get_driver_by_name ( api, "MEM" ) . unwrap ( ) ;
620+ let dataset = driver. create_with_band_type :: < i64 > ( "" , 20 , 10 , 1 ) . unwrap ( ) ;
621+ let rasterband = dataset. rasterband ( 1 ) . unwrap ( ) ;
622+ let nodata = -9_007_199_254_740_993i64 ;
623+
624+ assert_eq ! ( rasterband. no_data_value_i64( ) , None ) ;
625+ assert ! ( rasterband. set_no_data_value_i64( Some ( nodata) ) . is_ok( ) ) ;
626+ assert_eq ! ( rasterband. no_data_value_i64( ) , Some ( nodata) ) ;
627+ assert ! ( rasterband. set_no_data_value_i64( None ) . is_ok( ) ) ;
628+ assert_eq ! ( rasterband. no_data_value_i64( ) , None ) ;
629+ } )
630+ . unwrap ( ) ;
631+ }
372632}
0 commit comments