Skip to content

Commit f054059

Browse files
authored
Merge pull request #2768 from image-rs/efficient-copy
Propagate copy_from through SubImage
2 parents c4c8525 + cf4dbaf commit f054059

File tree

2 files changed

+61
-7
lines changed

2 files changed

+61
-7
lines changed

benches/copy_from.rs

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use image::{GenericImage, ImageBuffer, Rgba};
44
pub fn bench_copy_from(c: &mut Criterion) {
55
let at = image::math::Rect::from_xy_ranges(256..1280, 256..1280);
66

7+
let mut target = ImageBuffer::from_pixel(2048, 2048, Rgba([0u8, 0, 0, 255]));
78
let src = ImageBuffer::from_pixel(2048, 2048, Rgba([255u8, 0, 0, 255]));
8-
let mut dst = ImageBuffer::from_pixel(2048, 2048, Rgba([0u8, 0, 0, 255]));
99
let part = ImageBuffer::from_pixel(at.width, at.height, Rgba([255u8, 0, 0, 255]));
1010

1111
let view = image::GenericImageView::view(&src, at);
@@ -22,25 +22,68 @@ pub fn bench_copy_from(c: &mut Criterion) {
2222
let skip = samples.as_view().unwrap();
2323

2424
c.bench_function("copy_from", |b| {
25-
b.iter(|| dst.copy_from(black_box(&src), 0, 0));
25+
b.iter(|| target.copy_from(black_box(&src), 0, 0));
2626
});
2727

2828
c.bench_function("copy_at", |b| {
29-
b.iter(|| dst.copy_from(black_box(&part), at.x, at.y));
29+
b.iter(|| target.copy_from(black_box(&part), at.x, at.y));
3030
});
3131

3232
c.bench_function("copy_view", |b| {
33-
b.iter(|| dst.copy_from(black_box(&*view), at.x, at.y));
33+
b.iter(|| target.copy_from(black_box(&*view), at.x, at.y));
3434
});
3535

3636
c.bench_function("copy_fill", |b| {
37-
b.iter(|| dst.copy_from(black_box(&singular), at.x, at.y));
37+
b.iter(|| target.copy_from(black_box(&singular), at.x, at.y));
3838
});
3939

4040
c.bench_function("copy_strides", |b| {
41-
b.iter(|| dst.copy_from(black_box(&skip), at.x, at.y));
41+
b.iter(|| target.copy_from(black_box(&skip), at.x, at.y));
4242
});
4343
}
4444

45-
criterion_group!(benches, bench_copy_from);
45+
pub fn bench_copy_subimage_from(c: &mut Criterion) {
46+
let viewport = image::math::Rect::from_xy_ranges(256..1280, 256..1280);
47+
let at = image::math::Rect::from_xy_ranges(128..512, 128..512);
48+
49+
let mut target = ImageBuffer::from_pixel(2048, 2048, Rgba([0u8, 0, 0, 255]));
50+
let mut target = target.sub_image(viewport);
51+
52+
let src = ImageBuffer::from_pixel(viewport.width, viewport.height, Rgba([255u8, 0, 0, 255]));
53+
let part = ImageBuffer::from_pixel(at.width, at.height, Rgba([255u8, 0, 0, 255]));
54+
let view = image::GenericImageView::view(&src, at);
55+
56+
const BG: Rgba<u8> = Rgba([0u8, 0, 0, 255]);
57+
let samples = image::flat::FlatSamples::with_monocolor(&BG, at.width, at.height);
58+
let singular = samples.as_view().unwrap();
59+
60+
let mut samples = src.as_flat_samples();
61+
samples.layout.width = at.width / 2;
62+
samples.layout.width_stride *= 2;
63+
samples.layout.height = at.height / 2;
64+
samples.layout.height_stride *= 2;
65+
let skip = samples.as_view().unwrap();
66+
67+
c.bench_function("copy_subimage_from", |b| {
68+
b.iter(|| target.copy_from(black_box(&src), 0, 0));
69+
});
70+
71+
c.bench_function("copy_subimage_at", |b| {
72+
b.iter(|| target.copy_from(black_box(&part), at.x, at.y));
73+
});
74+
75+
c.bench_function("copy_subimage_view", |b| {
76+
b.iter(|| target.copy_from(black_box(&*view), at.x, at.y));
77+
});
78+
79+
c.bench_function("copy_subimage_fill", |b| {
80+
b.iter(|| target.copy_from(black_box(&singular), at.x, at.y));
81+
});
82+
83+
c.bench_function("copy_subimage_strides", |b| {
84+
b.iter(|| target.copy_from(black_box(&skip), at.x, at.y));
85+
});
86+
}
87+
88+
criterion_group!(benches, bench_copy_from, bench_copy_subimage_from);
4689
criterion_main!(benches);

src/images/sub_image.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,17 @@ where
237237
self.image
238238
.blend_pixel(x + self.xoffset, y + self.yoffset, pixel);
239239
}
240+
241+
fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> Result<(), crate::ImageError>
242+
where
243+
O: GenericImageView<Pixel = Self::Pixel>,
244+
{
245+
Rect::from_image_at(other, x, y).test_in_bounds(self)?;
246+
// Dispatch the inner images `copy_from` method with adjusted offsets. this ensures its
247+
// potentially optimized implementation gets used.
248+
self.image
249+
.copy_from(other, x + self.xoffset, y + self.yoffset)
250+
}
240251
}
241252

242253
#[cfg(test)]

0 commit comments

Comments
 (0)