diff --git a/source/leela/main.rs b/source/leela/main.rs index 795e1bb..142e12c 100644 --- a/source/leela/main.rs +++ b/source/leela/main.rs @@ -1,5 +1,5 @@ use maraiah::{durandal::{err::*, file::*, image::*, sound::*}, - marathon::{machdr, shp, snd, tga, wad, wav}}; + marathon::{machdr, ppm, shp, snd, tga, wad, wav}}; use std::{fs, io}; fn make_tga(_opt: &Options, fname: &str, im: &impl Image) -> ResultS<()> @@ -9,6 +9,13 @@ fn make_tga(_opt: &Options, fname: &str, im: &impl Image) -> ResultS<()> tga::write_tga(&mut out, im) } +fn make_ppm(_opt: &Options, fname: &str, im: &impl Image) -> ResultS<()> +{ + let mut out = io::BufWriter::new(fs::File::create(fname)?); + + ppm::write_ppm(&mut out, im) +} + fn make_yaml(opt: &Options, data: &T) -> ResultS<()> where T: serde::Serialize + std::fmt::Debug { @@ -111,6 +118,17 @@ fn process_snd(opt: &Options, b: &[u8]) -> ResultS<()> Ok(()) } +fn process_ppm(opt: &Options, b: &[u8]) -> ResultS<()> +{ + let im = ppm::read_ppm(b)?; + + let fname = format!("{}/out.tga", opt.out_dir); + make_tga(opt, &fname, &im)?; + + let fname = format!("{}/out.ppm", opt.out_dir); + make_ppm(opt, &fname, &im) +} + fn main() -> ResultS<()> { use argparse::*; @@ -210,6 +228,7 @@ fn main() -> ResultS<()> "wad:" => process_wad(&opt, b), "shp:" => process_shp(&opt, b), "snd:" => process_snd(&opt, b), + "ppm:" => process_ppm(&opt, b), _ => Err(err_msg("invalid file type specified on commandline")), }?; } diff --git a/source/marathon/ppm.rs b/source/marathon/ppm.rs index 4789e9d..48448f3 100644 --- a/source/marathon/ppm.rs +++ b/source/marathon/ppm.rs @@ -1,6 +1,6 @@ //! Portable PixMap format images. -use crate::durandal::{err::*, image::*}; +use crate::durandal::{err::*, fixed::FixedLong, image::*}; use std::io; /// Writes a PPM file from an image. @@ -24,4 +24,46 @@ pub fn write_ppm(out: &mut impl io::Write, im: &impl Image) -> ResultS<()> 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 * 65535).integ() as u16; + let g = (g / depth * 65535).integ() as u16; + let b = (b / depth * 65535).integ() as u16; + + im.cr.push(Color16::new(r, g, b)); + } + + Ok(im) +} + // EOF