devela/media/image/
pnm.rs
1#![allow(unused, reason = "WIP")]
6
7#[cfg(feature = "alloc")]
8use crate::text::String;
9#[cfg(doc)]
10use crate::ImageError::FmtError;
11use crate::{
12 FmtWrite, ImageError,
13 ImageError::{InvalidImageSize, InvalidPixel},
14 ImageResult as Result, Mem,
15};
16
17#[cold] #[rustfmt::skip]
19const fn invalid_pixel<T>() -> crate::Result<T, ImageError> { Err(InvalidPixel) }
20
21#[doc = crate::TAG_NAMESPACE!()]
22pub struct Pnm;
43
44impl Pnm {
45 #[cfg(feature = "alloc")]
54 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
55 pub fn p1_encode_bytes(bitmap: &[u8], width: usize, height: usize) -> Result<String> {
56 if bitmap.len() != width * height {
57 return Err(InvalidImageSize(Some((width, height))));
58 }
59 let mut result = String::new();
60 writeln!(result, "P1\n{} {}", width, height)?;
61
62 for row in 0..height {
64 let first_pixel = bitmap[row * width];
65 result.push(match first_pixel {
66 0 => '0',
67 1 => '1',
68 _ => return invalid_pixel(),
69 });
70
71 for col in 1..width {
72 let pixel = bitmap[row * width + col];
73 result.push(' '); match pixel {
75 0 => result.push('0'),
76 1 => result.push('1'),
77 _ => return invalid_pixel(),
78 }
79 }
80 result.push('\n'); }
82 Ok(result)
83 }
84
85 #[cfg(feature = "alloc")]
95 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
96 pub fn p1_encode_bits(bitmap: &[u8], width: usize, height: usize) -> Result<String> {
97 if bitmap.len() != Mem::bytes_from_bits(width * height) {
98 return Err(InvalidImageSize(Some((width, height))));
99 }
100 let mut result = String::new();
101 writeln!(result, "P1\n{} {}", width, height)?;
102
103 for row in 0..height {
105 let first_col = 0;
106 let byte_index = (row * width + first_col) / 8;
107 let bit = 1 << (7 - (first_col % 8));
108 let first_pixel = (bitmap[byte_index] & bit) != 0;
109 result.push(if first_pixel { '1' } else { '0' });
110
111 for col in 1..width {
112 let byte_index = (row * width + col) / 8;
113 let bit = 1 << (7 - (col % 8));
114 let pixel = (bitmap[byte_index] & bit) != 0;
115 result.push(' '); result.push(if pixel { '1' } else { '0' });
117 }
118 result.push('\n'); }
120 Ok(result)
121 }
122}
123
124#[cfg(all(test, feature = "alloc"))]
125mod tests_alloc {
126 use super::*;
127 use crate::_dep::_alloc::vec;
128
129 #[test]
130 fn p1_encode_bytes() {
131 let bitmap = vec![
132 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, ];
135 let (w, h) = (8, 2);
136 let expected_output = "P1\n8 2\n1 0 1 0 1 0 1 0\n0 1 0 1 0 1 0 1\n";
137 let result = Pnm::p1_encode_bytes(&bitmap, w, h).expect("PNM P1 encoded");
138 assert_eq!(result, expected_output);
139 }
140 #[test]
141 fn p1_encode_bytes_invalid_size() {
142 let bitmap = vec![1, 0, 1, 0]; let (w, h) = (3, 3);
144 let result = Pnm::p1_encode_bytes(&bitmap, w, h);
145 assert_eq!(result, Err(InvalidImageSize(Some((3, 3)))));
146 }
147 #[test]
148 fn p1_encode_bytes_invalid_pixel() {
149 let bitmap = vec![1, 0, 2, 0]; let (w, h) = (2, 2);
151 let result = Pnm::p1_encode_bytes(&bitmap, w, h);
152 assert_eq!(result, Err(InvalidPixel));
153 }
154
155 #[test]
156 fn p1_encode_bits() {
157 let bitmap = vec![0b10101010, 0b01010101]; let (w, h) = (8, 2);
159 let expected_output = "P1\n8 2\n1 0 1 0 1 0 1 0\n0 1 0 1 0 1 0 1\n";
160 let result = Pnm::p1_encode_bits(&bitmap, w, h).expect("PNM P1 encoded");
161 assert_eq!(result, expected_output);
162 }
163 #[test]
164 fn p1_encode_bits_invalid_size() {
165 let bitmap = vec![0b10101010]; let (w, h) = (8, 2);
167 let result = Pnm::p1_encode_bits(&bitmap, w, h);
168 assert_eq!(result, Err(InvalidImageSize(Some((8, 2)))));
169 }
170}