some small changes

This commit is contained in:
bendn 2024-05-06 11:11:51 +07:00
parent 3a1b6a3435
commit 0dffa5bc99
4 changed files with 90 additions and 31 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "fimg"
version = "0.4.41"
version = "0.4.42"
authors = ["bend-n <bend.n@outlook.com>"]
license = "MIT"
edition = "2021"
@ -14,19 +14,19 @@ categories = ["multimedia::images", "graphics"]
mattr = "0.0.2"
png = { version = "0.17", features = ["unstable"], optional = true }
fontdue = { version = "0.7.3", optional = true }
vecto = "0.1.0"
vecto = "0.1.1"
umath = "0.0.7"
fr = { version = "0.1.1", package = "fer", optional = true }
slur = { version = "0.1.0", optional = true }
clipline = "0.1.1"
clipline = "0.1.2"
minifb = { version = "0.25.0", default-features = false, features = [
"x11",
"wayland",
], optional = true }
wgpu = { version = "0.19.1", default-features = false, optional = true }
atools = "0.1.0"
atools = "0.1.4"
qwant = { version = "1.0.0", optional = true }
libc = "0.2.153"
libc = "0.2.154"
[target.'cfg(windows)'.dependencies]
windows = { version = "0.53.0", features = [

View file

@ -78,6 +78,10 @@ impl<T: Copy, const C: usize> Builder<Box<[T]>, C> {
/// seals the [`Buffer`] trait
mod buf {
/// A valid buffer for use in the builder
#[diagnostic::on_unimplemented(
message = "this type is not a buffer",
note = "if you think this type is a buffer, please open an issue.\nYou can manually circumvent this warning via Image::new."
)]
pub trait Buffer {
#[doc(hidden)]
fn len(&self) -> usize;

View file

@ -56,10 +56,8 @@
slice_swap_unchecked,
generic_const_exprs,
iter_array_chunks,
split_at_checked,
core_intrinsics,
slice_as_chunks,
unchecked_math,
slice_flatten,
rustc_private,
portable_simd,
@ -320,6 +318,12 @@ impl<T, const CHANNELS: usize> Image<T, CHANNELS> {
// SAFETY: we dont change anything, why check
unsafe { Image::new(self.width, self.height, f(self.buffer)) }
}
/// # Safety
/// buffer size must be the same.
unsafe fn map_into<U: From<T>, const N: usize>(self) -> Image<U, N> {
unsafe { self.mapped(Into::into) }
}
}
impl<const CHANNELS: usize, T: Clone> Image<&[T], CHANNELS> {
@ -379,7 +383,7 @@ impl<const CHANNELS: usize, const N: usize> Image<[u8; N], CHANNELS> {
/// Box this array image.
pub fn boxed(self) -> Image<Box<[u8]>, CHANNELS> {
// SAFETY: size not changed
unsafe { self.mapped(|b| b.into()) }
unsafe { self.map_into() }
}
}
@ -387,7 +391,7 @@ impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
/// Box this image.
pub fn boxed(self) -> Image<Box<[u8]>, CHANNELS> {
// SAFETY: size not changed
unsafe { self.mapped(|b| b.into()) }
unsafe { self.map_into() }
}
}
@ -395,7 +399,15 @@ impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
/// Box this owned image.
pub fn boxed(self) -> Image<Box<[u8]>, CHANNELS> {
// SAFETY: ctor
unsafe { self.mapped(|b| b.into()) }
unsafe { self.map_into() }
}
}
impl<const CHANNELS: usize> Image<Box<[u8]>, CHANNELS> {
/// Unbox this vec image.
pub fn unbox(self) -> Image<Vec<u8>, CHANNELS> {
// SAFETY: ctor
unsafe { self.map_into() }
}
}
@ -624,6 +636,16 @@ pub trait WritePng {
fn write(&self, f: &mut impl std::io::Write) -> std::io::Result<()>;
}
/// Read png.
#[cfg(feature = "save")]
pub trait ReadPng
where
Self: Sized,
{
/// Read a png into an image.
fn read(f: &mut impl std::io::Read) -> std::io::Result<Self>;
}
/// helper macro for defining the save() method.
macro_rules! save {
($channels:literal == $clr:ident ($clrhuman:literal)) => {
@ -663,34 +685,67 @@ macro_rules! save {
};
}
impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
macro_rules! read {
($n:literal) => {
#[cfg(feature = "save")]
impl ReadPng for Image<Box<[u8]>, $n> {
/// Open a PNG image
fn read(f: &mut impl std::io::Read) -> std::io::Result<Self> {
use png::Transformations as T;
let mut dec = png::Decoder::new(f);
match $n {
1 | 3 => dec.set_transformations(T::STRIP_16 | T::EXPAND),
2 | 4 => dec.set_transformations(T::STRIP_16 | T::ALPHA), // alpha implies expand
_ => (),
}
let mut reader = dec.read_info()?;
let mut buf = vec![0; reader.output_buffer_size()].into_boxed_slice();
let info = reader.next_frame(&mut buf)?;
use png::ColorType::*;
macro_rules! n {
($x:literal) => {
Image::<_, $x>::build(info.width, info.height)
.buf(buf)
.into()
};
}
Ok(match info.color_type {
Indexed => unreachable!(), // see EXPAND
Grayscale => n![1],
GrayscaleAlpha => n![2],
Rgb => n![3],
Rgba => n![4],
})
}
}
};
}
impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS>
where
[(); { (CHANNELS <= 4) as usize } - 1]:,
{
#[cfg(feature = "save")]
/// Open a PNG image
pub fn open(f: impl AsRef<std::path::Path>) -> Self {
use png::Transformations as T;
let p = std::fs::File::open(f).unwrap();
let r = std::io::BufReader::new(p);
let mut dec = png::Decoder::new(r);
let r = &mut std::io::BufReader::new(p);
use core::intrinsics::transmute_unchecked as t;
// SAFETY: ... this is idiotic.
unsafe {
match CHANNELS {
1 | 3 => dec.set_transformations(T::STRIP_16 | T::EXPAND),
2 | 4 => dec.set_transformations(T::STRIP_16 | T::ALPHA),
_ => (),
}
let mut reader = dec.read_info().unwrap();
let mut buf = vec![0; reader.output_buffer_size()];
let info = reader.next_frame(&mut buf).unwrap();
use png::ColorType::*;
match info.color_type {
Indexed | Grayscale => {
assert_eq!(CHANNELS, 1, "indexed | grayscale requires one channel")
}
Rgb => assert_eq!(CHANNELS, 3, "rgb requires three channels"),
Rgba => assert_eq!(CHANNELS, 4, "rgba requires four channels"),
GrayscaleAlpha => assert_eq!(CHANNELS, 2, "ya requires two channels"),
}
Self::build(info.width, info.height).buf(buf)
1 => t(Image::<Box<_>, 1>::read(r).unwrap().unbox()),
2 => t(Image::<Box<_>, 2>::read(r).unwrap().unbox()),
3 => t(Image::<Box<_>, 3>::read(r).unwrap().unbox()),
4 => t(Image::<Box<_>, 4>::read(r).unwrap().unbox()),
_ => unreachable!(),
}
}
}
}
read!(1);
read!(2);
read!(3);
read!(4);
save!(3 == Rgb("RGB"));
save!(4 == Rgba("RGBA"));