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
#![deprecated(since="0.17.0", note="Use `pnm::PNMDecoder` instead, check the subtype if necessary")]
use std::io::Read;
use color::{ColorType};
use image::{DecodingResult, ImageDecoder, ImageResult, ImageError};
use pnm::{PNMDecoder, PNMSubtype};
pub struct PPMDecoder<R>(PNMDecoder<R>);
impl<R: Read> PPMDecoder<R> {
pub fn new(read: R) -> ImageResult<PPMDecoder<R>> {
let pnm = PNMDecoder::new(read)?;
match pnm.subtype() {
PNMSubtype::Pixmap(_) => {},
_ => return Err(ImageError::FormatError("Expected pixmap magic constant (P3 or P6)".to_string())),
}
Ok(PPMDecoder(pnm))
}
}
impl<R: Read> ImageDecoder for PPMDecoder<R> {
fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
self.0.dimensions()
}
fn colortype(&mut self) -> ImageResult<ColorType> {
self.0.colortype()
}
fn row_len(&mut self) -> ImageResult<usize> {
self.0.row_len()
}
fn read_scanline(&mut self, mut buf: &mut [u8]) -> ImageResult<u32> {
self.0.read_scanline(&mut buf)
}
fn read_image(&mut self) -> ImageResult<DecodingResult> {
self.0.read_image()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn minimal_form() {
decode_minimal_image(&b"P61 1 255 123"[..]);
decode_minimal_image(&b"P6 1 1 255 123"[..]);
decode_minimal_image(&b"P6 1 1 255 123\xFF"[..]);
}
#[test]
fn comment_in_token() {
decode_minimal_image(&b"P6 1 1 2#comment\n55 123"[..]);
decode_minimal_image(&b"P6 1 1 2#comment\r55 123"[..]);
decode_minimal_image(&b"P6 1 1#comment\n 255 123"[..]);
decode_minimal_image(&b"P6 1 1 #comment\n255 123"[..]);
decode_minimal_image(&b"P6#comment\n 1 1 255 123"[..]);
decode_minimal_image(&b"P6 1 1 255#comment\n 123"[..]);
}
#[test]
fn whitespace() {
decode_minimal_image(&b"P6\x091\x091\x09255\x09123"[..]);
decode_minimal_image(&b"P6\x0a1\x0a1\x0a255\x0a123"[..]);
decode_minimal_image(&b"P6\x0b1\x0b1\x0b255\x0b123"[..]);
decode_minimal_image(&b"P6\x0c1\x0c1\x0c255\x0c123"[..]);
decode_minimal_image(&b"P6\x0d1\x0d1\x0d255\x0d123"[..]);
decode_minimal_image(&b"P61\x09\x0a\x0b\x0c\x0d1 255 123"[..]);
}
#[test]
fn ascii_encoded() {
decode_minimal_image(&b"P31 1 255 49 50 51"[..]);
assert!(PPMDecoder::new(&b"P31 1 65535 65535 65535 65535"[..]).unwrap()
.read_image().is_ok());
decode_minimal_image(&b"P31 1 255 49 50 51"[..]);
decode_minimal_image(&b"P31 1 255 49\n\t 50\r\x0b\x0c51"[..]);
}
fn decode_minimal_image(encoded: &[u8]) {
let content = vec![49 as u8, 50, 51];
let mut decoder = PPMDecoder::new(encoded).unwrap();
assert_eq!(decoder.dimensions().unwrap(), (1, 1));
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
assert_eq!(decoder.row_len().unwrap(), 3);
match decoder.read_image().unwrap() {
DecodingResult::U8(image) => assert_eq!(image, content),
_ => assert!(false),
}
}
#[test]
fn wrong_tag() {
assert!(PPMDecoder::new(&b"P5 1 1 255 1"[..]).is_err());
}
#[test]
fn invalid_characters() {
assert!(PPMDecoder::new(&b"P6 1chars1 255 1"[..]).is_err());
assert!(PPMDecoder::new(&b"P6 1\xFF1 255 1"[..]).is_err());
assert!(PPMDecoder::new(&b"P6 0x01 1 255 1"[..]).is_err());
}
#[test]
fn unsupported_extensions() {
assert!(PPMDecoder::new(&b"P6 1 1 65536 1"[..]).is_err());
}
}