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}
185