I'm using the image crate for picture manipulation and want to create a little wrapper to make my code a bit fancier.
extern crate image;
const BLACK: [u8; 4] = [0, 0, 0, 255];
const WHITE: [u8; 4] = [255, 255, 255, 255];
const RED: [u8; 4] = [255, 0, 0, 255];
pub struct Picture {
buffer: image::ImageBuffer,
width: u32,
height: u32
}
impl Picture {
// My functions like fill(), line() etc.
}
But when I compile this, I have an error:
src\pic.rs:11:13: 11:31 error: wrong number of type arguments: expected 2, found 0 [E0243]
src\pic.rs:11 buffer: image::ImageBuffer,
^~~~~~~~~~~~~~~~~~
In the source, I saw that ImageBuffer
accepts two arguments:
pub struct ImageBuffer<P: Pixel, Container> {
width: u32,
height: u32,
_phantom: PhantomData<P>,
data: Container,
}
So I decided to put those arguments in the Picture
declaration:
pub struct Picture {
buffer: image::ImageBuffer<image::Pixel>,
}
And got another error:
src\pic.rs:11:32: 11:44 error: the value of the associated type `Subpixel` (from the trait `pic::image::buffer::Pixel`) must be specified [E0191]
src\pic.rs:11 buffer: image::ImageBuffer<image::Pixel>,
^~~~~~~~~~~~
That means I must specify some value for the Subpixel
type, and I don't get it. I don't know how to declare that Container
type, I can't find anything useful in the sources. I tried to re-read the Rust Book, examples, rustc --explain E0191
but I am still lost.
update:
In sources found next declaration:
impl<P, Container> ImageBuffer<P, Container>
where P: Pixel + 'static,
P::Subpixel: 'static,
Container: Deref<Target=[P::Subpixel]>
And Subpixel
is:
/// Primitive trait from old stdlib
pub trait Primitive: Copy + NumCast + Num + PartialOrd<Self> + Clone + Bounded {
}
But it not public for my crate.
Looking at the documentation for ImageBuffer
, we can see the trait requirements for the type parameters:
impl<P, Container> ImageBuffer<P, Container>
where P: Pixel + 'static,
P::Subpixel: 'static,
Container: Deref<Target=[P::Subpixel]>
So, it's important that the second type parameter can dereference to a slice of subpixels. Subpixel
is determined by the Pixel
trait, which has a few implementations:
Rgb<T>
Luma<T>
Rgba<T>
LumaA<T>
Where T
is the subpixel type.
This is all pretty complicated, but should provide a good bit of power and generality.
Note that I've only shown one of the implementation blocks. There are others that require DerefMut
or that require the subpixel to be a u8
.
How do you actually use it? First you need to pick a specific color and subpixel type. Based on your colors, it looks like you want to use a 4-channel, 8-bit color type. That would be Rgba<u8>
.
There are many types that could dereference to an &[u8]
or &mut [u8]
. The obvious (but not only!) choice would be a Vec<u8>
.
Combining these two, your structure needs to be something like:
buffer: image::ImageBuffer<Rgba<u8>, Vec<u8>>,
Then, it's just a matter of creating the structure and doing things to it:
extern crate image;
use image::{ImageBuffer, Pixel, Rgba};
pub struct Picture {
buffer: ImageBuffer<Rgba<u8>, Vec<u8>>,
}
impl Picture {
fn new(width: u32, height: u32) -> Self {
// There's probably a cleaner way to figure out the right size
let storage = vec![0; 4 * width as usize * height as usize];
let buf = ImageBuffer::from_raw(width, height, storage).unwrap();
Picture {
buffer: buf,
}
}
fn fill_red(&mut self) {
let color = Rgba::from_channels(255, 0, 0, 255);
for p in self.buffer.pixels_mut() {
*p = color;
}
}
}
fn main() {
let mut pic = Picture::new(256, 256);
pic.fill_red();
}
Note that ImageBuffer
already tracks the width and height, so there's no real reason to track them a second time.
However, all of this is the hard way. There are convenience functions like new
which will allocate storage for you:
buffer: ImageBuffer::new(width, height),
These functions are hard-coded to return a Vec
as the Container
. If you didn't see that in the docs, you could try something like printing the type:
let () = ImageBuffer::new(width, height);
Which would tell you the type in the error message:
expected `image::buffer::ImageBuffer<_, collections::vec::Vec<_>>`,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With