//! 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 { 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 { 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