diff options
Diffstat (limited to 'third_party/rust/png/src/common.rs')
-rw-r--r-- | third_party/rust/png/src/common.rs | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/third_party/rust/png/src/common.rs b/third_party/rust/png/src/common.rs new file mode 100644 index 0000000000..014efb751e --- /dev/null +++ b/third_party/rust/png/src/common.rs @@ -0,0 +1,404 @@ +//! Common types shared between the encoder and decoder +use crate::filter; + +use std::fmt; + +/// Describes the layout of samples in a pixel +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum ColorType { + Grayscale = 0, + RGB = 2, + Indexed = 3, + GrayscaleAlpha = 4, + RGBA = 6 +} + +impl ColorType { + /// Returns the number of samples used per pixel of `ColorType` + pub fn samples(&self) -> usize { + use self::ColorType::*; + match *self { + Grayscale | Indexed => 1, + RGB => 3, + GrayscaleAlpha => 2, + RGBA => 4 + } + } + + /// u8 -> Self. Temporary solution until Rust provides a canonical one. + pub fn from_u8(n: u8) -> Option<ColorType> { + match n { + 0 => Some(ColorType::Grayscale), + 2 => Some(ColorType::RGB), + 3 => Some(ColorType::Indexed), + 4 => Some(ColorType::GrayscaleAlpha), + 6 => Some(ColorType::RGBA), + _ => None + } + } +} + +/// Bit depth of the png file +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum BitDepth { + One = 1, + Two = 2, + Four = 4, + Eight = 8, + Sixteen = 16, +} + +impl BitDepth { + /// u8 -> Self. Temporary solution until Rust provides a canonical one. + pub fn from_u8(n: u8) -> Option<BitDepth> { + match n { + 1 => Some(BitDepth::One), + 2 => Some(BitDepth::Two), + 4 => Some(BitDepth::Four), + 8 => Some(BitDepth::Eight), + 16 => Some(BitDepth::Sixteen), + _ => None + } + } +} + +/// Pixel dimensions information +#[derive(Clone, Copy, Debug)] +pub struct PixelDimensions { + /// Pixels per unit, X axis + pub xppu: u32, + /// Pixels per unit, Y axis + pub yppu: u32, + /// Either *Meter* or *Unspecified* + pub unit: Unit, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +/// Physical unit of the pixel dimensions +pub enum Unit { + Unspecified = 0, + Meter = 1, +} + +impl Unit { + /// u8 -> Self. Temporary solution until Rust provides a canonical one. + pub fn from_u8(n: u8) -> Option<Unit> { + match n { + 0 => Some(Unit::Unspecified), + 1 => Some(Unit::Meter), + _ => None + } + } +} + +/// How to reset buffer of an animated png (APNG) at the end of a frame. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum DisposeOp { + /// Leave the buffer unchanged. + None = 0, + /// Clear buffer with the background color. + Background = 1, + /// Reset the buffer to the state before the current frame. + Previous = 2, +} + +impl DisposeOp { + /// u8 -> Self. Using enum_primitive or transmute is probably the right thing but this will do for now. + pub fn from_u8(n: u8) -> Option<DisposeOp> { + match n { + 0 => Some(DisposeOp::None), + 1 => Some(DisposeOp::Background), + 2 => Some(DisposeOp::Previous), + _ => None + } + } +} + +impl fmt::Display for DisposeOp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let name = match *self { + DisposeOp::None => "DISPOSE_OP_NONE", + DisposeOp::Background => "DISPOSE_OP_BACKGROUND", + DisposeOp::Previous => "DISPOSE_OP_PREVIOUS", + }; + write!(f, "{}", name) + } +} + +/// How pixels are written into the buffer. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum BlendOp { + /// Pixels overwrite the value at their position. + Source = 0, + /// The new pixels are blended into the current state based on alpha. + Over = 1, +} + +impl BlendOp { + /// u8 -> Self. Using enum_primitive or transmute is probably the right thing but this will do for now. + pub fn from_u8(n: u8) -> Option<BlendOp> { + match n { + 0 => Some(BlendOp::Source), + 1 => Some(BlendOp::Over), + _ => None + } + } +} + +impl fmt::Display for BlendOp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let name = match *self { + BlendOp::Source => "BLEND_OP_SOURCE", + BlendOp::Over => "BLEND_OP_OVER", + }; + write!(f, "{}", name) + } +} + +/// Frame control information +#[derive(Clone, Copy, Debug)] +pub struct FrameControl { + /// Sequence number of the animation chunk, starting from 0 + pub sequence_number: u32, + /// Width of the following frame + pub width: u32, + /// Height of the following frame + pub height: u32, + /// X position at which to render the following frame + pub x_offset: u32, + /// Y position at which to render the following frame + pub y_offset: u32, + /// Frame delay fraction numerator + pub delay_num: u16, + /// Frame delay fraction denominator + pub delay_den: u16, + /// Type of frame area disposal to be done after rendering this frame + pub dispose_op: DisposeOp, + /// Type of frame area rendering for this frame + pub blend_op: BlendOp, +} + +impl Default for FrameControl { + fn default() -> FrameControl { + FrameControl { + sequence_number: 0, + width: 0, + height: 0, + x_offset: 0, + y_offset: 0, + delay_num: 1, + delay_den: 30, + dispose_op: DisposeOp::None, + blend_op: BlendOp::Source, + } + } +} + +impl FrameControl { + pub fn set_seq_num(&mut self, s: u32) { + self.sequence_number = s; + } + + pub fn inc_seq_num(&mut self, i: u32) { + self.sequence_number += i; + } + +} + +/// Animation control information +#[derive(Clone, Copy, Debug)] +pub struct AnimationControl { + /// Number of frames + pub num_frames: u32, + /// Number of times to loop this APNG. 0 indicates infinite looping. + pub num_plays: u32, +} + +/// The type and strength of applied compression. +#[derive(Debug, Clone)] +pub enum Compression { + /// Default level + Default, + /// Fast minimal compression + Fast, + /// Higher compression level + /// + /// Best in this context isn't actually the highest possible level + /// the encoder can do, but is meant to emulate the `Best` setting in the `Flate2` + /// library. + Best, + Huffman, + Rle, +} + +/// PNG info struct +#[derive(Debug)] +pub struct Info { + pub width: u32, + pub height: u32, + pub bit_depth: BitDepth, + pub color_type: ColorType, + pub interlaced: bool, + pub trns: Option<Vec<u8>>, + pub pixel_dims: Option<PixelDimensions>, + pub palette: Option<Vec<u8>>, + pub frame_control: Option<FrameControl>, + pub animation_control: Option<AnimationControl>, + pub compression: Compression, + pub filter: filter::FilterType, +} + +impl Default for Info { + fn default() -> Info { + Info { + width: 0, + height: 0, + bit_depth: BitDepth::Eight, + color_type: ColorType::Grayscale, + interlaced: false, + palette: None, + trns: None, + pixel_dims: None, + frame_control: None, + animation_control: None, + // Default to `deflate::Compresion::Fast` and `filter::FilterType::Sub` + // to maintain backward compatible output. + compression: Compression::Fast, + filter: filter::FilterType::Sub, + } + } +} + +impl Info { + /// Size of the image + pub fn size(&self) -> (u32, u32) { + (self.width, self.height) + } + + /// Returns true if the image is an APNG image. + pub fn is_animated(&self) -> bool { + self.frame_control.is_some() && self.animation_control.is_some() + } + + /// Returns the frame control information of the image + pub fn animation_control(&self) -> Option<&AnimationControl> { + self.animation_control.as_ref() + } + + /// Returns the frame control information of the current frame + pub fn frame_control(&self) -> Option<&FrameControl> { + self.frame_control.as_ref() + } + + /// Returns the bits per pixel + pub fn bits_per_pixel(&self) -> usize { + self.color_type.samples() * self.bit_depth as usize + } + + /// Returns the bytes per pixel + pub fn bytes_per_pixel(&self) -> usize { + self.color_type.samples() * ((self.bit_depth as usize + 7) >> 3) + } + + /// Returns the number of bytes needed for one deinterlaced image + pub fn raw_bytes(&self) -> usize { + self.height as usize * self.raw_row_length() + } + + /// Returns the number of bytes needed for one deinterlaced row + pub fn raw_row_length(&self) -> usize { + let bits = self.width as usize * self.color_type.samples() * self.bit_depth as usize; + let extra = bits % 8; + bits/8 + + match extra { 0 => 0, _ => 1 } + + 1 // filter method + } + + /// Returns the number of bytes needed for one deinterlaced row of width `width` + pub fn raw_row_length_from_width(&self, width: u32) -> usize { + let bits = width as usize * self.color_type.samples() * self.bit_depth as usize; + let extra = bits % 8; + bits/8 + + match extra { 0 => 0, _ => 1 } + + 1 // filter method + } +} + + +bitflags! { + /// # Output transformations + /// + /// Only `IDENTITY` and `TRANSFORM_EXPAND | TRANSFORM_STRIP_ALPHA` can be used at the moment. + pub struct Transformations: u32 { + /// No transformation + const IDENTITY = 0x0000; // read and write */ + /// Strip 16-bit samples to 8 bits + const STRIP_16 = 0x0001; // read only */ + /// Discard the alpha channel + const STRIP_ALPHA = 0x0002; // read only */ + /// Expand 1; 2 and 4-bit samples to bytes + const PACKING = 0x0004; // read and write */ + /// Change order of packed pixels to LSB first + const PACKSWAP = 0x0008; // read and write */ + /// Expand paletted images to RGB; expand grayscale images of + /// less than 8-bit depth to 8-bit depth; and expand tRNS chunks + /// to alpha channels. + const EXPAND = 0x0010; // read only */ + /// Invert monochrome images + const INVERT_MONO = 0x0020; // read and write */ + /// Normalize pixels to the sBIT depth + const SHIFT = 0x0040; // read and write */ + /// Flip RGB to BGR; RGBA to BGRA + const BGR = 0x0080; // read and write */ + /// Flip RGBA to ARGB or GA to AG + const SWAP_ALPHA = 0x0100; // read and write */ + /// Byte-swap 16-bit samples + const SWAP_ENDIAN = 0x0200; // read and write */ + /// Change alpha from opacity to transparency + const INVERT_ALPHA = 0x0400; // read and write */ + const STRIP_FILLER = 0x0800; // write only */ + const STRIP_FILLER_BEFORE = 0x0800; // write only + const STRIP_FILLER_AFTER = 0x1000; // write only */ + const GRAY_TO_RGB = 0x2000; // read only */ + const EXPAND_16 = 0x4000; // read only */ + const SCALE_16 = 0x8000; // read only */ + } +} + +/// Mod to encapsulate the converters depending on the `deflate` crate. +/// +/// Since this only contains trait impls, there is no need to make this public, they are simply +/// available when the mod is compiled as well. +#[cfg(feature = "png-encoding")] +mod deflate_convert { + extern crate deflate; + use super::Compression; + + impl From<deflate::Compression> for Compression { + fn from(c: deflate::Compression) -> Self { + match c { + deflate::Compression::Default => Compression::Default, + deflate::Compression::Fast => Compression::Fast, + deflate::Compression::Best => Compression::Best, + } + } + } + + impl From<Compression> for deflate::CompressionOptions { + fn from(c: Compression) -> Self { + match c { + Compression::Default => deflate::CompressionOptions::default(), + Compression::Fast => deflate::CompressionOptions::fast(), + Compression::Best => deflate::CompressionOptions::high(), + Compression::Huffman => deflate::CompressionOptions::huffman_only(), + Compression::Rle => deflate::CompressionOptions::rle(), + } + } + } +} + |