Maraiah/maraiah/image/ppm.rs

70 lines
1.7 KiB
Rust

//! Portable Pixel Map format images.
use crate::{err::*, fixed::FixedLong, image::*};
use std::io;
/// Writes a PPM file from an image.
///
/// # Errors
///
/// Errors if `out` cannot be written to.
pub fn write_ppm(out: &mut impl io::Write, im: &impl Image) -> ResultS<()>
{
write!(out, "P3\n{} {}\n{}\n", im.w(), im.h(), u16::max_value())?;
for y in 0..im.h() {
for x in 0..im.w() {
let cr = im.index(x, y);
write!(out, "{} {} {} ", cr.r(), cr.g(), cr.b())?;
}
out.write_all(b"\n")?;
}
Ok(())
}
/// Reads a PPM file into an image.
pub fn read_ppm(inp: &[u8]) -> ResultS<Image16>
{
let mut it = inp.split(|&n| n == b'\n' || n == b'\r' || n == b' ');
if ok!(it.next(), "no magic number")? != b"P3" {
bail!("not P3 format");
}
let mut get_num = move || -> ResultS<u16> {
let st = loop {
match ok!(it.next(), "no more strings")? {
b"" => {}
st => break st
}
};
let st = unsafe {std::str::from_utf8_unchecked(st)};
let nu = u16::from_str_radix(st, 10)?;
Ok(nu)
};
let width = get_num()?;
let height = get_num()?;
let depth = i64::from(get_num()?);
let mut im = Image16::new(usize::from(width), usize::from(height));
for _ in 0..height * width {
let r = FixedLong::from_int(get_num()?.into());
let g = FixedLong::from_int(get_num()?.into());
let b = FixedLong::from_int(get_num()?.into());
let r = (r / depth * 0xFFFF).integ() as u16;
let g = (g / depth * 0xFFFF).integ() as u16;
let b = (b / depth * 0xFFFF).integ() as u16;
im.cr.push(Color16::new(r, g, b));
}
Ok(im)
}
// EOF