use std::fs::File;
use std::io;
use std::io::Write;
use std::ptr;
use png;
use png::HasParameters;
use path::FillRule;
use imgbuf::{accumulate_non_zero, accumulate_odd};
pub struct Mask {
width : u32,
height : u32,
pixels : Vec<u8>,
}
impl Mask {
pub(crate) fn new(width: u32, height: u32) -> Mask {
let len = (width * height) as usize;
let cap = ((len + 7) >> 3) << 3;
let mut pixels = vec![0; cap];
for _ in 0..cap-len { pixels.pop(); };
Mask { width, height, pixels }
}
pub(crate) fn width(&self) -> u32 {
self.width
}
pub(crate) fn height(&self) -> u32 {
self.height
}
pub fn pixels(&self) -> &[u8] {
&self.pixels
}
pub(crate) fn clear(&mut self) {
let len = self.pixels.len();
self.fill(0, len, 0);
}
fn fill(&mut self, x: usize, len: usize, v: u8) {
assert!(x + len <= self.pixels.len());
unsafe {
let pix = self.pixels.as_mut_ptr().offset(x as isize);
ptr::write_bytes(pix, v, len);
}
}
pub(crate) fn scan_accumulate(&mut self, sgn_area: &mut [i16], row: u32,
rule: FillRule)
{
assert!(self.width <= sgn_area.len() as u32);
assert!(row < self.height);
let dst = self.scan_line(row);
match rule {
FillRule::NonZero => accumulate_non_zero(dst, sgn_area),
FillRule::EvenOdd => accumulate_odd(dst, sgn_area),
}
}
fn scan_line(&mut self, row: u32) -> &mut [u8] {
let s = (row * self.width) as usize;
let t = s + self.width as usize;
&mut self.pixels[s..t]
}
pub fn write_pgm(&self, filename: &str) -> io::Result<()> {
let fl = File::create(filename)?;
let mut bw = io::BufWriter::new(fl);
let w = bw.get_mut();
w.write_all(format!("P5\n{} {}\n255\n", self.width, self.height)
.as_bytes())?;
w.write_all(&self.pixels[..])?;
w.flush()?;
Ok(())
}
pub fn write_png(&self, filename: &str) -> io::Result<()> {
let fl = File::create(filename)?;
let ref mut bw = io::BufWriter::new(fl);
let mut enc = png::Encoder::new(bw, self.width, self.height);
enc.set(png::ColorType::Grayscale).set(png::BitDepth::Eight);
let mut writer = enc.write_header()?;
writer.write_image_data(&self.pixels[..])?;
Ok(())
}
}
#[cfg(test)]
mod test {
use super::Mask;
#[test]
fn test_mask() {
let mut m = Mask::new(10, 10);
m.clear();
assert!(m.width == 10);
assert!(m.height == 10);
assert!(m.pixels.len() == 100);
m.fill(40, 20, 255);
assert!(m.pixels[0] == 0);
assert!(m.pixels[39] == 0);
assert!(m.pixels[40] == 255);
assert!(m.pixels[59] == 255);
assert!(m.pixels[60] == 0);
assert!(m.pixels[99] == 0);
}
}