use oximg::pipeline;
use std::fs;
fn write_ppm(path: &str, rgb: &[u8], w: usize, h: usize) -> anyhow::Result<()> {
let mut buf = format!("P6\n{w} {h}\n255\n").into_bytes();
buf.extend_from_slice(rgb);
fs::write(path, buf)?;
Ok(())
}
fn read_ppm(path: &str) -> anyhow::Result<(Vec<u8>, usize, usize)> {
let data = fs::read(path)?;
let mut fields = Vec::new(); let mut pos = 0;
while fields.len() < 4 {
while pos < data.len() && (data[pos] as char).is_whitespace() {
pos += 1;
}
if data[pos] == b'#' {
while data[pos] != b'\n' {
pos += 1;
}
continue;
}
let start = pos;
while pos < data.len() && !(data[pos] as char).is_whitespace() {
pos += 1;
}
fields.push(std::str::from_utf8(&data[start..pos])?.to_string());
}
pos += 1; anyhow::ensure!(fields[0] == "P6" && fields[3] == "255", "unsupported PPM");
let (w, h): (usize, usize) = (fields[1].parse()?, fields[2].parse()?);
anyhow::ensure!(data.len() - pos >= w * h * 3, "truncated PPM");
Ok((data[pos..pos + w * h * 3].to_vec(), w, h))
}
fn params(quality: f32, preset: &str) -> pipeline::Params {
pipeline::Params {
max_width: 0,
max_height: 0,
quality,
fast_preset: preset != "small",
parallel: 1,
}
}
fn main() -> anyhow::Result<()> {
let args: Vec<String> = std::env::args().collect();
match args[1].as_str() {
"resize" => {
let (input, max_w, max_h) = (&args[2], args[3].parse()?, args[4].parse()?);
let (quality, preset, out) = (args[5].parse()?, args[6].as_str(), &args[7]);
let jpeg = fs::read(input)?;
let par: usize = std::env::var("OXIMG_PAR")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(1);
let (rgb, w, h) = pipeline::decode_and_resize(&jpeg, max_w, max_h, par)?;
fs::write(out, pipeline::encode(&rgb, w, h, ¶ms(quality, preset))?)?;
if let Some(ppm) = args.get(8) {
write_ppm(ppm, &rgb, w, h)?;
}
eprintln!("{w}x{h}");
}
"encode" => {
let (input, quality, preset, out) =
(&args[2], args[3].parse()?, args[4].as_str(), &args[5]);
let (rgb, w, h) = read_ppm(input)?;
fs::write(out, pipeline::encode(&rgb, w, h, ¶ms(quality, preset))?)?;
}
other => anyhow::bail!("unknown mode: {other}"),
}
Ok(())
}