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