add crop setting, DynamicBendable like the image crate
This commit is contained in:
parent
e1edc611bc
commit
3527c0a2af
4 changed files with 130 additions and 22 deletions
|
@ -13,3 +13,7 @@ keywords.workspace = true
|
||||||
image = { version = "0.25", features = ["rayon"] }
|
image = { version = "0.25", features = ["rayon"] }
|
||||||
num = "0"
|
num = "0"
|
||||||
rayon = "1"
|
rayon = "1"
|
||||||
|
infer = "0.16"
|
||||||
|
thiserror = "2.0"
|
||||||
|
derive-new = "0.7"
|
||||||
|
strum = { version = "0.26", features = ["derive"] }
|
||||||
|
|
|
@ -13,7 +13,7 @@ impl IntoDataBytes for Bytes {
|
||||||
impl TryFromDataBytes for Bytes {
|
impl TryFromDataBytes for Bytes {
|
||||||
type Error = Infallible;
|
type Error = Infallible;
|
||||||
type Format = ();
|
type Format = ();
|
||||||
fn try_from_bytes(bytes: Bytes, _: Self::Format) -> Result<Self, Self::Error>
|
fn try_from_bytes(bytes: Bytes, _: Self::Format, _: crate::Crop) -> Result<Self, Self::Error>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
@ -26,4 +26,7 @@ impl Bendable for Bytes {
|
||||||
fn map<F: Fn(&Self::Unit) -> Self::Unit + Sync>(self, f: F) -> Self {
|
fn map<F: Fn(&Self::Unit) -> Self::Unit + Sync>(self, f: F) -> Self {
|
||||||
self.into_par_iter().map(|e| f(&e)).collect()
|
self.into_par_iter().map(|e| f(&e)).collect()
|
||||||
}
|
}
|
||||||
|
fn format() -> crate::Format {
|
||||||
|
crate::Format::Binary
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,24 +34,41 @@ where
|
||||||
{
|
{
|
||||||
type Error = ();
|
type Error = ();
|
||||||
type Format = Dimensions;
|
type Format = Dimensions;
|
||||||
fn try_from_bytes(bytes: crate::Bytes, format: Self::Format) -> Result<Self, Self::Error>
|
fn try_from_bytes(
|
||||||
|
bytes: crate::Bytes,
|
||||||
|
format: Self::Format,
|
||||||
|
crop: crate::Crop,
|
||||||
|
) -> Result<Self, Self::Error>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
ImageBuffer::from_raw(
|
ImageBuffer::from_raw(
|
||||||
format.width,
|
format.width,
|
||||||
format.height,
|
format.height,
|
||||||
bytes
|
match crop {
|
||||||
.chunks_exact(P::Subpixel::zero().to_ne_bytes().as_ref().len())
|
crate::Crop::End => bytes
|
||||||
.map(|p| {
|
.chunks_exact(P::Subpixel::zero().to_ne_bytes().as_ref().len())
|
||||||
P::Subpixel::from_ne_bytes(
|
.map(|p| {
|
||||||
&match <P::Subpixel as FromBytes>::Bytes::try_from(p) {
|
P::Subpixel::from_ne_bytes(
|
||||||
Ok(v) => v,
|
&match <P::Subpixel as FromBytes>::Bytes::try_from(p) {
|
||||||
Err(_) => unreachable!("you messed up chunk size!"),
|
Ok(v) => v,
|
||||||
},
|
Err(_) => unreachable!("you messed up chunk size!"),
|
||||||
)
|
},
|
||||||
})
|
)
|
||||||
.collect::<Vec<P::Subpixel>>(),
|
})
|
||||||
|
.collect::<Vec<P::Subpixel>>(),
|
||||||
|
crate::Crop::Start => bytes
|
||||||
|
.rchunks_exact(P::Subpixel::zero().to_ne_bytes().as_ref().len())
|
||||||
|
.map(|p| {
|
||||||
|
P::Subpixel::from_ne_bytes(
|
||||||
|
&match <P::Subpixel as FromBytes>::Bytes::try_from(p) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => unreachable!("you messed up chunk size!"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<P::Subpixel>>(),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.ok_or(())
|
.ok_or(())
|
||||||
}
|
}
|
||||||
|
@ -69,6 +86,15 @@ where
|
||||||
self.par_pixels_mut().for_each(|p| *p = f(p));
|
self.par_pixels_mut().for_each(|p| *p = f(p));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
fn format() -> crate::Format {
|
||||||
|
crate::Format::Image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoDataBytes for DynamicImage {
|
||||||
|
fn into_bytes(self) -> crate::Bytes {
|
||||||
|
self.into_bytes()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -90,7 +116,8 @@ mod tests {
|
||||||
Dimensions {
|
Dimensions {
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0
|
height: 0
|
||||||
}
|
},
|
||||||
|
Default::default()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -105,7 +132,8 @@ mod tests {
|
||||||
Dimensions {
|
Dimensions {
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 1
|
height: 1
|
||||||
}
|
},
|
||||||
|
Default::default()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -121,7 +149,8 @@ mod tests {
|
||||||
Dimensions {
|
Dimensions {
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 1
|
height: 1
|
||||||
}
|
},
|
||||||
|
Default::default()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -141,7 +170,8 @@ mod tests {
|
||||||
Dimensions {
|
Dimensions {
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 1
|
height: 1
|
||||||
}
|
},
|
||||||
|
Default::default()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -161,7 +191,8 @@ mod tests {
|
||||||
Dimensions {
|
Dimensions {
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 1
|
height: 1
|
||||||
}
|
},
|
||||||
|
Default::default()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -181,7 +212,8 @@ mod tests {
|
||||||
Dimensions {
|
Dimensions {
|
||||||
width: 3,
|
width: 3,
|
||||||
height: 1
|
height: 1
|
||||||
}
|
},
|
||||||
|
Default::default()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,31 +5,100 @@ pub mod txt;
|
||||||
|
|
||||||
pub(crate) type Bytes = Vec<u8>;
|
pub(crate) type Bytes = Vec<u8>;
|
||||||
|
|
||||||
|
pub mod dynamic {
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{self, Read},
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
img::{self, DynamicImage},
|
||||||
|
Bytes,
|
||||||
|
};
|
||||||
|
|
||||||
|
use infer::MatcherType;
|
||||||
|
use strum::EnumDiscriminants;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(EnumDiscriminants)]
|
||||||
|
#[strum_discriminants(name(Format))]
|
||||||
|
pub enum DynamicBendable {
|
||||||
|
Image(DynamicImage),
|
||||||
|
Binary(Bytes),
|
||||||
|
Sound,
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum OpenError {
|
||||||
|
#[error("{0:?}")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
#[error("{0:?}")]
|
||||||
|
Image(#[from] img::ImageError),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open<P: AsRef<Path>>(path: P) -> Result<Option<DynamicBendable>, OpenError> {
|
||||||
|
use MatcherType::*;
|
||||||
|
if let Some(matcher) = infer::get_from_path(&path)?.map(|t| t.matcher_type()) {
|
||||||
|
Ok(Some(match matcher {
|
||||||
|
Image => DynamicBendable::Image(img::open(path)?),
|
||||||
|
App | Archive => DynamicBendable::Binary({
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
File::open(path)?.read_to_end(&mut buf)?;
|
||||||
|
buf
|
||||||
|
}),
|
||||||
|
Audio => todo!(),
|
||||||
|
Book => todo!(),
|
||||||
|
Doc => todo!(),
|
||||||
|
Font => todo!(),
|
||||||
|
Text => todo!(),
|
||||||
|
Video => todo!(),
|
||||||
|
Custom => unimplemented!("I don't even know what this is!"),
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use dynamic::*;
|
||||||
|
|
||||||
pub trait Bendable: TryFromDataBytes + IntoDataBytes {
|
pub trait Bendable: TryFromDataBytes + IntoDataBytes {
|
||||||
type Unit;
|
type Unit;
|
||||||
fn bend_into<T: Bendable>(
|
fn bend_into<T: Bendable>(
|
||||||
self,
|
self,
|
||||||
format: <T as TryFromDataBytes>::Format,
|
format: <T as TryFromDataBytes>::Format,
|
||||||
|
crop: Crop,
|
||||||
) -> Result<T, <T as TryFromDataBytes>::Error> {
|
) -> Result<T, <T as TryFromDataBytes>::Error> {
|
||||||
T::bend_from(self, format)
|
T::bend_from(self, format, crop)
|
||||||
}
|
}
|
||||||
fn bend_from<T: Bendable>(
|
fn bend_from<T: Bendable>(
|
||||||
b: T,
|
b: T,
|
||||||
format: <Self as TryFromDataBytes>::Format,
|
format: <Self as TryFromDataBytes>::Format,
|
||||||
|
crop: Crop,
|
||||||
) -> Result<Self, <Self as TryFromDataBytes>::Error> {
|
) -> Result<Self, <Self as TryFromDataBytes>::Error> {
|
||||||
Self::try_from_bytes(b.into_bytes(), format)
|
Self::try_from_bytes(b.into_bytes(), format, crop)
|
||||||
}
|
}
|
||||||
fn map<F: Fn(&Self::Unit) -> Self::Unit + Sync>(self, f: F) -> Self;
|
fn map<F: Fn(&Self::Unit) -> Self::Unit + Sync>(self, f: F) -> Self;
|
||||||
|
fn format() -> Format;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IntoDataBytes: Sized {
|
pub trait IntoDataBytes: Sized {
|
||||||
fn into_bytes(self) -> Bytes;
|
fn into_bytes(self) -> Bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub enum Crop {
|
||||||
|
Start,
|
||||||
|
#[default]
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait TryFromDataBytes {
|
pub trait TryFromDataBytes {
|
||||||
type Error;
|
type Error;
|
||||||
type Format;
|
type Format;
|
||||||
fn try_from_bytes(bytes: Bytes, format: Self::Format) -> Result<Self, Self::Error>
|
fn try_from_bytes(bytes: Bytes, format: Self::Format, crop: Crop) -> Result<Self, Self::Error>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue