70 lines
1.5 KiB
Rust
70 lines
1.5 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
|