Change BitDepth to u8 representation with TryFrom

This commit is contained in:
Andrew 2023-04-21 12:37:59 +12:00 committed by Josh Holmer
parent 873f0fefbe
commit 4e0cbbe973
8 changed files with 34 additions and 63 deletions

View file

@ -1,6 +1,8 @@
use rgb::{RGB16, RGBA8};
use std::fmt;
use crate::PngError;
#[derive(Debug, PartialEq, Eq, Clone)]
/// The color type used to represent this image
pub enum ColorType {
@ -67,64 +69,40 @@ impl ColorType {
}
}
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
/// The number of bits to be used per channel per pixel
pub enum BitDepth {
/// One bit per channel per pixel
One,
One = 1,
/// Two bits per channel per pixel
Two,
Two = 2,
/// Four bits per channel per pixel
Four,
Four = 4,
/// Eight bits per channel per pixel
Eight,
Eight = 8,
/// Sixteen bits per channel per pixel
Sixteen,
Sixteen = 16,
}
impl TryFrom<u8> for BitDepth {
type Error = PngError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::One),
2 => Ok(Self::Two),
4 => Ok(Self::Four),
8 => Ok(Self::Eight),
16 => Ok(Self::Sixteen),
_ => Err(PngError::new("Unexpected bit depth")),
}
}
}
impl fmt::Display for BitDepth {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
BitDepth::One => "1",
BitDepth::Two => "2",
BitDepth::Four => "4",
BitDepth::Eight => "8",
BitDepth::Sixteen => "16",
}
)
}
}
impl BitDepth {
/// Retrieve the number of bits per channel per pixel as a `u8`
#[inline]
pub fn as_u8(self) -> u8 {
match self {
BitDepth::One => 1,
BitDepth::Two => 2,
BitDepth::Four => 4,
BitDepth::Eight => 8,
BitDepth::Sixteen => 16,
}
}
/// Parse a number of bits per channel per pixel into a `BitDepth`
///
/// # Panics
///
/// If depth is unsupported
#[inline]
pub fn from_u8(depth: u8) -> BitDepth {
match depth {
1 => BitDepth::One,
2 => BitDepth::Two,
4 => BitDepth::Four,
8 => BitDepth::Eight,
16 => BitDepth::Sixteen,
_ => panic!("Unsupported bit depth"),
}
write!(f, "{}", *self as u8)
}
}

View file

@ -32,7 +32,7 @@ impl IhdrData {
#[must_use]
#[inline]
pub fn bpp(&self) -> usize {
(self.bit_depth.as_u8() * self.color_type.channels_per_pixel()) as usize
self.bit_depth as usize * self.color_type.channels_per_pixel() as usize
}
/// Byte length of IDAT that is correct for this IHDR
@ -173,14 +173,7 @@ pub fn parse_ihdr_header(
6 => ColorType::RGBA,
_ => return Err(PngError::new("Unexpected color type in header")),
},
bit_depth: match byte_data[8] {
1 => BitDepth::One,
2 => BitDepth::Two,
4 => BitDepth::Four,
8 => BitDepth::Eight,
16 => BitDepth::Sixteen,
_ => return Err(PngError::new("Unexpected bit depth in header")),
},
bit_depth: byte_data[8].try_into()?,
width: read_be_u32(&mut rdr).map_err(|_| PngError::TruncatedData)?,
height: read_be_u32(&mut rdr).map_err(|_| PngError::TruncatedData)?,
compression: byte_data[10],

View file

@ -569,7 +569,7 @@ fn optimize_png(
if filters.is_empty() {
// Pick a filter automatically
if png.raw.ihdr.bit_depth.as_u8() >= 8 {
if png.raw.ihdr.bit_depth as u8 >= 8 {
// Bigrams is the best all-rounder when there's at least one byte per pixel
filters.insert(RowFilter::Bigrams);
} else {

View file

@ -144,7 +144,7 @@ impl PngData {
ihdr_data
.write_all(&self.raw.ihdr.height.to_be_bytes())
.ok();
ihdr_data.write_all(&[self.raw.ihdr.bit_depth.as_u8()]).ok();
ihdr_data.write_all(&[self.raw.ihdr.bit_depth as u8]).ok();
ihdr_data
.write_all(&[self.raw.ihdr.color_type.png_header_code()])
.ok();
@ -165,7 +165,7 @@ impl PngData {
match &self.raw.ihdr.color_type {
ColorType::Indexed { palette } => {
let mut palette_data = Vec::with_capacity(palette.len() * 3);
let mut max_palette_size = 1 << (self.raw.ihdr.bit_depth.as_u8() as usize);
let mut max_palette_size = 1 << (self.raw.ihdr.bit_depth as u8);
// Ensure bKGD color doesn't get truncated from palette
if let Some(&idx) = self.raw.aux_headers.get(b"bKGD").and_then(|b| b.first()) {
max_palette_size = max_palette_size.max(idx as usize + 1);

View file

@ -32,7 +32,7 @@ pub fn reduce_bit_depth(png: &PngImage, minimum_bits: usize) -> Option<PngImage>
#[must_use]
pub fn reduce_bit_depth_8_or_less(png: &PngImage, mut minimum_bits: usize) -> Option<PngImage> {
assert!((1..8).contains(&minimum_bits));
let bit_depth: usize = png.ihdr.bit_depth.as_u8() as usize;
let bit_depth = png.ihdr.bit_depth as usize;
if minimum_bits >= bit_depth || bit_depth > 8 {
return None;
}
@ -154,7 +154,7 @@ pub fn reduce_bit_depth_8_or_less(png: &PngImage, mut minimum_bits: usize) -> Op
data: reduced,
ihdr: IhdrData {
color_type,
bit_depth: BitDepth::from_u8(minimum_bits as u8),
bit_depth: (minimum_bits as u8).try_into().unwrap(),
..png.ihdr
},
aux_headers: png.aux_headers.clone(),

View file

@ -61,7 +61,7 @@ fn test_it_converts(
assert_eq!(png.raw.ihdr.color_type.png_header_code(), color_type_out);
assert_eq!(png.raw.ihdr.bit_depth, bit_depth_out);
if let ColorType::Indexed { palette } = &png.raw.ihdr.color_type {
assert!(palette.len() <= 1 << (png.raw.ihdr.bit_depth.as_u8() as usize));
assert!(palette.len() <= 1 << (png.raw.ihdr.bit_depth as u8));
}
remove_file(output).ok();

View file

@ -70,7 +70,7 @@ fn test_it_converts(
"optimized to wrong bit depth"
);
if let ColorType::Indexed { palette } = &png.raw.ihdr.color_type {
let mut max_palette_size = 1 << (png.raw.ihdr.bit_depth.as_u8() as usize);
let mut max_palette_size = 1 << (png.raw.ihdr.bit_depth as u8);
// Ensure bKGD color is valid
if let Some(&idx) = png.raw.aux_headers.get(b"bKGD").and_then(|b| b.first()) {
assert!(palette.len() > idx as usize);

View file

@ -60,7 +60,7 @@ fn test_it_converts(
assert_eq!(png.raw.ihdr.color_type.png_header_code(), color_type_out);
assert_eq!(png.raw.ihdr.bit_depth, bit_depth_out);
if let ColorType::Indexed { palette } = &png.raw.ihdr.color_type {
assert!(palette.len() <= 1 << (png.raw.ihdr.bit_depth.as_u8() as usize));
assert!(palette.len() <= 1 << (png.raw.ihdr.bit_depth as u8));
}
remove_file(output).ok();