@@ -8,9 +8,7 @@ use geoengine_datatypes::operations::image::{ColorMapper, RgbParams};
88use geoengine_datatypes:: raster:: { FromIndexFn , GridIndexAccess , GridShapeAccess } ;
99use geoengine_datatypes:: {
1010 operations:: image:: { Colorizer , RasterColorizer , RgbaColor , ToPng } ,
11- primitives:: {
12- AxisAlignedRectangle , BandSelection , CacheHint , RasterQueryRectangle , TimeInterval ,
13- } ,
11+ primitives:: { AxisAlignedRectangle , CacheHint , RasterQueryRectangle , TimeInterval } ,
1412 raster:: { Blit , ConvertDataType , EmptyGrid2D , GeoTransform , GridOrEmpty , Pixel , RasterTile2D } ,
1513} ;
1614use num_traits:: AsPrimitive ;
@@ -23,14 +21,24 @@ use tracing::{span, Level};
2321#[ allow( clippy:: too_many_arguments) ]
2422pub async fn raster_stream_to_png_bytes < T : Pixel , C : QueryContext + ' static > (
2523 processor : Box < dyn RasterQueryProcessor < RasterType = T > > ,
26- mut query_rect : RasterQueryRectangle ,
24+ query_rect : RasterQueryRectangle ,
2725 mut query_ctx : C ,
2826 width : u32 ,
2927 height : u32 ,
3028 time : Option < TimeInterval > ,
3129 raster_colorizer : Option < RasterColorizer > ,
3230 conn_closed : BoxFuture < ' _ , ( ) > ,
3331) -> Result < ( Vec < u8 > , CacheHint ) > {
32+ debug_assert ! (
33+ query_rect. attributes. count( ) <= 3
34+ || query_rect
35+ . attributes
36+ . as_slice( )
37+ . windows( 2 )
38+ . all( |w| w[ 0 ] < w[ 1 ] ) , // TODO: replace with `is_sorted` once it is stable
39+ "bands must be sorted and at most three bands can be queried"
40+ ) ;
41+
3442 let span = span ! ( Level :: TRACE , "raster_stream_to_png_bytes" ) ;
3543 let _enter = span. enter ( ) ;
3644
@@ -52,21 +60,24 @@ pub async fn raster_stream_to_png_bytes<T: Pixel, C: QueryContext + 'static>(
5260 RasterColorizer :: SingleBand { band, .. } => vec ! [ band] ,
5361 } ;
5462
55- if query_rect
56- . attributes
57- . as_slice ( )
63+ let band_positions = required_bands
5864 . iter ( )
59- . any ( |band| !required_bands. contains ( band) )
60- {
65+ . filter_map ( |band| {
66+ query_rect
67+ . attributes
68+ . as_slice ( )
69+ . iter ( )
70+ . position ( |b| b == band)
71+ } )
72+ . collect :: < Vec < usize > > ( ) ;
73+
74+ if band_positions. len ( ) != required_bands. len ( ) {
6175 return Err ( PngCreationError :: ColorizerBandsMustBePresentInQuery {
6276 bands_present : query_rect. attributes . as_vec ( ) ,
6377 required_bands,
6478 } ) ?;
6579 }
6680
67- // modify query to only query the required bands
68- query_rect. attributes = BandSelection :: new_unchecked ( required_bands) ;
69-
7081 let query_abort_trigger = query_ctx. abort_trigger ( ) ?;
7182
7283 let x_query_resolution = query_rect. spatial_bounds . size_x ( ) / f64:: from ( width) ;
@@ -114,6 +125,7 @@ pub async fn raster_stream_to_png_bytes<T: Pixel, C: QueryContext + 'static>(
114125 width,
115126 height,
116127 rgba_params,
128+ band_positions,
117129 conn_closed,
118130 query_abort_trigger,
119131 )
@@ -160,45 +172,45 @@ async fn multi_band_colorizer_to_png_bytes<T: Pixel, C: QueryContext + 'static>(
160172 width : u32 ,
161173 height : u32 ,
162174 rgb_params : RgbParams ,
175+ band_positions : Vec < usize > ,
163176 conn_closed : BoxFuture < ' _ , ( ) > ,
164177 query_abort_trigger : QueryAbortTrigger ,
165178) -> Result < ( Vec < u8 > , CacheHint ) > {
166- const RGB_CHANNEL_COUNT : usize = 3 ;
167-
168- debug_assert_eq ! ( query_rect. attributes. count( ) , RGB_CHANNEL_COUNT as u32 ) ;
169-
170- let tile_stream = processor. query ( query_rect. clone ( ) , & query_ctx) . await ?;
171-
172- let band_numbers: [ u32 ; 3 ] = [
173- query_rect. attributes . as_slice ( ) [ 0 ] ,
174- query_rect. attributes . as_slice ( ) [ 1 ] ,
175- query_rect. attributes . as_slice ( ) [ 2 ] ,
176- ] ;
177-
179+ let rgb_channel_count = query_rect. attributes . count ( ) as usize ;
178180 let no_data_color = rgb_params. no_data_color ;
179-
180181 let tile_template: RasterTile2D < u32 > = tile_template. convert_data_type ( ) ;
181- let output_tile = Box :: pin (
182- tile_stream
183- // .map_ok(|tile| tile.convert_data_type())
184- . try_chunks ( RGB_CHANNEL_COUNT )
185- . fold ( Ok ( tile_template) , |raster2d, chunk| async move {
186- let chunk = chunk. boxed_context ( error:: QueryDidNotProduceNextChunk ) ?;
182+ let red_band_index = band_positions[ 0 ] ;
183+ let green_band_index = band_positions[ 1 ] ;
184+ let blue_band_index = band_positions[ 2 ] ;
187185
188- let mut tuple: [ RasterTile2D < T > ; RGB_CHANNEL_COUNT ] = chunk
189- . try_into ( )
190- . map_err ( |_| PngCreationError :: RgbChunkIsNotThreeBands ) ?;
186+ let tile_stream = processor. query ( query_rect. clone ( ) , & query_ctx) . await ?;
191187
192- // tiles don't arrive in query order, so we need to sort them to be in query order
193- // TODO: remove this when we have a guarantee that tiles are in query order
194- sort_by_indices ( & mut tuple, & band_numbers) ;
188+ let output_tile = Box :: pin ( tile_stream. try_chunks ( rgb_channel_count) . fold (
189+ Ok ( tile_template) ,
190+ |raster2d, chunk| async move {
191+ let chunk = chunk. boxed_context ( error:: QueryDidNotProduceNextChunk ) ?;
195192
196- // TODO: spawn blocking task
197- let rgb_tile = compute_rgb_tile ( tuple, & rgb_params) ;
193+ if chunk. len ( ) != rgb_channel_count {
194+ return Err ( PngCreationError :: RgbChunkIsNotEnoughBands ) ?;
195+ }
198196
199- blit_tile ( raster2d, Ok ( rgb_tile) )
200- } ) ,
201- ) ;
197+ // TODO: spawn blocking task
198+ let rgb_tile = crate :: util:: spawn_blocking ( move || {
199+ compute_rgb_tile (
200+ [
201+ & chunk[ red_band_index] ,
202+ & chunk[ green_band_index] ,
203+ & chunk[ blue_band_index] ,
204+ ] ,
205+ & rgb_params,
206+ )
207+ } )
208+ . await
209+ . boxed_context ( error:: UnexpectedComputational ) ?;
210+
211+ blit_tile ( raster2d, Ok ( rgb_tile) )
212+ } ,
213+ ) ) ;
202214
203215 let result = abortable_query_execution ( output_tile, conn_closed, query_abort_trigger) . await ?;
204216 Ok ( (
@@ -209,24 +221,6 @@ async fn multi_band_colorizer_to_png_bytes<T: Pixel, C: QueryContext + 'static>(
209221 ) )
210222}
211223
212- /// Sorts the tiles by their band numbers and returns them in the order of the band numbers.
213- /// Uses bubble sort since the number of bands is small.
214- fn sort_by_indices < T > ( tiles : & mut [ T ; 3 ] , band_numbers : & [ u32 ; 3 ] ) {
215- debug_assert_eq ! ( tiles. len( ) , 3 ) ;
216- debug_assert_eq ! ( band_numbers. len( ) , 3 ) ;
217-
218- let mut band_numbers = [ band_numbers[ 0 ] , band_numbers[ 1 ] , band_numbers[ 2 ] ] ;
219-
220- for r in [ 2 , 1 ] {
221- for i in 0 ..r {
222- if band_numbers[ i] > band_numbers[ i + 1 ] {
223- tiles. swap ( i, i + 1 ) ;
224- band_numbers. swap ( i, i + 1 ) ;
225- }
226- }
227- }
228- }
229-
230224fn blit_tile < T > (
231225 raster2d : Result < RasterTile2D < T > > ,
232226 tile : Result < RasterTile2D < T > > ,
@@ -271,7 +265,7 @@ pub fn default_colorizer_gradient<T: Pixel>() -> Colorizer {
271265}
272266
273267pub fn compute_rgb_tile < P : Pixel > (
274- [ red, green, blue] : [ RasterTile2D < P > ; 3 ] ,
268+ [ red, green, blue] : [ & RasterTile2D < P > ; 3 ] ,
275269 params : & RgbParams ,
276270) -> RasterTile2D < u32 > {
277271 fn fit_to_interval_0_255 ( value : f64 , min : f64 , max : f64 , scale : f64 ) -> u32 {
@@ -347,8 +341,10 @@ pub enum PngCreationError {
347341 } ,
348342 #[ snafu( display( "Query did not produce next chunk: {source}" ) ) ]
349343 QueryDidNotProduceNextChunk { source : Box < dyn ErrorSource > } ,
350- #[ snafu( display( "RGB chunk is not three bands" ) ) ]
351- RgbChunkIsNotThreeBands ,
344+ #[ snafu( display( "RGB chunk is not enough bands" ) ) ]
345+ RgbChunkIsNotEnoughBands ,
346+ #[ snafu( display( "Unexpected computational error" ) ) ]
347+ UnexpectedComputationalError { source : Box < dyn ErrorSource > } ,
352348}
353349
354350#[ cfg( test) ]
@@ -429,21 +425,4 @@ mod tests {
429425 image_bytes. as_slice( )
430426 ) ;
431427 }
432-
433- #[ test]
434- fn it_sorts_by_index ( ) {
435- let mut values = [ 2 , 1 , 3 ] ;
436- let band_numbers = [ 2 , 1 , 5 ] ;
437-
438- sort_by_indices ( & mut values, & band_numbers) ;
439-
440- assert_eq ! ( values, [ 1 , 2 , 3 ] ) ;
441-
442- let mut values = [ 3 , 2 , 1 ] ;
443- let band_numbers = [ 5 , 2 , 1 ] ;
444-
445- sort_by_indices ( & mut values, & band_numbers) ;
446-
447- assert_eq ! ( values, [ 1 , 2 , 3 ] ) ;
448- }
449428}
0 commit comments