pile-audio refactor
This commit is contained in:
213
crates/pile-flac/src/blocks/picture.rs
Normal file
213
crates/pile-flac/src/blocks/picture.rs
Normal file
@@ -0,0 +1,213 @@
|
||||
use mime::Mime;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
io::{Cursor, Read},
|
||||
};
|
||||
|
||||
use super::{FlacMetablockDecode, FlacMetablockEncode, FlacMetablockHeader, FlacMetablockType};
|
||||
use crate::{FlacDecodeError, FlacEncodeError, PictureType};
|
||||
|
||||
/// A picture metablock in a flac file
|
||||
pub struct FlacPictureBlock {
|
||||
/// The type of this picture
|
||||
pub picture_type: PictureType,
|
||||
|
||||
/// The format of this picture
|
||||
pub mime: Mime,
|
||||
|
||||
/// The description of this picture
|
||||
pub description: String,
|
||||
|
||||
/// The width of this picture, in px
|
||||
pub width: u32,
|
||||
|
||||
/// The height of this picture, in px
|
||||
pub height: u32,
|
||||
|
||||
/// The bit depth of this picture
|
||||
pub bit_depth: u32,
|
||||
|
||||
/// The color count of this picture (if indexed)
|
||||
pub color_count: u32,
|
||||
|
||||
/// The image data
|
||||
pub img_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Debug for FlacPictureBlock {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("FlacPicture")
|
||||
.field("type", &self.picture_type)
|
||||
.field("mime", &self.mime)
|
||||
.field("img_data.len()", &self.img_data.len())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl FlacMetablockDecode for FlacPictureBlock {
|
||||
fn decode(data: &[u8]) -> Result<Self, FlacDecodeError> {
|
||||
let mut d = Cursor::new(data);
|
||||
|
||||
// This is re-used whenever we need to read four bytes
|
||||
let mut block = [0u8; 4];
|
||||
|
||||
#[expect(clippy::map_err_ignore)]
|
||||
d.read_exact(&mut block)
|
||||
.map_err(|_| FlacDecodeError::MalformedBlock)?;
|
||||
let picture_type = u32::from_be_bytes(block);
|
||||
let picture_type = PictureType::from_idx(picture_type)
|
||||
.ok_or(FlacDecodeError::InvalidPictureType(picture_type))?;
|
||||
|
||||
// Image format
|
||||
let mime = {
|
||||
d.read_exact(&mut block)
|
||||
.map_err(|_err| FlacDecodeError::MalformedBlock)?;
|
||||
|
||||
#[expect(clippy::expect_used)]
|
||||
let mime_length = u32::from_be_bytes(block)
|
||||
.try_into()
|
||||
.expect("mime length does not fit into usize");
|
||||
let mut mime = vec![0u8; mime_length];
|
||||
|
||||
d.read_exact(&mut mime)
|
||||
.map_err(|_err| FlacDecodeError::MalformedBlock)?;
|
||||
|
||||
String::from_utf8(mime)
|
||||
.ok()
|
||||
.and_then(|x| x.parse().ok())
|
||||
.unwrap_or(mime::APPLICATION_OCTET_STREAM)
|
||||
};
|
||||
|
||||
// Image description
|
||||
let description = {
|
||||
d.read_exact(&mut block)
|
||||
.map_err(|_err| FlacDecodeError::MalformedBlock)?;
|
||||
|
||||
#[expect(clippy::expect_used)]
|
||||
let desc_length = u32::from_be_bytes(block)
|
||||
.try_into()
|
||||
.expect("description length does not fit into usize");
|
||||
let mut desc = vec![0u8; desc_length];
|
||||
|
||||
d.read_exact(&mut desc)
|
||||
.map_err(|_err| FlacDecodeError::MalformedBlock)?;
|
||||
|
||||
String::from_utf8(desc)?
|
||||
};
|
||||
|
||||
// Image width
|
||||
#[expect(clippy::map_err_ignore)]
|
||||
d.read_exact(&mut block)
|
||||
.map_err(|_| FlacDecodeError::MalformedBlock)?;
|
||||
let width = u32::from_be_bytes(block);
|
||||
|
||||
// Image height
|
||||
#[expect(clippy::map_err_ignore)]
|
||||
d.read_exact(&mut block)
|
||||
.map_err(|_| FlacDecodeError::MalformedBlock)?;
|
||||
let height = u32::from_be_bytes(block);
|
||||
|
||||
// Image bit depth
|
||||
#[expect(clippy::map_err_ignore)]
|
||||
d.read_exact(&mut block)
|
||||
.map_err(|_| FlacDecodeError::MalformedBlock)?;
|
||||
let depth = u32::from_be_bytes(block);
|
||||
|
||||
// Color count for indexed images
|
||||
#[expect(clippy::map_err_ignore)]
|
||||
d.read_exact(&mut block)
|
||||
.map_err(|_| FlacDecodeError::MalformedBlock)?;
|
||||
let color_count = u32::from_be_bytes(block);
|
||||
|
||||
// Image data length
|
||||
let img_data = {
|
||||
d.read_exact(&mut block)
|
||||
.map_err(|_err| FlacDecodeError::MalformedBlock)?;
|
||||
|
||||
#[expect(clippy::expect_used)]
|
||||
let data_length = u32::from_be_bytes(block)
|
||||
.try_into()
|
||||
.expect("image data length does not fit into usize");
|
||||
let mut img_data = vec![0u8; data_length];
|
||||
|
||||
d.read_exact(&mut img_data)
|
||||
.map_err(|_err| FlacDecodeError::MalformedBlock)?;
|
||||
|
||||
img_data
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
picture_type,
|
||||
mime,
|
||||
description,
|
||||
width,
|
||||
height,
|
||||
bit_depth: depth,
|
||||
color_count,
|
||||
img_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FlacMetablockEncode for FlacPictureBlock {
|
||||
#[expect(clippy::expect_used)]
|
||||
fn get_len(&self) -> u32 {
|
||||
(4 + (4 + self.mime.to_string().len())
|
||||
+ (4 + self.description.len())
|
||||
+ 4 + 4 + 4
|
||||
+ 4 + (4 + self.img_data.len()))
|
||||
.try_into()
|
||||
.expect("picture block size does not fit into u32")
|
||||
}
|
||||
|
||||
fn encode(
|
||||
&self,
|
||||
is_last: bool,
|
||||
with_header: bool,
|
||||
target: &mut impl std::io::Write,
|
||||
) -> Result<(), FlacEncodeError> {
|
||||
if with_header {
|
||||
let header = FlacMetablockHeader {
|
||||
block_type: FlacMetablockType::Picture,
|
||||
length: self.get_len(),
|
||||
is_last,
|
||||
};
|
||||
header.encode(target)?;
|
||||
}
|
||||
|
||||
target.write_all(&self.picture_type.to_idx().to_be_bytes())?;
|
||||
|
||||
#[expect(clippy::expect_used)]
|
||||
{
|
||||
let mime = self.mime.to_string();
|
||||
target.write_all(
|
||||
&u32::try_from(mime.len())
|
||||
.expect("mime length does not fit into u32")
|
||||
.to_be_bytes(),
|
||||
)?;
|
||||
target.write_all(self.mime.to_string().as_bytes())?;
|
||||
drop(mime);
|
||||
|
||||
target.write_all(
|
||||
&u32::try_from(self.description.len())
|
||||
.expect("description length does not fit into u32")
|
||||
.to_be_bytes(),
|
||||
)?;
|
||||
target.write_all(self.description.as_bytes())?;
|
||||
|
||||
target.write_all(&self.width.to_be_bytes())?;
|
||||
target.write_all(&self.height.to_be_bytes())?;
|
||||
target.write_all(&self.bit_depth.to_be_bytes())?;
|
||||
target.write_all(&self.color_count.to_be_bytes())?;
|
||||
|
||||
target.write_all(
|
||||
&u32::try_from(self.img_data.len())
|
||||
.expect("image data length does not fit into u32")
|
||||
.to_be_bytes(),
|
||||
)?;
|
||||
}
|
||||
target.write_all(&self.img_data)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user