png_codec 0.1.1

A minimal pure Rust PNG encoder
Documentation
//! A library for encoding PNG images, supporting indexed images.
//!
//! ## Getting Started
//! Add the following to your `Cargo.toml`.
//!
//! ```toml
//! [dependencies.png_codec]
//! version = "0.1"
//! ```
//!
//! ### Example
//! ```rust
//! let mut data = vec![0u8; 512 * 512];
//! for i in 0..512 * 512 {
//!     data[i] = (i % 7) as u8;
//! }
//! let png = png_codec::IndexedImage {
//!     height: 512,
//!     width: 512,
//!     pixels: &data,
//!     palette: &[
//!         Rgba::new(0, 0, 0, 255),
//!         Rgba::new(255, 0, 255, 255),
//!         Rgba::new(255, 0, 0, 255),
//!         Rgba::new(0, 10, 90, 255),
//!         Rgba::new(255, 0, 0, 200),
//!         Rgba::new(255, 1, 90, 255),
//!         Rgba::new(0, 10, 90, 255),
//!     ],
//! };
//! let encoded = png.encode_png(5).unwrap();
//! std::fs::write("graphic.png", &encoded).expect("Failed to save image");
//! ```

#![doc(
    html_logo_url = "https://raw.githubusercontent.com/AldaronLau/png_pong/master/res/icon.png",
    html_favicon_url = "https://raw.githubusercontent.com/AldaronLau/png_pong/master/res/icon.png",
    html_root_url = "https://docs.rs/png_pong"
)]
#![forbid(unsafe_code)]
#![warn(
    anonymous_parameters,
    missing_copy_implementations,
    nonstandard_style,
    rust_2018_idioms,
    single_use_lifetimes,
    trivial_casts,
    trivial_numeric_casts,
    unreachable_pub,
    unused_extern_crates,
    unused_qualifications,
    variant_size_differences
)]

mod chunk;
// pub mod decode;
mod consts;
mod encode;
mod encoder;
mod zlib;

#[derive(Debug, Clone, Copy)]
pub struct Rgb {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

#[derive(Debug, Clone, Copy)]
pub struct Rgba {
    pub r: u8,
    pub g: u8,
    pub b: u8,
    pub a: u8,
}

impl Rgba {
    pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
        Self { r, g, b, a }
    }
    pub fn blend(&self, secondary: Rgba, primary_ratio: f64) -> Rgba {
        let ratio = ((primary_ratio * 1024.0) as u32).min(1024);
        let inv_ratio = 1024 - ratio;
        let blended = |a: u8, b: u8| {
            ((a as u32 * ratio + b as u32 * inv_ratio) >> 10).min(255) as u8
        };
        Rgba {
            r: blended(self.r, secondary.r),
            g: blended(self.g, secondary.g),
            b: blended(self.b, secondary.b),
            a: blended(self.a, secondary.a),
        }
    }
    pub const fn from_be(rgba: u32) -> Self {
        let rgba = rgba.to_be_bytes();
        Self {
            r: rgba[0],
            g: rgba[1],
            b: rgba[2],
            a: rgba[3],
        }
    }
}

impl From<[u8; 4]> for Rgba {
    fn from(rgba: [u8; 4]) -> Self {
        Self {
            r: rgba[0],
            g: rgba[1],
            b: rgba[2],
            a: rgba[3],
        }
    }
}
impl From<u32> for Rgba {
    fn from(rgba: u32) -> Self {
        rgba.to_be_bytes().into()
    }
}
use encode::Error;
// pub use decoder::Decoder;
pub use encoder::Encoder;

/// Raw Data for Indexed Image
pub struct IndexedImage<'a> {
    /// Indices into palette Row major
    pub pixels: &'a [u8],
    /// width of image
    pub width: u32,
    /// height of image
    pub height: u32,
    /// colors
    pub palette: &'a [Rgba],
}

impl IndexedImage<'_> {
    #[inline(never)]
    pub fn encode(&self, compression: u8) -> Result<Vec<u8>, Error> {
        let mut encoder = Encoder::new()
            .compression_level(compression)
            .into_step_enc();
        encoder.encode(self.pixels, self.width, self.height, self.palette)?;
        Ok(encoder.encoder.encode.writer)
    }
}