fast image operations
Diffstat (limited to 'src/dyn/mod.rs')
-rw-r--r--src/dyn/mod.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/dyn/mod.rs b/src/dyn/mod.rs
new file mode 100644
index 0000000..b86742e
--- /dev/null
+++ b/src/dyn/mod.rs
@@ -0,0 +1,121 @@
+use crate::Image;
+mod affine;
+mod convert;
+#[cfg(feature = "scale")]
+mod scale;
+
+#[derive(Clone, Debug, PartialEq)]
+/// Dynamic image.
+/// Can be any of {`Y8`, `YA8`, `RGB8`, `RGB16`}.
+pub enum DynImage<T> {
+ /// Y image
+ Y(Image<T, 1>),
+ /// YA image
+ Ya(Image<T, 2>),
+ /// RGB image
+ Rgb(Image<T, 3>),
+ /// RGBA image
+ Rgba(Image<T, 4>),
+}
+
+impl Copy for DynImage<&[u8]> {}
+
+macro_rules! e {
+ ($dyn:expr => |$image: pat_param| $do:expr) => {
+ match $dyn {
+ DynImage::Y($image) => DynImage::Y($do),
+ DynImage::Ya($image) => DynImage::Ya($do),
+ DynImage::Rgb($image) => DynImage::Rgb($do),
+ DynImage::Rgba($image) => DynImage::Rgba($do),
+ }
+ };
+ ($dyn:expr, |$image: pat_param| $do:expr) => {
+ match $dyn {
+ DynImage::Y($image) => $do,
+ DynImage::Ya($image) => $do,
+ DynImage::Rgb($image) => $do,
+ DynImage::Rgba($image) => $do,
+ }
+ };
+}
+use e;
+
+impl<T> DynImage<T> {
+ /// Get the width of this image.
+ pub const fn width(&self) -> u32 {
+ e!(self, |i| i.width())
+ }
+
+ /// Get the height of this image.
+ pub const fn height(&self) -> u32 {
+ e!(self, |i| i.height())
+ }
+
+ /// Get the image buffer.
+ pub const fn buffer(&self) -> &T {
+ e!(self, |i| i.buffer())
+ }
+
+ /// Take the image buffer.
+ pub fn take_buffer(self) -> T {
+ e!(self, |i| i.take_buffer())
+ }
+}
+
+impl<T: AsRef<[u8]>> DynImage<T> {
+ /// Reference this image.
+ pub fn as_ref(&self) -> DynImage<&[u8]> {
+ e!(self => |i| i.as_ref())
+ }
+
+ /// Bytes of this image.
+ pub fn bytes(&self) -> &[u8] {
+ e!(self, |i| i.bytes())
+ }
+}
+
+impl DynImage<Box<[u8]>> {
+ #[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);
+ dec.set_transformations(T::STRIP_16 | T::EXPAND);
+ let mut reader = dec.read_info().unwrap();
+ let mut buf = vec![0; reader.output_buffer_size()].into_boxed_slice();
+ let info = reader.next_frame(&mut buf).unwrap();
+ use png::ColorType::*;
+ match info.color_type {
+ Indexed | Grayscale => Self::Y(Image::build(info.width, info.height).buf(buf)),
+ Rgb => Self::Rgb(Image::build(info.width, info.height).buf(buf)),
+ Rgba => Self::Rgba(Image::build(info.width, info.height).buf(buf)),
+ GrayscaleAlpha => Self::Ya(Image::build(info.width, info.height).buf(buf)),
+ }
+ }
+
+ #[cfg(feature = "save")]
+ /// Save this image to a PNG.
+ pub fn save(&self, f: impl AsRef<std::path::Path>) {
+ let p = std::fs::File::create(f).unwrap();
+ let w = &mut std::io::BufWriter::new(p);
+ let mut enc = png::Encoder::new(w, self.width(), self.height());
+ enc.set_depth(png::BitDepth::Eight);
+ enc.set_color(match self {
+ Self::Y(_) => png::ColorType::Grayscale,
+ Self::Ya(_) => png::ColorType::GrayscaleAlpha,
+ Self::Rgb(_) => png::ColorType::Rgb,
+ Self::Rgba(_) => png::ColorType::Rgba,
+ });
+ enc.set_source_gamma(png::ScaledFloat::new(1.0 / 2.2));
+ enc.set_source_chromaticities(png::SourceChromaticities::new(
+ (0.31270, 0.32900),
+ (0.64000, 0.33000),
+ (0.30000, 0.60000),
+ (0.15000, 0.06000),
+ ));
+ let mut writer = enc.write_header().unwrap();
+ writer.write_image_data(self.bytes()).unwrap();
+ }
+}