use {
crate::{never, panic, ToPng},
serde::{Deserialize, Serialize},
std::io::{Read, Write},
};
#[doc(hidden)]
pub use self::{BitDepth::*, ColorType::*};
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
#[non_exhaustive]
pub struct Png {
pub width: u32,
pub height: u32,
pub bit_depth: BitDepth,
pub color_type: ColorType,
pub pixel_data: Vec<u8>,
pub palette_data: Option<Vec<u8>>,
pub transparency_data: Option<Vec<u8>>,
}
impl Png {
pub fn new(data: &impl ToPng) -> Self {
data.to_png().into_owned()
}
pub fn write(&self, output: &impl Write) -> Result<usize, panic> {
todo!()
}
pub fn read(input: &impl Read) -> Result<Self, panic> {
todo!()
}
pub fn write_vec(&self) -> Result<Vec<u8>, never> {
let mut output = Vec::new();
self.write(&mut output)?;
Ok(output)
}
pub fn read_slice(input: &[u8]) -> Result<Self, never> {
Ok(Self::read(&input)?)
}
pub fn set_pixel(&mut self, x: u32, y: u32, color: &[u8]) -> Result<(), ()> {
todo!()
}
}
impl Serialize for Png {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
serializer.serialize_bytes(
&self
.write_vec()
.expect("serializing Png to bytes should not fail"),
)
}
}
impl<'de> Deserialize<'de> for Png {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de> {
let bytes: &[u8] = serde_bytes::deserialize(deserializer)?;
Self::read_slice(&bytes).map_err(serde::de::Error::custom)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(u8)]
pub enum BitDepth {
OneBit = 1,
TwoBit = 2,
FourBit = 4,
#[default]
EightBit = 8,
SixteenBit = 16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(u8)]
pub enum ColorType {
#[default]
Luminance = 0,
RedGreenBlue = 2,
Indexed = 3,
LuminanceAlpha = 4,
RedGreenBlueAlpha = 6,
}
impl BitDepth {
pub fn bits_per_sample(&self) -> usize {
u8::from(*self).into()
}
}
impl From<BitDepth> for u8 {
fn from(depth: BitDepth) -> Self {
depth as u8
}
}
impl ColorType {
pub fn samples_per_pixel(&self) -> usize {
match self {
Luminance => 1,
RedGreenBlue => 3,
Indexed => 1,
LuminanceAlpha => 2,
RedGreenBlueAlpha => 4,
}
}
}
impl From<ColorType> for u8 {
fn from(val: ColorType) -> Self {
val as u8
}
}