pnm decoding and encoding
add some docs
| -rw-r--r-- | README.md | 13 | ||||
| -rw-r--r-- | src/decode.rs | 2 | ||||
| -rw-r--r-- | src/lib.rs | 64 | ||||
| -rw-r--r-- | src/pam.rs | 26 | ||||
| -rw-r--r-- | src/ppm.rs | 8 | ||||
| -rw-r--r-- | tdata/fimg-rainbowA.ppm (renamed from tdata/fimgA.ppm) | 0 | ||||
| -rw-r--r-- | tdata/fimg-rainbowR.ppm (renamed from tdata/fimgR.ppm) | bin | 913 -> 913 bytes |
7 files changed, 96 insertions, 17 deletions
@@ -1,3 +1,14 @@ # PNM -provides encoders and decoders for the portable anymap formats.
\ No newline at end of file +provides encoders and decoders for the portable anymap formats. + +> **Warning** 16 bit images are not supported. + +### pnm format depth support table + +||[PBM](https://docs.rs/pnm/latest/pnm/pbm/index.html)|[PGM](https://docs.rs/pnm/latest/pnm/pgm/index.html)|[PPM](https://docs.rs/pnm/latest/pnm/ppm/index.html)|[PAM](https://docs.rs/pnm/latest/pnm/pam/index.html) +|----|--|--|--|--| +|Y |✅|✅|❎|✅| +|YA |❎|❎|❎|✅| +|RGB |❎|❎|✅|✅| +|RGBA|❎|❎|❎|✅| diff --git a/src/decode.rs b/src/decode.rs index 183d2ec..4ca678c 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -86,6 +86,7 @@ macro_rules! dec_fn { pub(crate) use dec_fn; /// Header for the older PNM formats. Not applicable to PAM. +#[derive(Debug, Clone, Copy)] pub struct Header { /// Magic number. pub magic: u8, @@ -135,6 +136,7 @@ impl std::fmt::Display for Error { } } } +impl std::error::Error for Error {} /// Decodes the magic number. pub fn magic(x: &mut &[u8]) -> Option<u8> { @@ -1,13 +1,26 @@ //! crate for decoding/encoding the portable anymap format. +//! +//! ### a quick guide to the various functions for everyday use +//! +//! - [`decode()`]: your go-to for all PNM image decoding. +//! If you have a specific format you need to support, use its module directly. +//! Note that this function reads both plain and raw formats. +//! - [`encode()`]: this function is a little tricky. +//! It supports the "older" PNM formats, and, due to their age they do not support the alpha channels existence. +//! If possible, use [`pam::encode`] instead. +//! - [`encode_plain`]: The `PAM` format doesnt actually support read-age-by-humans, so this is still useful at times. +//! Outputs data in decimal digits. +//! +//! ### functions in action +//! +//! ``` +//! let data = include_bytes!("../tdata/fimg-rainbowR.ppm"); +//! let out = pnm::decode(data).unwrap(); +//! +//! assert_eq!(pnm::encode(out), data); +//! ``` #![allow(incomplete_features)] -#![feature( - test, - generic_const_exprs, - ptr_sub_ptr, - array_chunks, - let_chains, - iter_array_chunks -)] +#![feature(ptr_sub_ptr, let_chains, iter_array_chunks)] #![warn( clippy::missing_const_for_fn, clippy::suboptimal_flops, @@ -55,10 +68,21 @@ pub fn decode(x: &impl AsRef<[u8]>) -> decode::Result<DynImage<Vec<u8>>> { /// Encodes an image to one of the [`pgm`] or [`ppm`] portable anymap formats. /// /// Please note that this will not produce a [`pam`], use [`PAM`] for that. +pub fn encode(x: impl Encode) -> Vec<u8> { + x.encode() +} + +/// Encodes an image to one of the [`pgm`] or [`ppm`] portable anymap formats. +/// +/// Please note that this will not produce a [`pam`], use [`PAM`] for that. +/// ASCII EDITION! +pub fn encode_plain(x: impl Encode) -> String { + x.encode_plain() +} + +#[doc(hidden)] pub trait Encode { - /// Encodes an image to one of the [`pgm`] or [`ppm`] portable anymap formats. fn encode(self) -> Vec<u8>; - /// ASCII EDITION. fn encode_plain(self) -> String; } @@ -88,3 +112,23 @@ x![pgm]; x![t pgm, 2]; x![ppm]; x![t ppm, 4]; + +macro_rules! e { + ($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: AsRef<[u8]>> Encode for DynImage<T> { + fn encode(self) -> Vec<u8> { + e!(self, |x| encode(x)) + } + fn encode_plain(self) -> String { + e!(self, |x| encode_plain(x)) + } +} @@ -10,8 +10,20 @@ use fimg::{DynImage, Image}; pub const MAGIC: u8 = 7; -/// Encode an <code>[Image]<[u8], N></code> to [PAM](https://en.wikipedia.org/wiki/Netpbm#PAM_graphics_format) Raw (binary) Image. -/// And decode. +/// Encode this <code>[Image]<[u8], N></code> to a [PAM](https://en.wikipedia.org/wiki/Netpbm#PAM_graphics_format) Raw (binary) Image. +/// +/// ``` +/// # use pnm::pam; +/// # use fimg::Image; +/// let out = pam::encode( +/// Image::<_, 1>::build(20, 15).buf(&include_bytes!("../tdata/fimg-gray.imgbuf")[..]) +/// ); +/// ``` +pub fn encode(x: impl PAM) -> Vec<u8> { + x.encode() +} + +#[doc(hidden)] pub trait PAM { /// Encode this image to pam. fn encode(self) -> Vec<u8>; @@ -100,6 +112,16 @@ impl<T: AsRef<[u8]>> PAM for Image<T, 4> { } } +impl<T: AsRef<[u8]>> PAM for DynImage<T> { + fn encode(self) -> Vec<u8> { + super::e!(self, |x| encode(x)) + } + + unsafe fn encode_into(x: Self, out: *mut u8) -> usize { + super::e!(x, |x| PAM::encode_into(x, out)) + } +} + #[inline] unsafe fn encode_into<const N: usize>( (buf, (w, h)): (&[u8], (u32, u32)), @@ -91,14 +91,14 @@ pub mod plain { fn test_encode() { assert_eq!( encode(Image::build(20, 15).buf(tdata())), - include_str!("../tdata/fimgA.ppm") + include_str!("../tdata/fimg-rainbowA.ppm") ); } #[test] fn test_decode() { assert_eq!( - &**decode(include_bytes!("../tdata/fimgA.ppm")) + &**decode(include_bytes!("../tdata/fimg-rainbowA.ppm")) .unwrap() .buffer(), tdata() @@ -163,7 +163,7 @@ pub mod raw { #[test] fn test_decode() { assert_eq!( - &**decode(include_bytes!("../tdata/fimgR.ppm")) + &**decode(include_bytes!("../tdata/fimg-rainbowR.ppm")) .unwrap() .buffer(), tdata() @@ -174,7 +174,7 @@ pub mod raw { fn test_encode() { assert_eq!( encode(Image::build(20, 15).buf(tdata())), - include_bytes!("../tdata/fimgR.ppm") + include_bytes!("../tdata/fimg-rainbowR.ppm") ); } } diff --git a/tdata/fimgA.ppm b/tdata/fimg-rainbowA.ppm index fe0ae58..fe0ae58 100644 --- a/tdata/fimgA.ppm +++ b/tdata/fimg-rainbowA.ppm diff --git a/tdata/fimgR.ppm b/tdata/fimg-rainbowR.ppm Binary files differindex 2bf5d88..2bf5d88 100644 --- a/tdata/fimgR.ppm +++ b/tdata/fimg-rainbowR.ppm |