Skip to content

Commit 0dfa1d5

Browse files
author
HeroicKatora
authored
Merge pull request #1437 from fintelia/bug-1430
Fix #1430
2 parents 9579426 + 0664960 commit 0dfa1d5

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

src/codecs/bmp/decoder.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,7 +1467,7 @@ impl<'a, R: 'a + Read + Seek> ImageDecoderExt<'a> for BmpDecoder<R> {
14671467
progress_callback: F,
14681468
) -> ImageResult<()> {
14691469
let start = self.reader.seek(SeekFrom::Current(0))?;
1470-
image::load_rect(x, y, width, height, buf, progress_callback, self, |_, _| unreachable!(),
1470+
image::load_rect(x, y, width, height, buf, progress_callback, self, |_, _| Ok(()),
14711471
|s, buf| s.read_image_data(buf))?;
14721472
self.reader.seek(SeekFrom::Start(start))?;
14731473
Ok(())
@@ -1476,7 +1476,7 @@ impl<'a, R: 'a + Read + Seek> ImageDecoderExt<'a> for BmpDecoder<R> {
14761476

14771477
#[cfg(test)]
14781478
mod test {
1479-
use super::Bitfield;
1479+
use super::*;
14801480

14811481
#[test]
14821482
fn test_bitfield_len() {
@@ -1492,4 +1492,13 @@ mod test {
14921492
}
14931493
}
14941494
}
1495+
1496+
#[test]
1497+
fn read_rect() {
1498+
let f = std::fs::File::open("tests/images/bmp/images/Core_8_Bit.bmp").unwrap();
1499+
let mut decoder = super::BmpDecoder::new(f).unwrap();
1500+
1501+
let mut buf: Vec<u8> = vec![0; 8 * 8 * 3];
1502+
decoder.read_rect(0, 0, 8, 8, &mut *buf).unwrap();
1503+
}
14951504
}

src/image.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,11 +387,34 @@ pub(crate) fn load_rect<'a, D, F, F1, F2, E>(x: u32, y: u32, width: u32, height:
387387
let mut bytes_read = 0u64;
388388
let mut current_scanline = 0;
389389
let mut tmp = Vec::new();
390+
let mut tmp_scanline = None;
390391

391392
{
392393
// Read a range of the image starting from byte number `start` and continuing until byte
393394
// 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+
395418
let target_scanline = start / scanline_bytes;
396419
if target_scanline != current_scanline {
397420
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:
407430
} else {
408431
tmp.resize(scanline_bytes as usize, 0u8);
409432
read_scanline(decoder, &mut tmp)?;
433+
tmp_scanline = Some(current_scanline);
410434

411435
let offset = start.saturating_sub(position);
412436
let len = (end - start)
@@ -1185,6 +1209,45 @@ mod tests {
11851209
}
11861210
}
11871211

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+
11881251
#[test]
11891252
fn test_image_format_from_path() {
11901253
fn from_path(s: &str) -> ImageResult<ImageFormat> {

0 commit comments

Comments
 (0)