Refactor allowing multiple pixel formats

This commit is contained in:
cdo committed 2026-10-25 22:24:52 +00:00
1 parent cef82a2e14
commit 6cd059f401
3 files changed
+138 -102

No files matched your search

+64 -59
View File
@@ -2,59 +2,8 @@ use super::*;
pub struct Farbfeld;
fn read_header<I>(input: &mut I) -> Result<Extent, Error>
where
I: std::io::Read,
{
let mut bytes: [u8; 16] = [0; 16];
if input.read(&mut bytes)? < 16 || &bytes[0..8] != b"farbfeld" {
Err(Error::Invalid)
} else {
Ok(Extent {
x: u32::from_be_bytes(bytes[8..12].try_into().unwrap()),
y: u32::from_be_bytes(bytes[12..16].try_into().unwrap()),
})
}
}
fn read_pixels<I>(input: &mut I, extent: Extent) -> Result<Vec<Pixel>, Error>
where
I: std::io::Read,
{
let mut pixels = Vec::with_capacity(extent.size() as usize);
for _ in 0..extent.size() {
pixels.push(read_pixel(input)?);
}
Ok(pixels)
}
fn read_pixel<I>(input: &mut I) -> Result<Pixel, Error>
where
I: std::io::Read,
{
let mut bytes: [u8; 8] = [0; 8];
if input.read(&mut bytes)? < 8 {
Err(Error::Invalid)
} else {
Ok(Pixel {
r: to_channel(bytes[0..2].try_into().unwrap()),
g: to_channel(bytes[2..4].try_into().unwrap()),
b: to_channel(bytes[4..6].try_into().unwrap()),
a: to_channel(bytes[6..8].try_into().unwrap()),
})
}
}
fn to_channel(bytes: [u8; 2]) -> f32 {
u16::from_be_bytes(bytes) as f32 / u16::MAX as f32
}
fn from_channel(channel: f32) -> [u8; 2] {
((channel * u16::MAX as f32) as u16).to_be_bytes()
}
impl Format for Farbfeld {
fn read<I>(input: &mut I) -> Result<Image, Error>
impl Format<SRGBA> for Farbfeld {
fn read<I>(input: &mut I) -> Result<Image<SRGBA>, Error>
where
I: std::io::Read,
{
@@ -65,13 +14,13 @@ impl Format for Farbfeld {
})
}
fn write<O>(output: &mut O, img: &Image) -> std::io::Result<()>
fn write<O>(output: &mut O, img: &Image<SRGBA>) -> std::io::Result<()>
where
O: std::io::Write,
{
output.write_all(b"farbfeld")?;
output.write_all(&img.extent.x.to_be_bytes())?;
output.write_all(&img.extent.y.to_be_bytes())?;
output.write_all(&(img.extent.x as u32).to_be_bytes())?;
output.write_all(&(img.extent.y as u32).to_be_bytes())?;
for pixel in &img.pixels {
output.write_all(&from_channel(pixel.r))?;
output.write_all(&from_channel(pixel.g))?;
@@ -82,6 +31,62 @@ impl Format for Farbfeld {
}
}
fn read_header<I>(input: &mut I) -> Result<Extent, Error>
where
I: std::io::Read,
{
let mut bytes: [u8; 16] = [0; 16];
if input.read(&mut bytes)? < 16 || &bytes[0..8] != b"farbfeld" {
Err(Error::Invalid)
} else {
Ok(Extent {
x: be_u32_at(&bytes, 8) as usize,
y: be_u32_at(&bytes, 12) as usize,
})
}
}
fn read_pixels<I>(input: &mut I, extent: Extent) -> Result<Vec<SRGBA>, Error>
where
I: std::io::Read,
{
let mut pixels = Vec::with_capacity(extent.size() as usize);
for _ in 0..extent.size() {
pixels.push(read_pixel(input)?);
}
Ok(pixels)
}
fn read_pixel<I>(input: &mut I) -> Result<SRGBA, Error>
where
I: std::io::Read,
{
let mut bytes: [u8; 8] = [0; 8];
if input.read(&mut bytes)? < 8 {
Err(Error::Invalid)
} else {
Ok(SRGBA {
r: to_channel(bytes[0..2].try_into().unwrap()),
g: to_channel(bytes[2..4].try_into().unwrap()),
b: to_channel(bytes[4..6].try_into().unwrap()),
a: to_channel(bytes[6..8].try_into().unwrap()),
})
}
}
fn be_u32_at(bytes: &[u8], start: usize) -> u32 {
let end = start + std::mem::size_of::<u32>();
u32::from_be_bytes(bytes[start..end].try_into().unwrap())
}
fn to_channel(bytes: [u8; 2]) -> f32 {
u16::from_be_bytes(bytes) as f32 / u16::MAX as f32
}
fn from_channel(channel: f32) -> [u8; 2] {
((channel * u16::MAX as f32) as u16).to_be_bytes()
}
#[cfg(test)]
mod tests {
use super::*;
@@ -177,7 +182,7 @@ mod tests {
fn write_magic() {
let img = Image {
extent: Extent { x: 1, y: 1 },
pixels: vec![Pixel {
pixels: vec![SRGBA {
r: 0.0,
g: 0.0,
b: 0.0,
@@ -193,7 +198,7 @@ mod tests {
fn write_extent() {
let img = Image {
extent: Extent { x: 1, y: 2 },
pixels: vec![Pixel {
pixels: vec![SRGBA {
r: 0.0,
g: 0.0,
b: 0.0,
@@ -210,7 +215,7 @@ mod tests {
fn write_pixel() {
let img = Image {
extent: Extent { x: 1, y: 1 },
pixels: vec![Pixel {
pixels: vec![SRGBA {
r: 0.0,
g: 0.25,
b: 0.5,