1 //! Common types shared between the encoder and decoder 2 use crate::filter; 3 4 use std::fmt; 5 6 /// Describes the layout of samples in a pixel 7 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 8 #[repr(u8)] 9 pub enum ColorType { 10 Grayscale = 0, 11 RGB = 2, 12 Indexed = 3, 13 GrayscaleAlpha = 4, 14 RGBA = 6, 15 } 16 17 impl ColorType { 18 /// Returns the number of samples used per pixel of `ColorType` samples(&self) -> usize19 pub fn samples(&self) -> usize { 20 use self::ColorType::*; 21 match *self { 22 Grayscale | Indexed => 1, 23 RGB => 3, 24 GrayscaleAlpha => 2, 25 RGBA => 4, 26 } 27 } 28 29 /// u8 -> Self. Temporary solution until Rust provides a canonical one. from_u8(n: u8) -> Option<ColorType>30 pub fn from_u8(n: u8) -> Option<ColorType> { 31 match n { 32 0 => Some(ColorType::Grayscale), 33 2 => Some(ColorType::RGB), 34 3 => Some(ColorType::Indexed), 35 4 => Some(ColorType::GrayscaleAlpha), 36 6 => Some(ColorType::RGBA), 37 _ => None, 38 } 39 } 40 } 41 42 /// Bit depth of the png file 43 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 44 #[repr(u8)] 45 pub enum BitDepth { 46 One = 1, 47 Two = 2, 48 Four = 4, 49 Eight = 8, 50 Sixteen = 16, 51 } 52 53 impl BitDepth { 54 /// u8 -> Self. Temporary solution until Rust provides a canonical one. from_u8(n: u8) -> Option<BitDepth>55 pub fn from_u8(n: u8) -> Option<BitDepth> { 56 match n { 57 1 => Some(BitDepth::One), 58 2 => Some(BitDepth::Two), 59 4 => Some(BitDepth::Four), 60 8 => Some(BitDepth::Eight), 61 16 => Some(BitDepth::Sixteen), 62 _ => None, 63 } 64 } 65 } 66 67 /// Pixel dimensions information 68 #[derive(Clone, Copy, Debug)] 69 pub struct PixelDimensions { 70 /// Pixels per unit, X axis 71 pub xppu: u32, 72 /// Pixels per unit, Y axis 73 pub yppu: u32, 74 /// Either *Meter* or *Unspecified* 75 pub unit: Unit, 76 } 77 78 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 79 #[repr(u8)] 80 /// Physical unit of the pixel dimensions 81 pub enum Unit { 82 Unspecified = 0, 83 Meter = 1, 84 } 85 86 impl Unit { 87 /// u8 -> Self. Temporary solution until Rust provides a canonical one. from_u8(n: u8) -> Option<Unit>88 pub fn from_u8(n: u8) -> Option<Unit> { 89 match n { 90 0 => Some(Unit::Unspecified), 91 1 => Some(Unit::Meter), 92 _ => None, 93 } 94 } 95 } 96 97 /// How to reset buffer of an animated png (APNG) at the end of a frame. 98 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 99 #[repr(u8)] 100 pub enum DisposeOp { 101 /// Leave the buffer unchanged. 102 None = 0, 103 /// Clear buffer with the background color. 104 Background = 1, 105 /// Reset the buffer to the state before the current frame. 106 Previous = 2, 107 } 108 109 impl DisposeOp { 110 /// u8 -> Self. Using enum_primitive or transmute is probably the right thing but this will do for now. from_u8(n: u8) -> Option<DisposeOp>111 pub fn from_u8(n: u8) -> Option<DisposeOp> { 112 match n { 113 0 => Some(DisposeOp::None), 114 1 => Some(DisposeOp::Background), 115 2 => Some(DisposeOp::Previous), 116 _ => None, 117 } 118 } 119 } 120 121 impl fmt::Display for DisposeOp { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 123 let name = match *self { 124 DisposeOp::None => "DISPOSE_OP_NONE", 125 DisposeOp::Background => "DISPOSE_OP_BACKGROUND", 126 DisposeOp::Previous => "DISPOSE_OP_PREVIOUS", 127 }; 128 write!(f, "{}", name) 129 } 130 } 131 132 /// How pixels are written into the buffer. 133 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 134 #[repr(u8)] 135 pub enum BlendOp { 136 /// Pixels overwrite the value at their position. 137 Source = 0, 138 /// The new pixels are blended into the current state based on alpha. 139 Over = 1, 140 } 141 142 impl BlendOp { 143 /// u8 -> Self. Using enum_primitive or transmute is probably the right thing but this will do for now. from_u8(n: u8) -> Option<BlendOp>144 pub fn from_u8(n: u8) -> Option<BlendOp> { 145 match n { 146 0 => Some(BlendOp::Source), 147 1 => Some(BlendOp::Over), 148 _ => None, 149 } 150 } 151 } 152 153 impl fmt::Display for BlendOp { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result154 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 155 let name = match *self { 156 BlendOp::Source => "BLEND_OP_SOURCE", 157 BlendOp::Over => "BLEND_OP_OVER", 158 }; 159 write!(f, "{}", name) 160 } 161 } 162 163 /// Frame control information 164 #[derive(Clone, Copy, Debug)] 165 pub struct FrameControl { 166 /// Sequence number of the animation chunk, starting from 0 167 pub sequence_number: u32, 168 /// Width of the following frame 169 pub width: u32, 170 /// Height of the following frame 171 pub height: u32, 172 /// X position at which to render the following frame 173 pub x_offset: u32, 174 /// Y position at which to render the following frame 175 pub y_offset: u32, 176 /// Frame delay fraction numerator 177 pub delay_num: u16, 178 /// Frame delay fraction denominator 179 pub delay_den: u16, 180 /// Type of frame area disposal to be done after rendering this frame 181 pub dispose_op: DisposeOp, 182 /// Type of frame area rendering for this frame 183 pub blend_op: BlendOp, 184 } 185 186 impl Default for FrameControl { default() -> FrameControl187 fn default() -> FrameControl { 188 FrameControl { 189 sequence_number: 0, 190 width: 0, 191 height: 0, 192 x_offset: 0, 193 y_offset: 0, 194 delay_num: 1, 195 delay_den: 30, 196 dispose_op: DisposeOp::None, 197 blend_op: BlendOp::Source, 198 } 199 } 200 } 201 202 impl FrameControl { set_seq_num(&mut self, s: u32)203 pub fn set_seq_num(&mut self, s: u32) { 204 self.sequence_number = s; 205 } 206 inc_seq_num(&mut self, i: u32)207 pub fn inc_seq_num(&mut self, i: u32) { 208 self.sequence_number += i; 209 } 210 } 211 212 /// Animation control information 213 #[derive(Clone, Copy, Debug)] 214 pub struct AnimationControl { 215 /// Number of frames 216 pub num_frames: u32, 217 /// Number of times to loop this APNG. 0 indicates infinite looping. 218 pub num_plays: u32, 219 } 220 221 /// The type and strength of applied compression. 222 #[derive(Debug, Clone)] 223 pub enum Compression { 224 /// Default level 225 Default, 226 /// Fast minimal compression 227 Fast, 228 /// Higher compression level 229 /// 230 /// Best in this context isn't actually the highest possible level 231 /// the encoder can do, but is meant to emulate the `Best` setting in the `Flate2` 232 /// library. 233 Best, 234 Huffman, 235 Rle, 236 } 237 238 /// PNG info struct 239 #[derive(Debug)] 240 pub struct Info { 241 pub width: u32, 242 pub height: u32, 243 pub bit_depth: BitDepth, 244 pub color_type: ColorType, 245 pub interlaced: bool, 246 pub trns: Option<Vec<u8>>, 247 pub pixel_dims: Option<PixelDimensions>, 248 pub palette: Option<Vec<u8>>, 249 pub frame_control: Option<FrameControl>, 250 pub animation_control: Option<AnimationControl>, 251 pub compression: Compression, 252 pub filter: filter::FilterType, 253 } 254 255 impl Default for Info { default() -> Info256 fn default() -> Info { 257 Info { 258 width: 0, 259 height: 0, 260 bit_depth: BitDepth::Eight, 261 color_type: ColorType::Grayscale, 262 interlaced: false, 263 palette: None, 264 trns: None, 265 pixel_dims: None, 266 frame_control: None, 267 animation_control: None, 268 // Default to `deflate::Compresion::Fast` and `filter::FilterType::Sub` 269 // to maintain backward compatible output. 270 compression: Compression::Fast, 271 filter: filter::FilterType::Sub, 272 } 273 } 274 } 275 276 impl Info { 277 /// Size of the image size(&self) -> (u32, u32)278 pub fn size(&self) -> (u32, u32) { 279 (self.width, self.height) 280 } 281 282 /// Returns true if the image is an APNG image. is_animated(&self) -> bool283 pub fn is_animated(&self) -> bool { 284 self.frame_control.is_some() && self.animation_control.is_some() 285 } 286 287 /// Returns the frame control information of the image animation_control(&self) -> Option<&AnimationControl>288 pub fn animation_control(&self) -> Option<&AnimationControl> { 289 self.animation_control.as_ref() 290 } 291 292 /// Returns the frame control information of the current frame frame_control(&self) -> Option<&FrameControl>293 pub fn frame_control(&self) -> Option<&FrameControl> { 294 self.frame_control.as_ref() 295 } 296 297 /// Returns the bits per pixel bits_per_pixel(&self) -> usize298 pub fn bits_per_pixel(&self) -> usize { 299 self.color_type.samples() * self.bit_depth as usize 300 } 301 302 /// Returns the bytes per pixel bytes_per_pixel(&self) -> usize303 pub fn bytes_per_pixel(&self) -> usize { 304 self.color_type.samples() * ((self.bit_depth as usize + 7) >> 3) 305 } 306 307 /// Returns the number of bytes needed for one deinterlaced image raw_bytes(&self) -> usize308 pub fn raw_bytes(&self) -> usize { 309 self.height as usize * self.raw_row_length() 310 } 311 312 /// Returns the number of bytes needed for one deinterlaced row raw_row_length(&self) -> usize313 pub fn raw_row_length(&self) -> usize { 314 let bits = self.width as usize * self.color_type.samples() * self.bit_depth as usize; 315 let extra = bits % 8; 316 bits / 8 317 + match extra { 318 0 => 0, 319 _ => 1, 320 } 321 + 1 // filter method 322 } 323 324 /// Returns the number of bytes needed for one deinterlaced row of width `width` raw_row_length_from_width(&self, width: u32) -> usize325 pub fn raw_row_length_from_width(&self, width: u32) -> usize { 326 let bits = width as usize * self.color_type.samples() * self.bit_depth as usize; 327 let extra = bits % 8; 328 bits / 8 329 + match extra { 330 0 => 0, 331 _ => 1, 332 } 333 + 1 // filter method 334 } 335 } 336 337 bitflags! { 338 /// # Output transformations 339 /// 340 /// Only `IDENTITY` and `TRANSFORM_EXPAND | TRANSFORM_STRIP_ALPHA` can be used at the moment. 341 pub struct Transformations: u32 { 342 /// No transformation 343 const IDENTITY = 0x0000; // read and write */ 344 /// Strip 16-bit samples to 8 bits 345 const STRIP_16 = 0x0001; // read only */ 346 /// Discard the alpha channel 347 const STRIP_ALPHA = 0x0002; // read only */ 348 /// Expand 1; 2 and 4-bit samples to bytes 349 const PACKING = 0x0004; // read and write */ 350 /// Change order of packed pixels to LSB first 351 const PACKSWAP = 0x0008; // read and write */ 352 /// Expand paletted images to RGB; expand grayscale images of 353 /// less than 8-bit depth to 8-bit depth; and expand tRNS chunks 354 /// to alpha channels. 355 const EXPAND = 0x0010; // read only */ 356 /// Invert monochrome images 357 const INVERT_MONO = 0x0020; // read and write */ 358 /// Normalize pixels to the sBIT depth 359 const SHIFT = 0x0040; // read and write */ 360 /// Flip RGB to BGR; RGBA to BGRA 361 const BGR = 0x0080; // read and write */ 362 /// Flip RGBA to ARGB or GA to AG 363 const SWAP_ALPHA = 0x0100; // read and write */ 364 /// Byte-swap 16-bit samples 365 const SWAP_ENDIAN = 0x0200; // read and write */ 366 /// Change alpha from opacity to transparency 367 const INVERT_ALPHA = 0x0400; // read and write */ 368 const STRIP_FILLER = 0x0800; // write only */ 369 const STRIP_FILLER_BEFORE = 0x0800; // write only 370 const STRIP_FILLER_AFTER = 0x1000; // write only */ 371 const GRAY_TO_RGB = 0x2000; // read only */ 372 const EXPAND_16 = 0x4000; // read only */ 373 const SCALE_16 = 0x8000; // read only */ 374 } 375 } 376 377 /// Mod to encapsulate the converters depending on the `deflate` crate. 378 /// 379 /// Since this only contains trait impls, there is no need to make this public, they are simply 380 /// available when the mod is compiled as well. 381 #[cfg(feature = "png-encoding")] 382 mod deflate_convert { 383 extern crate deflate; 384 use super::Compression; 385 386 impl From<deflate::Compression> for Compression { from(c: deflate::Compression) -> Self387 fn from(c: deflate::Compression) -> Self { 388 match c { 389 deflate::Compression::Default => Compression::Default, 390 deflate::Compression::Fast => Compression::Fast, 391 deflate::Compression::Best => Compression::Best, 392 } 393 } 394 } 395 396 impl From<Compression> for deflate::CompressionOptions { from(c: Compression) -> Self397 fn from(c: Compression) -> Self { 398 match c { 399 Compression::Default => deflate::CompressionOptions::default(), 400 Compression::Fast => deflate::CompressionOptions::fast(), 401 Compression::Best => deflate::CompressionOptions::high(), 402 Compression::Huffman => deflate::CompressionOptions::huffman_only(), 403 Compression::Rle => deflate::CompressionOptions::rle(), 404 } 405 } 406 } 407 } 408