From 3527c0a2af5746ce830f04d50ed1568764723c57 Mon Sep 17 00:00:00 2001 From: p6nj Date: Sat, 18 Jan 2025 22:32:21 -0500 Subject: [PATCH] add crop setting, DynamicBendable like the image crate --- bingus/Cargo.toml | 4 +++ bingus/src/bin_/bytes.rs | 5 ++- bingus/src/img/image.rs | 68 ++++++++++++++++++++++++++---------- bingus/src/lib.rs | 75 ++++++++++++++++++++++++++++++++++++++-- 4 files changed, 130 insertions(+), 22 deletions(-) diff --git a/bingus/Cargo.toml b/bingus/Cargo.toml index ba3a65c..090a99d 100644 --- a/bingus/Cargo.toml +++ b/bingus/Cargo.toml @@ -13,3 +13,7 @@ keywords.workspace = true image = { version = "0.25", features = ["rayon"] } num = "0" rayon = "1" +infer = "0.16" +thiserror = "2.0" +derive-new = "0.7" +strum = { version = "0.26", features = ["derive"] } diff --git a/bingus/src/bin_/bytes.rs b/bingus/src/bin_/bytes.rs index 311a757..c1498f2 100644 --- a/bingus/src/bin_/bytes.rs +++ b/bingus/src/bin_/bytes.rs @@ -13,7 +13,7 @@ impl IntoDataBytes for Bytes { impl TryFromDataBytes for Bytes { type Error = Infallible; type Format = (); - fn try_from_bytes(bytes: Bytes, _: Self::Format) -> Result + fn try_from_bytes(bytes: Bytes, _: Self::Format, _: crate::Crop) -> Result where Self: Sized, { @@ -26,4 +26,7 @@ impl Bendable for Bytes { fn map Self::Unit + Sync>(self, f: F) -> Self { self.into_par_iter().map(|e| f(&e)).collect() } + fn format() -> crate::Format { + crate::Format::Binary + } } diff --git a/bingus/src/img/image.rs b/bingus/src/img/image.rs index aa0606c..2fb7f6d 100644 --- a/bingus/src/img/image.rs +++ b/bingus/src/img/image.rs @@ -34,24 +34,41 @@ where { type Error = (); type Format = Dimensions; - fn try_from_bytes(bytes: crate::Bytes, format: Self::Format) -> Result + fn try_from_bytes( + bytes: crate::Bytes, + format: Self::Format, + crop: crate::Crop, + ) -> Result where Self: Sized, { ImageBuffer::from_raw( format.width, format.height, - bytes - .chunks_exact(P::Subpixel::zero().to_ne_bytes().as_ref().len()) - .map(|p| { - P::Subpixel::from_ne_bytes( - &match ::Bytes::try_from(p) { - Ok(v) => v, - Err(_) => unreachable!("you messed up chunk size!"), - }, - ) - }) - .collect::>(), + match crop { + crate::Crop::End => bytes + .chunks_exact(P::Subpixel::zero().to_ne_bytes().as_ref().len()) + .map(|p| { + P::Subpixel::from_ne_bytes( + &match ::Bytes::try_from(p) { + Ok(v) => v, + Err(_) => unreachable!("you messed up chunk size!"), + }, + ) + }) + .collect::>(), + crate::Crop::Start => bytes + .rchunks_exact(P::Subpixel::zero().to_ne_bytes().as_ref().len()) + .map(|p| { + P::Subpixel::from_ne_bytes( + &match ::Bytes::try_from(p) { + Ok(v) => v, + Err(_) => unreachable!("you messed up chunk size!"), + }, + ) + }) + .collect::>(), + }, ) .ok_or(()) } @@ -69,6 +86,15 @@ where self.par_pixels_mut().for_each(|p| *p = f(p)); self } + fn format() -> crate::Format { + crate::Format::Image + } +} + +impl IntoDataBytes for DynamicImage { + fn into_bytes(self) -> crate::Bytes { + self.into_bytes() + } } #[cfg(test)] @@ -90,7 +116,8 @@ mod tests { Dimensions { width: 0, height: 0 - } + }, + Default::default() ) ) } @@ -105,7 +132,8 @@ mod tests { Dimensions { width: 3, height: 1 - } + }, + Default::default() ) ) } @@ -121,7 +149,8 @@ mod tests { Dimensions { width: 3, height: 1 - } + }, + Default::default() ) ) } @@ -141,7 +170,8 @@ mod tests { Dimensions { width: 3, height: 1 - } + }, + Default::default() ) ) } @@ -161,7 +191,8 @@ mod tests { Dimensions { width: 3, height: 1 - } + }, + Default::default() ) ) } @@ -181,7 +212,8 @@ mod tests { Dimensions { width: 3, height: 1 - } + }, + Default::default() ) ) } diff --git a/bingus/src/lib.rs b/bingus/src/lib.rs index 2195e59..56b043d 100644 --- a/bingus/src/lib.rs +++ b/bingus/src/lib.rs @@ -5,31 +5,100 @@ pub mod txt; pub(crate) type Bytes = Vec; +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>(path: P) -> Result, 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 { type Unit; fn bend_into( self, format: ::Format, + crop: Crop, ) -> Result::Error> { - T::bend_from(self, format) + T::bend_from(self, format, crop) } fn bend_from( b: T, format: ::Format, + crop: Crop, ) -> Result::Error> { - Self::try_from_bytes(b.into_bytes(), format) + Self::try_from_bytes(b.into_bytes(), format, crop) } fn map Self::Unit + Sync>(self, f: F) -> Self; + fn format() -> Format; } pub trait IntoDataBytes: Sized { fn into_bytes(self) -> Bytes; } +#[derive(Default)] +pub enum Crop { + Start, + #[default] + End, +} + pub trait TryFromDataBytes { type Error; type Format; - fn try_from_bytes(bytes: Bytes, format: Self::Format) -> Result + fn try_from_bytes(bytes: Bytes, format: Self::Format, crop: Crop) -> Result where Self: Sized; }