png/common.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
//! Common types shared between the encoder and decoder
extern crate deflate;
use filter;
#[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
}
}
}
/// Frame control information
#[derive(Clone, 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: u8,
/// Type of frame area rendering for this frame
pub blend_op: u8,
}
/// 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,
}
#[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,
}
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(),
}
}
}
/// 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: deflate::Compression::Fast.into(),
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 */
}
}