@@ -387,11 +387,34 @@ pub(crate) fn load_rect<'a, D, F, F1, F2, E>(x: u32, y: u32, width: u32, height:
387
387
let mut bytes_read = 0u64 ;
388
388
let mut current_scanline = 0 ;
389
389
let mut tmp = Vec :: new ( ) ;
390
+ let mut tmp_scanline = None ;
390
391
391
392
{
392
393
// Read a range of the image starting from byte number `start` and continuing until byte
393
394
// number `end`. Updates `current_scanline` and `bytes_read` appropiately.
394
- let mut read_image_range = |start : u64 , end : u64 | -> ImageResult < ( ) > {
395
+ let mut read_image_range = |mut start : u64 , end : u64 | -> ImageResult < ( ) > {
396
+ // If the first scanline we need is already stored in the temporary buffer, then handle
397
+ // it first.
398
+ let target_scanline = start / scanline_bytes;
399
+ if tmp_scanline == Some ( target_scanline) {
400
+ let position = target_scanline * scanline_bytes;
401
+ let offset = start. saturating_sub ( position) ;
402
+ let len = ( end - start)
403
+ . min ( scanline_bytes - offset)
404
+ . min ( end - position) ;
405
+
406
+ buf[ ( bytes_read as usize ) ..] [ ..len as usize ]
407
+ . copy_from_slice ( & tmp[ offset as usize ..] [ ..len as usize ] ) ;
408
+ bytes_read += len;
409
+ start += len;
410
+
411
+ progress_callback ( Progress { current : bytes_read, total : total_bytes} ) ;
412
+
413
+ if start == end {
414
+ return Ok ( ( ) ) ;
415
+ }
416
+ }
417
+
395
418
let target_scanline = start / scanline_bytes;
396
419
if target_scanline != current_scanline {
397
420
seek_scanline ( decoder, target_scanline) ?;
@@ -407,6 +430,7 @@ pub(crate) fn load_rect<'a, D, F, F1, F2, E>(x: u32, y: u32, width: u32, height:
407
430
} else {
408
431
tmp. resize ( scanline_bytes as usize , 0u8 ) ;
409
432
read_scanline ( decoder, & mut tmp) ?;
433
+ tmp_scanline = Some ( current_scanline) ;
410
434
411
435
let offset = start. saturating_sub ( position) ;
412
436
let len = ( end - start)
@@ -1185,6 +1209,45 @@ mod tests {
1185
1209
}
1186
1210
}
1187
1211
1212
+ #[ test]
1213
+ fn test_load_rect_single_scanline ( ) {
1214
+ const DATA : [ u8 ; 25 ] = [ 0 , 1 , 2 , 3 , 4 ,
1215
+ 5 , 6 , 7 , 8 , 9 ,
1216
+ 10 , 11 , 12 , 13 , 14 ,
1217
+ 15 , 16 , 17 , 18 , 19 ,
1218
+ 20 , 21 , 22 , 23 , 24 ] ;
1219
+
1220
+ struct MockDecoder ;
1221
+ impl < ' a > ImageDecoder < ' a > for MockDecoder {
1222
+ type Reader = Box < dyn io:: Read > ;
1223
+ fn dimensions ( & self ) -> ( u32 , u32 ) { ( 5 , 5 ) }
1224
+ fn color_type ( & self ) -> ColorType { ColorType :: L8 }
1225
+ fn into_reader ( self ) -> ImageResult < Self :: Reader > { unimplemented ! ( ) }
1226
+ fn scanline_bytes ( & self ) -> u64 { 25 }
1227
+ }
1228
+
1229
+ // Ensure that seek scanline is called only once.
1230
+ let mut seeks = 0 ;
1231
+ let seek_scanline = |_d : & mut MockDecoder , n : u64 | -> io:: Result < ( ) > {
1232
+ seeks += 1 ;
1233
+ assert_eq ! ( n, 0 ) ;
1234
+ assert_eq ! ( seeks, 1 ) ;
1235
+ Ok ( ( ) )
1236
+ } ;
1237
+
1238
+ fn read_scanline ( _m : & mut MockDecoder , buf : & mut [ u8 ] ) -> io:: Result < ( ) > {
1239
+ buf. copy_from_slice ( & DATA ) ;
1240
+ Ok ( ( ) )
1241
+ }
1242
+
1243
+ let mut output = [ 0 ; 26 ] ;
1244
+ load_rect ( 1 , 1 , 2 , 4 , & mut output, |_|{ } ,
1245
+ & mut MockDecoder ,
1246
+ seek_scanline, read_scanline) . unwrap ( ) ;
1247
+ assert_eq ! ( output[ 0 ..9 ] , [ 6 , 7 , 11 , 12 , 16 , 17 , 21 , 22 , 0 ] ) ;
1248
+ }
1249
+
1250
+
1188
1251
#[ test]
1189
1252
fn test_image_format_from_path ( ) {
1190
1253
fn from_path ( s : & str ) -> ImageResult < ImageFormat > {
0 commit comments