Skip to main content

pfx_denoise/
pfm.rs

1pub struct Pfm {
2    pub width: u32,
3    pub height: u32,
4    pub pixels: Vec<[f32; 4]>,
5}
6
7pub fn read(bytes: &[u8]) -> Result<Pfm, String> {
8    let mut fields = Vec::new();
9    let mut at = 0;
10    while fields.len() < 4 {
11        while at < bytes.len() && bytes[at].is_ascii_whitespace() {
12            at += 1;
13        }
14        let start = at;
15        while at < bytes.len() && !bytes[at].is_ascii_whitespace() {
16            at += 1;
17        }
18        if start == at {
19            return Err("invalid PFM image".into());
20        }
21        fields.push(std::str::from_utf8(&bytes[start..at]).map_err(|_| "invalid PFM image")?);
22    }
23    at += 1;
24    let channels = match fields[0] {
25        "PF" => 3,
26        "Pf" => 1,
27        _ => return Err("invalid PFM image".into()),
28    };
29    let parse = |field: &str| field.parse::<u32>().map_err(|_| "invalid PFM image");
30    let width = parse(fields[1])?;
31    let height = parse(fields[2])?;
32    let scale: f32 = fields[3].parse().map_err(|_| "invalid PFM image")?;
33    if scale >= 0.0 {
34        return Err("big-endian PFM images are not supported".into());
35    }
36    let count = width as usize * height as usize * channels;
37    let data = bytes
38        .get(at..at + count * 4)
39        .ok_or("invalid PFM image: error reading pixel data")?;
40    let values: Vec<f32> = data
41        .chunks_exact(4)
42        .map(|value| f32::from_le_bytes(value.try_into().unwrap()) * scale.abs())
43        .collect();
44    let mut pixels = vec![[0.0, 0.0, 0.0, 1.0]; width as usize * height as usize];
45    for y in 0..height as usize {
46        let row = height as usize - 1 - y;
47        for x in 0..width as usize {
48            let source = &values[(y * width as usize + x) * channels..][..channels];
49            let pixel = &mut pixels[row * width as usize + x];
50            for c in 0..3 {
51                pixel[c] = source[c.min(channels - 1)];
52            }
53        }
54    }
55    Ok(Pfm {
56        width,
57        height,
58        pixels,
59    })
60}
61
62pub fn write(width: u32, height: u32, pixels: &[[f32; 4]]) -> Vec<u8> {
63    let mut bytes = format!("PF\n{width} {height}\n-1.0\n").into_bytes();
64    for y in (0..height as usize).rev() {
65        for pixel in &pixels[y * width as usize..][..width as usize] {
66            for value in &pixel[..3] {
67                bytes.extend_from_slice(&value.to_le_bytes());
68            }
69        }
70    }
71    bytes
72}