image/codecs/pnm/
mod.rs

1//! Decoding of netpbm image formats (pbm, pgm, ppm and pam).
2//!
3//! The formats pbm, pgm and ppm are fully supported. The pam decoder recognizes the tuple types
4//! `BLACKANDWHITE`, `GRAYSCALE` and `RGB` and explicitly recognizes but rejects their `_ALPHA`
5//! variants for now as alpha color types are unsupported.
6use self::autobreak::AutoBreak;
7pub use self::decoder::PnmDecoder;
8pub use self::encoder::PnmEncoder;
9use self::header::HeaderRecord;
10pub use self::header::{
11    ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader, PixmapHeader,
12};
13pub use self::header::{PnmHeader, PnmSubtype, SampleEncoding};
14
15mod autobreak;
16mod decoder;
17mod encoder;
18mod header;
19
20#[cfg(test)]
21mod tests {
22    use super::*;
23    use crate::color::ColorType;
24    use crate::image::ImageDecoder;
25    use byteorder::{ByteOrder, NativeEndian};
26
27    fn execute_roundtrip_default(buffer: &[u8], width: u32, height: u32, color: ColorType) {
28        let mut encoded_buffer = Vec::new();
29
30        {
31            let mut encoder = PnmEncoder::new(&mut encoded_buffer);
32            encoder
33                .encode(buffer, width, height, color)
34                .expect("Failed to encode the image buffer");
35        }
36
37        let (header, loaded_color, loaded_image) = {
38            let decoder = PnmDecoder::new(&encoded_buffer[..]).unwrap();
39            let color_type = decoder.color_type();
40            let mut image = vec![0; decoder.total_bytes() as usize];
41            decoder
42                .read_image(&mut image)
43                .expect("Failed to decode the image");
44            let (_, header) = PnmDecoder::new(&encoded_buffer[..]).unwrap().into_inner();
45            (header, color_type, image)
46        };
47
48        assert_eq!(header.width(), width);
49        assert_eq!(header.height(), height);
50        assert_eq!(loaded_color, color);
51        assert_eq!(loaded_image.as_slice(), buffer);
52    }
53
54    fn execute_roundtrip_with_subtype(
55        buffer: &[u8],
56        width: u32,
57        height: u32,
58        color: ColorType,
59        subtype: PnmSubtype,
60    ) {
61        let mut encoded_buffer = Vec::new();
62
63        {
64            let mut encoder = PnmEncoder::new(&mut encoded_buffer).with_subtype(subtype);
65            encoder
66                .encode(buffer, width, height, color)
67                .expect("Failed to encode the image buffer");
68        }
69
70        let (header, loaded_color, loaded_image) = {
71            let decoder = PnmDecoder::new(&encoded_buffer[..]).unwrap();
72            let color_type = decoder.color_type();
73            let mut image = vec![0; decoder.total_bytes() as usize];
74            decoder
75                .read_image(&mut image)
76                .expect("Failed to decode the image");
77            let (_, header) = PnmDecoder::new(&encoded_buffer[..]).unwrap().into_inner();
78            (header, color_type, image)
79        };
80
81        assert_eq!(header.width(), width);
82        assert_eq!(header.height(), height);
83        assert_eq!(header.subtype(), subtype);
84        assert_eq!(loaded_color, color);
85        assert_eq!(loaded_image.as_slice(), buffer);
86    }
87
88    fn execute_roundtrip_u16(buffer: &[u16], width: u32, height: u32, color: ColorType) {
89        let mut encoded_buffer = Vec::new();
90
91        {
92            let mut encoder = PnmEncoder::new(&mut encoded_buffer);
93            encoder
94                .encode(buffer, width, height, color)
95                .expect("Failed to encode the image buffer");
96        }
97
98        let (header, loaded_color, loaded_image) = {
99            let decoder = PnmDecoder::new(&encoded_buffer[..]).unwrap();
100            let color_type = decoder.color_type();
101            let mut image = vec![0; decoder.total_bytes() as usize];
102            decoder
103                .read_image(&mut image)
104                .expect("Failed to decode the image");
105            let (_, header) = PnmDecoder::new(&encoded_buffer[..]).unwrap().into_inner();
106            (header, color_type, image)
107        };
108
109        let mut buffer_u8 = vec![0; buffer.len() * 2];
110        NativeEndian::write_u16_into(buffer, &mut buffer_u8[..]);
111
112        assert_eq!(header.width(), width);
113        assert_eq!(header.height(), height);
114        assert_eq!(loaded_color, color);
115        assert_eq!(loaded_image, buffer_u8);
116    }
117
118    #[test]
119    fn roundtrip_gray() {
120        #[rustfmt::skip]
121        let buf: [u8; 16] = [
122            0, 0, 0, 255,
123            255, 255, 255, 255,
124            255, 0, 255, 0,
125            255, 0, 0, 0,
126        ];
127
128        execute_roundtrip_default(&buf, 4, 4, ColorType::L8);
129        execute_roundtrip_with_subtype(&buf, 4, 4, ColorType::L8, PnmSubtype::ArbitraryMap);
130        execute_roundtrip_with_subtype(
131            &buf,
132            4,
133            4,
134            ColorType::L8,
135            PnmSubtype::Graymap(SampleEncoding::Ascii),
136        );
137        execute_roundtrip_with_subtype(
138            &buf,
139            4,
140            4,
141            ColorType::L8,
142            PnmSubtype::Graymap(SampleEncoding::Binary),
143        );
144    }
145
146    #[test]
147    fn roundtrip_rgb() {
148        #[rustfmt::skip]
149        let buf: [u8; 27] = [
150              0,   0,   0,
151              0,   0, 255,
152              0, 255,   0,
153              0, 255, 255,
154            255,   0,   0,
155            255,   0, 255,
156            255, 255,   0,
157            255, 255, 255,
158            255, 255, 255,
159        ];
160        execute_roundtrip_default(&buf, 3, 3, ColorType::Rgb8);
161        execute_roundtrip_with_subtype(&buf, 3, 3, ColorType::Rgb8, PnmSubtype::ArbitraryMap);
162        execute_roundtrip_with_subtype(
163            &buf,
164            3,
165            3,
166            ColorType::Rgb8,
167            PnmSubtype::Pixmap(SampleEncoding::Binary),
168        );
169        execute_roundtrip_with_subtype(
170            &buf,
171            3,
172            3,
173            ColorType::Rgb8,
174            PnmSubtype::Pixmap(SampleEncoding::Ascii),
175        );
176    }
177
178    #[test]
179    fn roundtrip_u16() {
180        let buf: [u16; 6] = [0, 1, 0xFFFF, 0x1234, 0x3412, 0xBEAF];
181
182        execute_roundtrip_u16(&buf, 6, 1, ColorType::L16);
183    }
184}