use crate::{AlphaMode, Ch8, Ch16, Channel, Format, GammaMode, PixModes};
use std::convert::TryFrom;
use std::marker::PhantomData;
pub struct RasterBuilder<F: Format> {
alpha_mode: AlphaMode,
gamma_mode: GammaMode,
_format : PhantomData<F>,
}
pub struct Raster<F: Format> {
alpha_mode: AlphaMode,
gamma_mode: GammaMode,
width : u32,
height : u32,
pixels : Box<[F]>,
}
pub struct RasterIter<'a, F: Format> {
raster: &'a Raster<F>,
left: u32,
right: u32,
bottom: u32,
x: u32,
y: u32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Region {
x: i32,
y: i32,
width: u32,
height: u32,
}
impl<F: Format> Into<Box<[F]>> for Raster<F> {
fn into(self) -> Box<[F]> {
self.pixels
}
}
impl<F: Format> Into<Vec<F>> for Raster<F> {
fn into(self) -> Vec<F> {
self.pixels.into()
}
}
impl<F: Format> RasterBuilder<F> {
pub fn new() -> Self {
let alpha_mode = AlphaMode::Separated;
let gamma_mode = GammaMode::Srgb;
let _format = PhantomData;
RasterBuilder { alpha_mode, gamma_mode, _format }
}
pub fn alpha_mode(mut self, alpha_mode: AlphaMode) -> Self {
self.alpha_mode = alpha_mode;
self
}
pub fn gamma_mode(mut self, gamma_mode: GammaMode) -> Self {
self.gamma_mode = gamma_mode;
self
}
pub fn with_clear(self, width: u32, height: u32) -> Raster<F> {
self.with_color(width, height, F::default())
}
pub fn with_color(self, width: u32, height: u32, clr: F) -> Raster<F> {
let alpha_mode = self.alpha_mode;
let gamma_mode = self.gamma_mode;
let len = (width * height) as usize;
let pixels = vec![clr; len].into_boxed_slice();
Raster { alpha_mode, gamma_mode, width, height, pixels }
}
pub fn with_raster<C, H, P>(self, o: &Raster<P>) -> Raster<F>
where C: Channel + From<H>, H: Channel, F: Format<Chan=C>,
P: Format<Chan=H>
{
let mut r = RasterBuilder::new().with_clear(o.width(), o.height());
let reg = o.region();
r.set_region(reg, o.region_iter(reg));
r
}
pub fn with_pixels<B>(self, width: u32, height: u32, pixels: B) -> Raster<F>
where B: Into<Box<[F]>>
{
let alpha_mode = self.alpha_mode;
let gamma_mode = self.gamma_mode;
let len = (width * height) as usize;
let pixels = pixels.into();
assert_eq!(len, pixels.len());
Raster { alpha_mode, gamma_mode, width, height, pixels }
}
pub fn with_u8_buffer<B>(self, width: u32, height: u32, buffer: B)
-> Raster<F> where B: Into<Box<[u8]>>, F: Format<Chan=Ch8>
{
let alpha_mode = self.alpha_mode;
let gamma_mode = self.gamma_mode;
let len = (width * height) as usize;
let buffer: Box<[u8]> = buffer.into();
let capacity = buffer.len();
assert_eq!(len * std::mem::size_of::<F>(), capacity);
let slice = std::boxed::Box::<[u8]>::into_raw(buffer);
let pixels: Box<[F]> = unsafe {
let ptr = (*slice).as_mut_ptr() as *mut F;
let slice = std::slice::from_raw_parts_mut(ptr, len);
Box::from_raw(slice)
};
Raster { alpha_mode, gamma_mode, width, height, pixels }
}
pub fn with_u16_buffer<B>(self, width: u32, height: u32, buffer: B)
-> Raster<F> where B: Into<Box<[u16]>>, F: Format<Chan=Ch16>
{
let alpha_mode = self.alpha_mode;
let gamma_mode = self.gamma_mode;
let len = (width * height) as usize;
let buffer: Box<[u16]> = buffer.into();
let capacity = buffer.len();
assert_eq!(len * std::mem::size_of::<F>(),
capacity * std::mem::size_of::<u16>());
let slice = std::boxed::Box::<[u16]>::into_raw(buffer);
let pixels: Box<[F]> = unsafe {
let ptr = (*slice).as_mut_ptr() as *mut F;
let slice = std::slice::from_raw_parts_mut(ptr, len);
Box::from_raw(slice)
};
Raster { alpha_mode, gamma_mode, width, height, pixels }
}
}
impl<F: Format> Raster<F> {
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn pixel(&self, x: u32, y: u32) -> F {
let row = &self.as_slice_row(y);
row[x as usize]
}
pub fn set_pixel<P>(&mut self, x: u32, y: u32, p: P)
where F: From<P>
{
let row = &mut self.as_slice_row_mut(y);
row[x as usize] = p.into();
}
pub fn clear(&mut self) {
for p in self.pixels.iter_mut() {
*p = F::default();
}
}
pub fn region(&self) -> Region {
Region::new(0, 0, self.width(), self.height())
}
pub fn region_iter<R>(&self, reg: R) -> RasterIter<F>
where R: Into<Region>
{
RasterIter::new(self, reg.into())
}
pub fn set_region<C, R, I, P, H>(&mut self, reg: R, mut it: I)
where F: Format<Chan=C>, C: Channel + From<H>, H: Channel,
P: Format<Chan=H>, R: Into<Region>, I: Iterator<Item=P> + PixModes
{
let reg = reg.into();
let alpha_mode = self.alpha_mode;
let gamma_mode = self.gamma_mode;
let x0 = if reg.x >= 0 { reg.x as u32 } else { self.width() };
let x1 = self.width().min(x0 + reg.width);
let (x0, x1) = (x0 as usize, x1 as usize);
let y0 = if reg.y >= 0 { reg.y as u32 } else { self.height() };
let y1 = self.height().min(y0 + reg.height);
if y0 < y1 && x0 < x1 {
for yi in y0..y1 {
let row = self.as_slice_row_mut(yi);
for x in x0..x1 {
if let Some(p) = it.next() {
row[x] = Self::convert_pixel(p, &it, alpha_mode,
gamma_mode);
}
}
}
}
}
fn convert_pixel<C, P, H, M>(p: P, m: &M, alpha_mode: AlphaMode,
gamma_mode: GammaMode) -> F
where F: Format<Chan=C>, C: Channel + From<H>, H: Channel,
P: Format<Chan=H>, M: PixModes
{
let rgba = p.rgba();
let rgba = match m.gamma_mode() {
Some(m) => {
[m.decode(rgba[0]),
m.decode(rgba[1]),
m.decode(rgba[2]),
rgba[3]]
},
None => rgba,
};
let rgba = match m.alpha_mode() {
Some(m) => {
[m.decode(rgba[0], rgba[3]),
m.decode(rgba[1], rgba[3]),
m.decode(rgba[2], rgba[3]),
rgba[3]]
},
None => rgba,
};
let red = C::from(rgba[0]);
let green = C::from(rgba[1]);
let blue = C::from(rgba[2]);
let alpha = C::from(rgba[3]);
let rgba = [red, green, blue, alpha];
let rgba = match m.alpha_mode() {
Some(_) => {
[alpha_mode.encode(red, alpha),
alpha_mode.encode(green, alpha),
alpha_mode.encode(blue, alpha),
alpha]
},
None => rgba,
};
let rgba = match m.gamma_mode() {
Some(_) => {
[gamma_mode.encode(rgba[0]),
gamma_mode.encode(rgba[1]),
gamma_mode.encode(rgba[2]),
rgba[3]]
},
None => rgba,
};
F::with_rgba(rgba)
}
pub fn as_slice(&self) -> &[F] {
&self.pixels
}
pub fn as_slice_mut(&mut self) -> &mut [F] {
&mut self.pixels
}
pub fn as_slice_row(&self, y: u32) -> &[F] {
debug_assert!(y < self.height);
let s = (y * self.width) as usize;
let t = s + self.width as usize;
&self.pixels[s..t]
}
pub fn as_slice_row_mut(&mut self, y: u32) -> &mut [F] {
debug_assert!(y < self.height);
let s = (y * self.width) as usize;
let t = s + self.width as usize;
&mut self.pixels[s..t]
}
pub fn as_u8_slice_row(&self, y: u32) -> &[u8] {
debug_assert!(y < self.height);
let s = (y * self.width) as usize;
let t = s + self.width as usize;
Self::u8_slice(&self.pixels[s..t])
}
fn u8_slice(pix: &[F]) -> &[u8] {
unsafe { pix.align_to::<u8>().1 }
}
pub fn as_u8_slice(&self) -> &[u8] {
Self::u8_slice(&self.pixels)
}
pub fn as_u8_slice_mut(&mut self) -> &mut [u8] {
Self::u8_slice_mut(&mut self.pixels)
}
fn u8_slice_mut(pix: &mut [F]) -> &mut [u8] {
unsafe { pix.align_to_mut::<u8>().1 }
}
}
impl<'a, F: Format> RasterIter<'a, F> {
fn new(raster: &'a Raster<F>, region: Region) -> Self {
let y = u32::try_from(region.y).unwrap_or(0);
let bottom = u32::try_from(region.bottom()).unwrap_or(0);
let x = u32::try_from(region.x).unwrap_or(0);
let right = u32::try_from(region.right()).unwrap_or(0);
let left = x;
RasterIter { raster, left, right, bottom, x, y }
}
}
impl<'a, F: Format> PixModes for RasterIter<'a, F> {
fn alpha_mode(&self) -> Option<AlphaMode> {
Some(self.raster.alpha_mode)
}
fn gamma_mode(&self) -> Option<GammaMode> {
Some(self.raster.gamma_mode)
}
}
impl<'a, F: Format> Iterator for RasterIter<'a, F> {
type Item = F;
fn next(&mut self) -> Option<Self::Item> {
if self.x >= self.right {
self.x = self.left;
self.y += 1;
if self.y >= self.bottom {
return None;
}
}
let p = self.raster.pixel(self.x, self.y);
self.x += 1;
Some(p)
}
}
impl From<(i32, i32, u32, u32)> for Region {
fn from(r: (i32, i32, u32, u32)) -> Self {
Region::new(r.0, r.1, r.2, r.3)
}
}
impl Region {
pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
Region { x, y, width, height }
}
pub fn intersection<R>(self, rhs: R) -> Self
where R: Into<Self>
{
let rhs = rhs.into();
let x0 = self.x.max(rhs.x);
let x1 = self.right().min(rhs.right());
let w = (x1 - x0) as u32;
let y0 = self.y.max(rhs.y);
let y1 = self.bottom().min(rhs.bottom());
let h = (y1 - y0) as u32;
Region::new(x0, y0, w, h)
}
fn right(self) -> i32 {
let x = i64::from(self.x) + i64::from(self.width);
if x < std::i32::MAX.into() {
x as i32
} else {
self.x
}
}
fn bottom(self) -> i32 {
let y = i64::from(self.y) + i64::from(self.height);
if y < std::i32::MAX.into() {
y as i32
} else {
self.y
}
}
}
#[cfg(test)]
mod test {
use super::*;
use super::super::*;
#[test]
fn mask8() {
let mut r = RasterBuilder::<Mask8>::new().with_clear(3, 3);
r.set_pixel(0, 0, 0xFF);
r.set_pixel(2, 0, 0x12);
r.set_pixel(1, 1, 0x34);
r.set_pixel(0, 2, 0x56);
r.set_pixel(2, 2, 0x78);
let v = vec![
0xFF, 0x00, 0x12,
0x00, 0x34, 0x00,
0x56, 0x00, 0x78,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn mask16() {
let mut r = RasterBuilder::<Mask16>::new().with_clear(3, 3);
r.set_pixel(2, 0, 0x9ABC);
r.set_pixel(1, 1, 0x5678);
r.set_pixel(0, 2, 0x1234);
r.set_pixel(0, 0, 0xFFFF);
r.set_pixel(2, 2, 0x8080);
let v = vec![
0xFF,0xFF, 0x00,0x00, 0xBC,0x9A,
0x00,0x00, 0x78,0x56, 0x00,0x00,
0x34,0x12, 0x00,0x00, 0x80,0x80,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn mask32() {
let p: Vec<_> = vec![
0.25, 0.5, 0.75, 1.0,
0.5, 0.55, 0.7, 0.8,
0.75, 0.65, 0.6, 0.4,
1.0, 0.75, 0.5, 0.25,
].iter().map(|p| Mask::new(Ch32::new(*p))).collect();
let mut r = RasterBuilder::<Mask32>::new().with_pixels(4, 4, p);
let clr = Mask32::new(Ch32::new(0.05));
r.set_region((1, 1, 2, 2), clr);
let v: Vec<_> = vec![
0.25, 0.5, 0.75, 1.0,
0.5, 0.05, 0.05, 0.8,
0.75, 0.05, 0.05, 0.4,
1.0, 0.75, 0.5, 0.25,
].iter().map(|p| Mask::new(Ch32::new(*p))).collect();
let r2 = RasterBuilder::<Mask32>::new().with_pixels(4, 4, v);
assert_eq!(r.as_slice(), r2.as_slice());
}
#[test]
fn rgb8() {
let mut r = RasterBuilder::<Rgb8>::new().with_clear(4, 4);
let rgb = Rgb8::new(0xCC, 0xAA, 0xBB);
r.set_region((1, 1, 2, 2), rgb);
let v = vec![
0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
0x00,0x00,0x00, 0xCC,0xAA,0xBB, 0xCC,0xAA,0xBB, 0x00,0x00,0x00,
0x00,0x00,0x00, 0xCC,0xAA,0xBB, 0xCC,0xAA,0xBB, 0x00,0x00,0x00,
0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn gray8() {
let mut r = RasterBuilder::<Gray8>::new().with_clear(4, 4);
r.set_region((0, 0, 1, 1), Gray8::from(0x23));
r.set_region((10, 10, 1, 1), Gray8::from(0x45));
r.set_region((2, 2, 10, 10), Gray8::from(0xBB));
let v = vec![
0x23,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x00,0x00,0xBB,0xBB,
0x00,0x00,0xBB,0xBB,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn rgb8_buffer() {
let b = vec![
0xAA,0x00,0x00, 0x00,0x11,0x22, 0x33,0x44,0x55,
0x00,0xBB,0x00, 0x66,0x77,0x88, 0x99,0xAA,0xBB,
0x00,0x00,0xCC, 0xCC,0xDD,0xEE, 0xFF,0x00,0x11,
];
let mut r = RasterBuilder::<Rgb8>::new().with_u8_buffer(3, 3, b);
let rgb = Rgb8::new(0x12, 0x34, 0x56);
r.set_region((0, 1, 2, 1), rgb);
let v = vec![
0xAA,0x00,0x00, 0x00,0x11,0x22, 0x33,0x44,0x55,
0x12,0x34,0x56, 0x12,0x34,0x56, 0x99,0xAA,0xBB,
0x00,0x00,0xCC, 0xCC,0xDD,0xEE, 0xFF,0x00,0x11,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn grayalpha16_buffer() {
let b = vec![
0x1001,0x5005, 0x1000,0x3002, 0x5004,0x7006,
0x2002,0x6006, 0x9008,0xB00A, 0xD00C,0xF00E,
0x3003,0x7007, 0xE00F,0xC00D, 0xA00B,0x8009,
];
let mut r = RasterBuilder::<GrayAlpha16>::new().with_u16_buffer(3, 3, b);
r.set_region((1, 0, 2, 2), GrayAlpha16::new(0x4444));
let v = vec![
0x01,0x10,0x05,0x50, 0x44,0x44,0xFF,0xFF, 0x44,0x44,0xFF,0xFF,
0x02,0x20,0x06,0x60, 0x44,0x44,0xFF,0xFF, 0x44,0x44,0xFF,0xFF,
0x03,0x30,0x07,0x70, 0x0F,0xE0,0x0D,0xC0, 0x0B,0xA0,0x09,0x80,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn gray_to_rgb() {
let mut r = RasterBuilder::<Gray8>::new().with_clear(3, 3);
r.set_region((2, 0, 4, 2), Gray8::new(0x45));
r.set_region((0, 2, 2, 10), Gray8::new(0xDA));
let r = RasterBuilder::<Rgb8>::new().with_raster(&r);
let v = vec![
0x00,0x00,0x00, 0x00,0x00,0x00, 0x45,0x45,0x45,
0x00,0x00,0x00, 0x00,0x00,0x00, 0x45,0x45,0x45,
0xDA,0xDA,0xDA, 0xDA,0xDA,0xDA, 0x00,0x00,0x00,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn rgb_to_gray() {
let mut r = RasterBuilder::<Rgb16>::new().with_clear(3, 3);
r.set_region((1, 0, 4, 2), Rgb16::new(0x4321, 0x9085, 0x5543));
r.set_region((0, 1, 1, 10), Rgb16::new(0x5768, 0x4091, 0x5000));
let r = RasterBuilder::<Gray8>::new().with_raster(&r);
let v = vec![
0x00, 0x90, 0x90,
0x56, 0x90, 0x90,
0x56, 0x00, 0x00,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn gray_to_mask() {
let mut r = RasterBuilder::<GrayAlpha8>::new().with_clear(3, 3);
r.set_region((0, 1, 2, 8), GrayAlpha8::with_alpha(0x67, 0x94));
r.set_region((2, 0, 1, 10), GrayAlpha8::with_alpha(0xBA, 0xA2));
let r = RasterBuilder::<Mask16>::new().with_raster(&r);
let v = vec![
0x00, 0x00, 0x00, 0x00, 0xA2, 0xA2,
0x94, 0x94, 0x94, 0x94, 0xA2, 0xA2,
0x94, 0x94, 0x94, 0x94, 0xA2, 0xA2,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn mask_to_gray() {
let mut r = RasterBuilder::<Mask16>::new().with_clear(3, 3);
r.set_region((0, 1, 3, 8), Mask16::new(0xABCD));
r.set_region((2, 0, 1, 3), Mask16::new(0x9876));
let r = RasterBuilder::<GrayAlpha8>::new().with_raster(&r);
let v = vec![
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x98,
0xFF, 0xAB, 0xFF, 0xAB, 0xFF, 0x98,
0xFF, 0xAB, 0xFF, 0xAB, 0xFF, 0x98,
];
assert_eq!(r.as_u8_slice(), &v[..]);
}
#[test]
fn copy_region_gray() {
let mut g0 = RasterBuilder::<Gray16>::new().with_clear(3, 3);
let mut g1 = RasterBuilder::<Gray16>::new()
.gamma_mode(GammaMode::Linear)
.with_clear(3, 3);
g0.set_region((0, 2, 2, 5), Gray16::new(0x4455));
g0.set_region((2, 0, 3, 2), Gray8::new(0x33));
g1.set_region(g1.region(), g0.region_iter(g0.region()));
let v = vec![
0x00,0x00, 0x00,0x00, 0x7A,0x08,
0x00,0x00, 0x00,0x00, 0x7A,0x08,
0xD4,0x0E, 0xD4,0x0E, 0x00,0x00,
];
assert_eq!(g1.as_u8_slice(), &v[..]);
}
#[test]
fn from_rgb8() {
let r = RasterBuilder::<Rgb8>::new().with_clear(50, 50);
let _ = RasterBuilder::<Rgb16>::new().with_raster(&r);
let _ = RasterBuilder::<Rgb32>::new().with_raster(&r);
let _ = RasterBuilder::<Rgba8>::new().with_raster(&r);
let _ = RasterBuilder::<Rgba16>::new().with_raster(&r);
let _ = RasterBuilder::<Rgba32>::new().with_raster(&r);
let _ = RasterBuilder::<Gray8>::new().with_raster(&r);
let _ = RasterBuilder::<Gray16>::new().with_raster(&r);
let _ = RasterBuilder::<Gray32>::new().with_raster(&r);
let _ = RasterBuilder::<GrayAlpha8>::new().with_raster(&r);
let _ = RasterBuilder::<GrayAlpha16>::new().with_raster(&r);
let _ = RasterBuilder::<GrayAlpha32>::new().with_raster(&r);
let _ = RasterBuilder::<Mask8>::new().with_raster(&r);
let _ = RasterBuilder::<Mask16>::new().with_raster(&r);
let _ = RasterBuilder::<Mask32>::new().with_raster(&r);
}
#[test]
fn from_mask8() {
let r = RasterBuilder::<Mask8>::new().with_clear(50, 50);
let _ = RasterBuilder::<Rgb8>::new().with_raster(&r);
let _ = RasterBuilder::<Rgb16>::new().with_raster(&r);
let _ = RasterBuilder::<Rgb32>::new().with_raster(&r);
let _ = RasterBuilder::<Rgba8>::new().with_raster(&r);
let _ = RasterBuilder::<Rgba16>::new().with_raster(&r);
let _ = RasterBuilder::<Rgba32>::new().with_raster(&r);
let _ = RasterBuilder::<Gray8>::new().with_raster(&r);
let _ = RasterBuilder::<Gray16>::new().with_raster(&r);
let _ = RasterBuilder::<Gray32>::new().with_raster(&r);
let _ = RasterBuilder::<GrayAlpha8>::new().with_raster(&r);
let _ = RasterBuilder::<GrayAlpha16>::new().with_raster(&r);
let _ = RasterBuilder::<GrayAlpha32>::new().with_raster(&r);
let _ = RasterBuilder::<Mask8>::new().with_raster(&r);
let _ = RasterBuilder::<Mask16>::new().with_raster(&r);
let _ = RasterBuilder::<Mask32>::new().with_raster(&r);
}
#[test]
fn region_size() {
assert_eq!(std::mem::size_of::<Region>(), 16);
}
#[test]
fn intersect() -> Result<(), ()> {
let r = Region::new(0, 0, 5, 5);
assert_eq!(r, Region::new(0, 0, 5, 5));
assert_eq!(r, r.intersection(Region::new(0, 0, 10, 10)));
assert_eq!(r, r.intersection(Region::new(-5, -5, 10, 10)));
assert_eq!(Region::new(0, 0, 4, 4), r.intersection(
Region::new(-1, -1, 5, 5)));
assert_eq!(Region::new(1, 2, 1, 3), r.intersection(
Region::new(1, 2, 1, 100)));
assert_eq!(Region::new(2, 1, 3, 1), r.intersection(
Region::new(2, 1, 100, 1)));
Ok(())
}
}