kornelski / imgref

A trivial Rust struct for interchange of pixel buffers with width, height & stride
https://lib.rs/crates/imgref
Apache License 2.0
59 stars 5 forks source link

Add `copy_sub_image()` based on `ptr::copy_nonoverlapping()` #9

Open yoanlcq opened 6 years ago

yoanlcq commented 6 years ago

This is doable with the current API using row iterators, but it's slightly annoying. I'd like a single function that does this. My use case is building font atlases from indiviual bitmaps.

I figure this would (roughly) look like this:

impl<'a, Pixel: Copy> ImgRefMut<'a, Pixel> {
    pub fn copy_sub_image(&mut self, dst_left: usize, dst_top: usize, src: ImgRef<Pixel>, src_left: usize, src_top: usize, width: usize, height: usize) {
        self.sub_image_mut(dst_left, dst_top, width, height).copy_image(src.sub_image(src_left, src_top, width, height))
    }
    pub fn copy_image(&mut self, src: ImgRef<Pixel>) {
        assert_eq!(self.width(), src.width());
        assert_eq!(self.height(), src.height());
        // Then, use row iterators and `ptr::copy_nonoverlapping()` to perform the copy efficiently.
    }
}

(The API is inspired by GDI's BitBlt()).

kornelski commented 6 years ago

Yes, copying would be useful. However, I wouldn't trust any Win32 APIs as an example of a good design ;)

So two issues with this:

yoanlcq commented 6 years ago

I agree with point 2. As for point 1, I don't see what's wrong; The function uses "copynonoverlapping" so it should start with "copy", because that's what it does. Other names I could come up with are "replace" or "overwrite", and at the end there's either "image", "sub_image", "other", "region" or "pixels".

In fact I think we could "copy" (haha) what the image crate does; Namely, its copy_from function, which appears to correspond to what you want.

kornelski commented 6 years ago

There could be copy_from for T: Copy, and clone_from for T: Clone

kornelski commented 6 years ago

but I'm not sure where the location should go

copy_from(top, left, src) seems wrong, because it sounds like from top/left. copy_from(src, top, left) is better. Or copy_at(src, top, left) maybe?

yoanlcq commented 6 years ago

OK, what about :

I've added "rows" in-between for these reasons :

Would that be OK?

kornelski commented 6 years ago

Interesting observation about clone_*_from. I agree, but "rows" makes me wonder what's special about them. Area? Fragment? Rect? Sub? sub_image?

I'm loving that the borrow checker will ensure copy_nonoverlapping is indeed non-overlapping.

yoanlcq commented 6 years ago

So how about copy_sub_image/clone_sub_image ? I kinda liked rows because that's what the implementation is necessarily supposed to do; In the existing API there's rows() but not cols(), and rightfully so; this is the expected memory layout. copy_[area/fragment/rect/sub] are inconsistent with existing names in the API, and look like they qualify the right-hand-side.

To me, the current candidates are (along with their clone couterpart, and in no particular order):

This kind of discussion could go on for a long time and at the end of the day the API will be very hard to misuse. So I prefer to let you have the final word on this. :)

Lastly, I guess using the same naming as a well-estabished crate such as image could be nice (the name would then be copy_from).

kornelski commented 6 years ago

Yea, clone|copy_sub_image is probably the best.