1 use std::{fmt, io}; 2 3 /// The kind of encoding used to store sample values 4 #[derive(Clone, Copy, PartialEq, Eq, Debug)] 5 pub enum SampleEncoding { 6 /// Samples are unsigned binary integers in big endian 7 Binary, 8 9 /// Samples are encoded as decimal ascii strings separated by whitespace 10 Ascii, 11 } 12 13 /// Denotes the category of the magic number 14 /// 15 /// DEPRECATED: The name of this enum will be changed to [`PnmSubtype`]. 16 /// 17 /// TODO: rename to [`PnmSubtype`]. 18 /// 19 /// [`PnmSubtype`]: type.PnmSubtype.html 20 #[derive(Clone, Copy, PartialEq, Eq, Debug)] 21 pub enum PNMSubtype { 22 /// Magic numbers P1 and P4 23 Bitmap(SampleEncoding), 24 25 /// Magic numbers P2 and P5 26 Graymap(SampleEncoding), 27 28 /// Magic numbers P3 and P6 29 Pixmap(SampleEncoding), 30 31 /// Magic number P7 32 ArbitraryMap, 33 } 34 35 /// PNM Subtype 36 /// 37 /// An alias of [`PNMSubtype`]. 38 /// 39 /// TODO: remove when [`DXTVariant`] is renamed. 40 /// 41 /// [`PNMSubtype`]: enum.PNMSubtype.html 42 #[allow(dead_code)] 43 pub type PnmSubtype = PNMSubtype; 44 45 /// Stores the complete header data of a file. 46 /// 47 /// Internally, provides mechanisms for lossless reencoding. After reading a file with the decoder 48 /// it is possible to recover the header and construct an encoder. Using the encoder on the just 49 /// loaded image should result in a byte copy of the original file (for single image pnms without 50 /// additional trailing data). 51 pub struct PnmHeader { 52 pub(crate) decoded: HeaderRecord, 53 pub(crate) encoded: Option<Vec<u8>>, 54 } 55 56 /// PNM Header 57 /// 58 /// An alias of [`PnmHeader`]. 59 /// 60 /// TODO: remove 61 /// 62 /// [`PnmHeader`]: struct.PnmHeader.html 63 #[allow(dead_code)] 64 #[deprecated(note = "Use `PnmHeader` instead")] 65 pub type PNMHeader = PnmHeader; 66 67 pub(crate) enum HeaderRecord { 68 Bitmap(BitmapHeader), 69 Graymap(GraymapHeader), 70 Pixmap(PixmapHeader), 71 Arbitrary(ArbitraryHeader), 72 } 73 74 /// Header produced by a `pbm` file ("Portable Bit Map") 75 #[derive(Clone, Copy, Debug)] 76 pub struct BitmapHeader { 77 /// Binary or Ascii encoded file 78 pub encoding: SampleEncoding, 79 80 /// Height of the image file 81 pub height: u32, 82 83 /// Width of the image file 84 pub width: u32, 85 } 86 87 /// Header produced by a `pgm` file ("Portable Gray Map") 88 #[derive(Clone, Copy, Debug)] 89 pub struct GraymapHeader { 90 /// Binary or Ascii encoded file 91 pub encoding: SampleEncoding, 92 93 /// Height of the image file 94 pub height: u32, 95 96 /// Width of the image file 97 pub width: u32, 98 99 /// Maximum sample value within the image 100 pub maxwhite: u32, 101 } 102 103 /// Header produced by a `ppm` file ("Portable Pixel Map") 104 #[derive(Clone, Copy, Debug)] 105 pub struct PixmapHeader { 106 /// Binary or Ascii encoded file 107 pub encoding: SampleEncoding, 108 109 /// Height of the image file 110 pub height: u32, 111 112 /// Width of the image file 113 pub width: u32, 114 115 /// Maximum sample value within the image 116 pub maxval: u32, 117 } 118 119 /// Header produced by a `pam` file ("Portable Arbitrary Map") 120 #[derive(Clone, Debug)] 121 pub struct ArbitraryHeader { 122 /// Height of the image file 123 pub height: u32, 124 125 /// Width of the image file 126 pub width: u32, 127 128 /// Number of color channels 129 pub depth: u32, 130 131 /// Maximum sample value within the image 132 pub maxval: u32, 133 134 /// Color interpretation of image pixels 135 pub tupltype: Option<ArbitraryTuplType>, 136 } 137 138 /// Standardized tuple type specifiers in the header of a `pam`. 139 #[derive(Clone, Debug)] 140 pub enum ArbitraryTuplType { 141 /// Pixels are either black (0) or white (1) 142 BlackAndWhite, 143 144 /// Pixels are either black (0) or white (1) and a second alpha channel 145 BlackAndWhiteAlpha, 146 147 /// Pixels represent the amount of white 148 Grayscale, 149 150 /// Grayscale with an additional alpha channel 151 GrayscaleAlpha, 152 153 /// Three channels: Red, Green, Blue 154 RGB, 155 156 /// Four channels: Red, Green, Blue, Alpha 157 RGBAlpha, 158 159 /// An image format which is not standardized 160 Custom(String), 161 } 162 163 impl ArbitraryTuplType { name(&self) -> &str164 pub(crate) fn name(&self) -> &str { 165 match self { 166 ArbitraryTuplType::BlackAndWhite => "BLACKANDWHITE", 167 ArbitraryTuplType::BlackAndWhiteAlpha => "BLACKANDWHITE_ALPHA", 168 ArbitraryTuplType::Grayscale => "GRAYSCALE", 169 ArbitraryTuplType::GrayscaleAlpha => "GRAYSCALE_ALPHA", 170 ArbitraryTuplType::RGB => "RGB", 171 ArbitraryTuplType::RGBAlpha => "RGB_ALPHA", 172 ArbitraryTuplType::Custom(custom) => custom, 173 } 174 } 175 } 176 177 impl PNMSubtype { 178 /// Get the two magic constant bytes corresponding to this format subtype. magic_constant(self) -> &'static [u8; 2]179 pub fn magic_constant(self) -> &'static [u8; 2] { 180 match self { 181 PNMSubtype::Bitmap(SampleEncoding::Ascii) => b"P1", 182 PNMSubtype::Graymap(SampleEncoding::Ascii) => b"P2", 183 PNMSubtype::Pixmap(SampleEncoding::Ascii) => b"P3", 184 PNMSubtype::Bitmap(SampleEncoding::Binary) => b"P4", 185 PNMSubtype::Graymap(SampleEncoding::Binary) => b"P5", 186 PNMSubtype::Pixmap(SampleEncoding::Binary) => b"P6", 187 PNMSubtype::ArbitraryMap => b"P7", 188 } 189 } 190 191 /// Whether samples are stored as binary or as decimal ascii sample_encoding(self) -> SampleEncoding192 pub fn sample_encoding(self) -> SampleEncoding { 193 match self { 194 PNMSubtype::ArbitraryMap => SampleEncoding::Binary, 195 PNMSubtype::Bitmap(enc) => enc, 196 PNMSubtype::Graymap(enc) => enc, 197 PNMSubtype::Pixmap(enc) => enc, 198 } 199 } 200 } 201 202 impl PnmHeader { 203 /// Retrieve the format subtype from which the header was created. subtype(&self) -> PNMSubtype204 pub fn subtype(&self) -> PNMSubtype { 205 match self.decoded { 206 HeaderRecord::Bitmap(BitmapHeader { encoding, .. }) => PNMSubtype::Bitmap(encoding), 207 HeaderRecord::Graymap(GraymapHeader { encoding, .. }) => PNMSubtype::Graymap(encoding), 208 HeaderRecord::Pixmap(PixmapHeader { encoding, .. }) => PNMSubtype::Pixmap(encoding), 209 HeaderRecord::Arbitrary(ArbitraryHeader { .. }) => PNMSubtype::ArbitraryMap, 210 } 211 } 212 213 /// The width of the image this header is for. width(&self) -> u32214 pub fn width(&self) -> u32 { 215 match self.decoded { 216 HeaderRecord::Bitmap(BitmapHeader { width, .. }) => width, 217 HeaderRecord::Graymap(GraymapHeader { width, .. }) => width, 218 HeaderRecord::Pixmap(PixmapHeader { width, .. }) => width, 219 HeaderRecord::Arbitrary(ArbitraryHeader { width, .. }) => width, 220 } 221 } 222 223 /// The height of the image this header is for. height(&self) -> u32224 pub fn height(&self) -> u32 { 225 match self.decoded { 226 HeaderRecord::Bitmap(BitmapHeader { height, .. }) => height, 227 HeaderRecord::Graymap(GraymapHeader { height, .. }) => height, 228 HeaderRecord::Pixmap(PixmapHeader { height, .. }) => height, 229 HeaderRecord::Arbitrary(ArbitraryHeader { height, .. }) => height, 230 } 231 } 232 233 /// The biggest value a sample can have. In other words, the colour resolution. maximal_sample(&self) -> u32234 pub fn maximal_sample(&self) -> u32 { 235 match self.decoded { 236 HeaderRecord::Bitmap(BitmapHeader { .. }) => 1, 237 HeaderRecord::Graymap(GraymapHeader { maxwhite, .. }) => maxwhite, 238 HeaderRecord::Pixmap(PixmapHeader { maxval, .. }) => maxval, 239 HeaderRecord::Arbitrary(ArbitraryHeader { maxval, .. }) => maxval, 240 } 241 } 242 243 /// Retrieve the underlying bitmap header if any as_bitmap(&self) -> Option<&BitmapHeader>244 pub fn as_bitmap(&self) -> Option<&BitmapHeader> { 245 match self.decoded { 246 HeaderRecord::Bitmap(ref bitmap) => Some(bitmap), 247 _ => None, 248 } 249 } 250 251 /// Retrieve the underlying graymap header if any as_graymap(&self) -> Option<&GraymapHeader>252 pub fn as_graymap(&self) -> Option<&GraymapHeader> { 253 match self.decoded { 254 HeaderRecord::Graymap(ref graymap) => Some(graymap), 255 _ => None, 256 } 257 } 258 259 /// Retrieve the underlying pixmap header if any as_pixmap(&self) -> Option<&PixmapHeader>260 pub fn as_pixmap(&self) -> Option<&PixmapHeader> { 261 match self.decoded { 262 HeaderRecord::Pixmap(ref pixmap) => Some(pixmap), 263 _ => None, 264 } 265 } 266 267 /// Retrieve the underlying arbitrary header if any as_arbitrary(&self) -> Option<&ArbitraryHeader>268 pub fn as_arbitrary(&self) -> Option<&ArbitraryHeader> { 269 match self.decoded { 270 HeaderRecord::Arbitrary(ref arbitrary) => Some(arbitrary), 271 _ => None, 272 } 273 } 274 275 /// Write the header back into a binary stream write(&self, writer: &mut dyn io::Write) -> io::Result<()>276 pub fn write(&self, writer: &mut dyn io::Write) -> io::Result<()> { 277 writer.write_all(self.subtype().magic_constant())?; 278 match *self { 279 PnmHeader { 280 encoded: Some(ref content), 281 .. 282 } => writer.write_all(content), 283 PnmHeader { 284 decoded: 285 HeaderRecord::Bitmap(BitmapHeader { 286 encoding: _encoding, 287 width, 288 height, 289 }), 290 .. 291 } => writeln!(writer, "\n{} {}", width, height), 292 PnmHeader { 293 decoded: 294 HeaderRecord::Graymap(GraymapHeader { 295 encoding: _encoding, 296 width, 297 height, 298 maxwhite, 299 }), 300 .. 301 } => writeln!(writer, "\n{} {} {}", width, height, maxwhite), 302 PnmHeader { 303 decoded: 304 HeaderRecord::Pixmap(PixmapHeader { 305 encoding: _encoding, 306 width, 307 height, 308 maxval, 309 }), 310 .. 311 } => writeln!(writer, "\n{} {} {}", width, height, maxval), 312 PnmHeader { 313 decoded: 314 HeaderRecord::Arbitrary(ArbitraryHeader { 315 width, 316 height, 317 depth, 318 maxval, 319 ref tupltype, 320 }), 321 .. 322 } => { 323 struct TupltypeWriter<'a>(&'a Option<ArbitraryTuplType>); 324 impl<'a> fmt::Display for TupltypeWriter<'a> { 325 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 326 match self.0 { 327 Some(tt) => writeln!(f, "TUPLTYPE {}", tt.name()), 328 None => Ok(()), 329 } 330 } 331 } 332 333 writeln!( 334 writer, 335 "\nWIDTH {}\nHEIGHT {}\nDEPTH {}\nMAXVAL {}\n{}ENDHDR", 336 width, height, depth, maxval, TupltypeWriter(tupltype) 337 ) 338 } 339 } 340 } 341 } 342 343 impl From<BitmapHeader> for PnmHeader { from(header: BitmapHeader) -> Self344 fn from(header: BitmapHeader) -> Self { 345 PnmHeader { 346 decoded: HeaderRecord::Bitmap(header), 347 encoded: None, 348 } 349 } 350 } 351 352 impl From<GraymapHeader> for PnmHeader { from(header: GraymapHeader) -> Self353 fn from(header: GraymapHeader) -> Self { 354 PnmHeader { 355 decoded: HeaderRecord::Graymap(header), 356 encoded: None, 357 } 358 } 359 } 360 361 impl From<PixmapHeader> for PnmHeader { from(header: PixmapHeader) -> Self362 fn from(header: PixmapHeader) -> Self { 363 PnmHeader { 364 decoded: HeaderRecord::Pixmap(header), 365 encoded: None, 366 } 367 } 368 } 369 370 impl From<ArbitraryHeader> for PnmHeader { from(header: ArbitraryHeader) -> Self371 fn from(header: ArbitraryHeader) -> Self { 372 PnmHeader { 373 decoded: HeaderRecord::Arbitrary(header), 374 encoded: None, 375 } 376 } 377 } 378