use super::super::drawable::*;
use super::super::transform::*;
use super::Image;
use coord::{Coord, ToUnsigned};
use core::marker::PhantomData;
use pixelcolor::PixelColor;
use unsignedcoord::{ToSigned, UnsignedCoord};
#[derive(Debug)]
pub struct Image8BPP<'a, C: PixelColor> {
width: u32,
height: u32,
imagedata: &'a [u8],
pub offset: Coord,
pixel_type: PhantomData<C>,
}
impl<'a, C> Dimensions for Image8BPP<'a, C>
where
C: PixelColor,
{
fn top_left(&self) -> Coord {
self.offset
}
fn bottom_right(&self) -> Coord {
self.top_left() + self.size().to_signed()
}
fn size(&self) -> UnsignedCoord {
let height = self.height;
let width = self.width;
UnsignedCoord::new(width, height)
}
}
impl<'a, C> Image<'a> for Image8BPP<'a, C>
where
C: PixelColor,
{
fn new(imagedata: &'a [u8], width: u32, height: u32) -> Self {
Self {
width,
height,
imagedata,
offset: Coord::new(0, 0),
pixel_type: PhantomData,
}
}
}
impl<'a, C> IntoIterator for &'a Image8BPP<'a, C>
where
C: PixelColor,
{
type Item = Pixel<C>;
type IntoIter = Image8BPPIterator<'a, C>;
fn into_iter(self) -> Self::IntoIter {
Image8BPPIterator {
im: self,
x: 0,
y: 0,
}
}
}
#[derive(Debug)]
pub struct Image8BPPIterator<'a, C: 'a>
where
C: PixelColor,
{
x: u32,
y: u32,
im: &'a Image8BPP<'a, C>,
}
impl<'a, C> Iterator for Image8BPPIterator<'a, C>
where
C: PixelColor,
{
type Item = Pixel<C>;
fn next(&mut self) -> Option<Self::Item> {
let current_pixel = loop {
let w = self.im.width;
let h = self.im.height;
let x = self.x;
let y = self.y;
if x >= w || y >= h {
return None;
}
let offset = (y * w) + x;
let bit_value = self.im.imagedata[offset as usize];
let current_pixel = self.im.offset + Coord::new(x as i32, y as i32);
self.x += 1;
if self.x >= w {
self.x = 0;
self.y += 1;
}
if current_pixel[0] >= 0 && current_pixel[1] >= 0 {
break Pixel(current_pixel.to_unsigned(), bit_value.into());
}
};
Some(current_pixel)
}
}
impl<'a, C> Drawable for Image8BPP<'a, C> where C: PixelColor {}
impl<'a, C> Transform for Image8BPP<'a, C>
where
C: PixelColor,
{
fn translate(&self, by: Coord) -> Self {
Self {
offset: self.offset + by,
..*self.clone()
}
}
fn translate_mut(&mut self, by: Coord) -> &mut Self {
self.offset += by;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use pixelcolor::PixelColorU8;
use unsignedcoord::UnsignedCoord;
#[test]
fn negative_top_left() {
let image: Image8BPP<PixelColorU8> = Image8BPP::new(
&[0xff, 0x00, 0xbb, 0x00, 0xcc, 0x00, 0xee, 0x00, 0xaa],
3,
3,
)
.translate(Coord::new(-1, -1));
assert_eq!(image.top_left(), Coord::new(-1, -1));
assert_eq!(image.bottom_right(), Coord::new(2, 2));
assert_eq!(image.size(), UnsignedCoord::new(3, 3));
}
#[test]
fn dimensions() {
let image: Image8BPP<PixelColorU8> = Image8BPP::new(
&[0xff, 0x00, 0xbb, 0x00, 0xcc, 0x00, 0xee, 0x00, 0xaa],
3,
3,
)
.translate(Coord::new(100, 200));
assert_eq!(image.top_left(), Coord::new(100, 200));
assert_eq!(image.bottom_right(), Coord::new(103, 203));
assert_eq!(image.size(), UnsignedCoord::new(3, 3));
}
#[test]
fn it_can_have_negative_offsets() {
let image: Image8BPP<PixelColorU8> = Image8BPP::new(
&[0xff, 0x00, 0xbb, 0x00, 0xcc, 0x00, 0xee, 0x00, 0xaa],
3,
3,
)
.translate(Coord::new(-1, -1));
let mut it = image.into_iter();
assert_eq!(
it.next(),
Some(Pixel(UnsignedCoord::new(0, 0), 0xcc_u8.into()))
);
assert_eq!(
it.next(),
Some(Pixel(UnsignedCoord::new(1, 0), 0x00_u8.into()))
);
assert_eq!(
it.next(),
Some(Pixel(UnsignedCoord::new(0, 1), 0x00_u8.into()))
);
assert_eq!(
it.next(),
Some(Pixel(UnsignedCoord::new(1, 1), 0xaa_u8.into()))
);
assert_eq!(it.next(), None);
}
}