mod ops;
pub use ops::*;
pub type ImgVec<Pixel> = Img<Vec<Pixel>>;
pub type ImgRef<'a, Pixel> = Img<&'a [Pixel]>;
pub trait ImgExt<Pixel> {
fn width_padded(&self) -> usize;
fn height_padded(&self) -> usize;
}
#[derive(Clone)]
pub struct Img<Container> {
pub buf: Container,
pub stride: usize,
pub width: u32,
pub height: u32,
}
impl<Container> Img<Container> {
#[inline(always)]
pub fn width(&self) -> usize {self.width as usize}
#[inline(always)]
pub fn height(&self) -> usize {self.height as usize}
#[inline(always)]
pub fn stride(&self) -> usize {self.stride}
}
impl<Pixel,Container> ImgExt<Pixel> for Img<Container> where Container: AsRef<[Pixel]> {
#[inline(always)]
fn width_padded(&self) -> usize {
self.stride()
}
#[inline(always)]
fn height_padded(&self) -> usize {
let len = self.buf.as_ref().len();
assert_eq!(0, len % self.stride);
len/self.stride
}
}
impl<'a, T> Copy for Img<&'a [T]> {}
impl<'a, T> Img<&'a [T]> {
#[inline]
pub fn sub_image(&self, left: usize, top: usize, width: usize, height: usize) -> Self {
assert!(height > 0);
assert!(width > 0);
assert!(top+height <= self.height());
assert!(left+width <= self.width());
let start = self.stride * top + left;
debug_assert!(self.buf.len() >= start + self.stride * height + width - self.stride, "the buffer is too small to fit the subimage");
let full_strides_end = start + self.stride * height;
let end = if self.buf.len() >= full_strides_end {
full_strides_end
} else {
full_strides_end + width - self.stride
};
let buf = &self.buf[start .. end];
Self::new_stride(buf, width, height, self.stride)
}
pub fn iter(&self) -> std::slice::Iter<T> {
self.buf.iter()
}
}
impl<Container> IntoIterator for Img<Container> where Container: IntoIterator {
type Item = Container::Item;
type IntoIter = Container::IntoIter;
fn into_iter(self) -> Container::IntoIter {
self.buf.into_iter()
}
}
impl<T> ImgVec<T> {
pub fn sub_image_mut(&mut self, left: usize, top: usize, width: usize, height: usize) -> Img<&mut [T]> {
assert!(height > 0);
assert!(width > 0);
assert!(top+height <= self.height());
assert!(left+width <= self.width());
let start = self.stride * top + left;
let buf = &mut self.buf[start .. start + self.stride * height + width - self.stride];
Img::new_stride(buf, width, height, self.stride)
}
#[inline]
pub fn sub_image(&self, left: usize, top: usize, width: usize, height: usize) -> ImgRef<T> {
self.as_ref().sub_image(left, top, width, height)
}
#[inline]
pub fn as_ref(&self) -> ImgRef<T> {
self.new_buf(self.buf.as_ref())
}
pub fn iter(&self) -> std::slice::Iter<T> {
self.buf.iter()
}
}
impl<Container> Img<Container> {
#[inline]
pub fn new_stride(buf: Container, width: usize, height: usize, stride: usize) -> Self {
assert!(height > 0);
assert!(width > 0);
assert!(stride >= width as usize);
debug_assert!(height < <u32>::max_value() as usize);
debug_assert!(width < <u32>::max_value() as usize);
Img {
buf: buf,
width: width as u32,
height: height as u32,
stride: stride,
}
}
#[inline]
pub fn new(buf: Container, width: usize, height: usize) -> Self {
Self::new_stride(buf, width, height, width)
}
}
impl<OldContainer> Img<OldContainer> {
#[inline]
pub fn new_buf<NewContainer, OldPixel, NewPixel>(&self, new_buf: NewContainer) -> Img<NewContainer>
where NewContainer: AsRef<[NewPixel]>, OldContainer: AsRef<[OldPixel]> {
assert_eq!(self.buf.as_ref().len(), new_buf.as_ref().len());
Img::new_stride(new_buf, self.width(), self.height(), self.stride)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn with_vec() {
let bytes = vec![0u8;20];
let old = Img::new_stride(bytes, 10,2,10);
let _ = old.new_buf(vec![6u16;20]);
}
#[test]
fn with_slice() {
let bytes = vec![0u8;20];
let _ = Img::new_stride(bytes.as_slice(), 10,2,10);
let vec = ImgVec::new_stride(bytes, 10,2,10);
for _ in vec.iter() {}
for _ in vec.as_ref().buf.iter() {}
for _ in vec {}
}
#[test]
fn sub() {
let img = Img::new_stride(vec![1,2,3,4,
5,6,7,8,
9], 3, 2, 4);
assert_eq!(img.buf[img.stride], 5);
assert_eq!(img.buf[img.stride + img.width()-1], 7);
{
let refimg = img.as_ref();
let refimg2 = refimg;
let s1 = refimg.sub_image(1, 0, refimg.width()-1, refimg.height());
let _ = s1.sub_image(1, 0, s1.width()-1, s1.height());
let subimg = refimg.sub_image(1, 1, 2, 1);
assert_eq!(subimg.buf[0], 6);
assert_eq!(subimg.stride, refimg2.stride);
assert!(subimg.stride() * subimg.height() + subimg.width() - subimg.stride <= subimg.buf.len());
assert_eq!(refimg.buf[0], 1);
}
let mut img = img;
let subimg = img.sub_image_mut(1, 1, 2, 1);
assert_eq!(subimg.buf[0], 6);
}
}