1use std::fmt::{self, Display};
10use std::io::{BufRead, Seek, Write};
11
12use image::error::{DecodingError, EncodingError, ImageFormatHint, LimitError, LimitErrorKind};
13use image::{ColorType, ExtendedColorType, ImageDecoder, ImageEncoder, ImageError, ImageResult};
14
15#[derive(Debug, Clone)]
17enum EncoderError {
18 ImageTooLarge,
20
21 UnsupportedColorType,
23}
24
25impl Display for EncoderError {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 match self {
28 EncoderError::ImageTooLarge => f.write_fmt(format_args!(
29 "Specified image is too large for the OTB format (Max 255x255)"
30 )),
31 EncoderError::UnsupportedColorType => f.write_fmt(format_args!(
32 "Color type of specified image is not supported"
33 )),
34 }
35 }
36}
37impl std::error::Error for EncoderError {}
38
39impl From<EncoderError> for ImageError {
40 fn from(e: EncoderError) -> ImageError {
41 match e {
42 EncoderError::ImageTooLarge => {
43 ImageError::Limits(LimitError::from_kind(LimitErrorKind::DimensionError))
44 }
45 _ => ImageError::Encoding(EncodingError::new(ImageFormatHint::Name("otb".into()), e)),
46 }
47 }
48}
49
50pub struct OtbEncoder<W> {
52 writer: W,
53 threshold: u8,
54}
55
56impl<W: Write> OtbEncoder<W> {
57 pub fn new(writer: W) -> Self {
58 Self {
59 writer,
60 threshold: 127_u8,
61 }
62 }
63
64 pub fn with_threshold(mut self, threshold: u8) -> Self {
65 self.threshold = threshold;
66 self
67 }
68}
69
70impl<W: Write> ImageEncoder for OtbEncoder<W> {
71 fn write_image(
72 mut self,
73 buf: &[u8],
74 width: u32,
75 height: u32,
76 color_type: ExtendedColorType,
77 ) -> std::result::Result<(), ImageError> {
78 if width > 0xFF || height > 0xFF {
79 return Err(EncoderError::ImageTooLarge.into());
80 }
81 if color_type != ExtendedColorType::L8 {
82 return Err(EncoderError::UnsupportedColorType.into());
83 }
84
85 let _ = self
87 .writer
88 .write(&[0x00, width as u8, height as u8, 0x01])?;
89
90 let mut current_byte = 0_u8;
92 let mut bit = 0;
93 for buf_idx in 0..(width * height) {
94 if buf[buf_idx as usize] < self.threshold {
95 current_byte |= 1 << (7 - bit);
96 }
97 bit += 1;
98 if bit == 8 {
99 self.writer.write_all(&[current_byte])?;
100 current_byte = 0_u8;
101 bit = 0;
102 };
103 }
104 if bit != 0 {
105 self.writer.write_all(&[current_byte])?;
106 }
107
108 Ok(())
109 }
110}
111
112#[derive(Debug, Clone)]
114enum DecoderError {
115 UnsupportedInfoField(u8),
117 WidthZero,
119 HeightZero,
121 UnsupportedColorDepth(u8),
123}
124
125impl Display for DecoderError {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match self {
128 Self::UnsupportedInfoField(info) => {
129 f.write_fmt(format_args!("Unsupported value in info field {info:08b}"))
130 }
131 Self::WidthZero => f.write_fmt(format_args!("Width cannot be zero")),
132 Self::HeightZero => f.write_fmt(format_args!("Height cannot be zero")),
133 Self::UnsupportedColorDepth(depth) => f.write_fmt(format_args!(
134 "Unsupported color depth value in headers {depth}"
135 )),
136 }
137 }
138}
139impl std::error::Error for DecoderError {}
140
141impl From<DecoderError> for ImageError {
142 fn from(e: DecoderError) -> ImageError {
143 ImageError::Decoding(DecodingError::new(ImageFormatHint::Name("otb".into()), e))
144 }
145}
146
147pub struct OtbDecoder<R> {
149 reader: R,
150 dimensions: (u32, u32),
151}
152
153impl<R> OtbDecoder<R>
154where
155 R: BufRead + Seek,
156{
157 pub fn new(reader: R) -> Result<OtbDecoder<R>, ImageError> {
159 let mut decoder = Self::new_decoder(reader);
160 decoder.read_metadata()?;
161 Ok(decoder)
162 }
163
164 fn new_decoder(reader: R) -> OtbDecoder<R> {
165 Self {
166 reader,
167 dimensions: (0, 0),
168 }
169 }
170
171 fn read_metadata(&mut self) -> Result<(), ImageError> {
172 let mut buf = [0_u8; 1];
173
174 self.reader.read_exact(&mut buf)?;
175 let info_field = buf[0];
176
177 if info_field != 0x0 && info_field != 0x10 {
181 return Err(DecoderError::UnsupportedInfoField(info_field).into());
182 }
183
184 self.reader.read_exact(&mut buf)?;
186 let mut width = buf[0] as u16;
187 if info_field == 0x10 {
188 self.reader.read_exact(&mut buf)?;
189 width = width << 8 | buf[0] as u16;
190 }
191 if width == 0 {
192 return Err(DecoderError::WidthZero.into());
193 }
194
195 self.reader.read_exact(&mut buf)?;
197 let mut height = buf[0] as u16;
198 if info_field == 0x10 {
199 self.reader.read_exact(&mut buf)?;
200 height = height << 8 | buf[0] as u16;
201 }
202 if height == 0 {
203 return Err(DecoderError::HeightZero.into());
204 }
205
206 self.reader.read_exact(&mut buf)?;
208 let depth = buf[0];
209 if depth != 1 {
210 return Err(DecoderError::UnsupportedColorDepth(depth).into());
211 }
212
213 self.dimensions = (width as u32, height as u32);
214
215 Ok(())
216 }
217}
218
219impl<R: BufRead + Seek> ImageDecoder for OtbDecoder<R> {
220 fn dimensions(&self) -> (u32, u32) {
221 self.dimensions
222 }
223
224 fn color_type(&self) -> ColorType {
225 ColorType::L8
226 }
227
228 fn original_color_type(&self) -> ExtendedColorType {
229 ExtendedColorType::L1
230 }
231
232 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
233 let (width, height) = (self.dimensions.0 as usize, self.dimensions.1 as usize);
234
235 assert_eq!(buf.len(), width * height, "Invalid buffer length");
236
237 let mut byte_buf = vec![0_u8; (width * height).div_ceil(8)].into_boxed_slice();
239 self.reader.read_exact(&mut byte_buf)?;
240
241 for (i, &byte) in byte_buf.iter().enumerate() {
243 for bit in 0..8 {
244 let buf_idx = 8 * i + bit;
245 if buf_idx >= buf.len() {
246 break;
247 }
248
249 buf[buf_idx] = if (byte >> (7 - bit)) & 1 == 0 {
250 0xFF
251 } else {
252 0x00
253 };
254 }
255 }
256 Ok(())
257 }
258
259 fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
260 (*self).read_image(buf)
261 }
262}
263
264mod test {
265 #[test]
266 fn test_decode_image() {
267 use image::ImageDecoder;
268 use std::io::Cursor;
269 let otb_data = vec![
270 0x00, 0x48, 0x1C, 0x01, 0x7F, 0xFF, 0xEF, 0xFF, 0xEF, 0xFF, 0xFB, 0xFF, 0xFE, 0x40, 0x3F, 0xE8, 0x38, 0x2F,
274 0xFF, 0xFB, 0xFF, 0xFE, 0x48, 0x3F, 0xA8, 0x38, 0x2F, 0x9F, 0xFB, 0xFF, 0xFE, 0x4C,
275 0xFF, 0xA9, 0xFF, 0x2F, 0x8F, 0xFA, 0xDA, 0xDA, 0x4E, 0xFF, 0x29, 0x01, 0x2F, 0x80,
276 0xFA, 0x52, 0x52, 0x5E, 0x7F, 0x69, 0x31, 0x2F, 0xBF, 0x7B, 0x07, 0x06, 0x4F, 0xFF,
277 0x69, 0x79, 0x2F, 0xBE, 0xFB, 0x77, 0x76, 0x47, 0xFF, 0x69, 0x79, 0x2F, 0xBE, 0x7B,
278 0x07, 0x06, 0x47, 0xFE, 0xEF, 0x7D, 0xEF, 0xBE, 0x7B, 0xFF, 0xFE, 0x47, 0xFC, 0xEF,
279 0x7D, 0xE7, 0xBC, 0xF1, 0xFF, 0xFC, 0x40, 0xF0, 0xEF, 0x7D, 0xE7, 0x7C, 0xF1, 0xED,
280 0xBC, 0x21, 0xE7, 0xC9, 0x79, 0x27, 0x98, 0xF1, 0xE5, 0x3C, 0x21, 0xE7, 0xC9, 0x39,
281 0x27, 0xC8, 0xF1, 0xF0, 0x7C, 0x16, 0x6F, 0x89, 0x39, 0x23, 0xE6, 0xE0, 0xF7, 0x78,
282 0x15, 0x2F, 0x88, 0x82, 0x23, 0xF3, 0xE0, 0xF0, 0x78, 0x08, 0x3F, 0x04, 0x44, 0x43,
283 0xD7, 0xE0, 0xFF, 0xF8, 0x04, 0x3E, 0x02, 0x28, 0x81, 0xEF, 0xC0, 0x7F, 0xF0, 0x02,
284 0x3C, 0x01, 0x39, 0x00, 0xFF, 0x80, 0x3F, 0xE0, 0x01, 0x38, 0x00, 0xBA, 0x00, 0x7F,
285 0x00, 0x1F, 0xC0, 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0xFF, 0xC0,
286 0x00, 0x38, 0x00, 0x1C, 0x00, 0x07, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
287 0xFF, 0xAA, 0x2A, 0xF3, 0x87, 0x87, 0x3F, 0x1E, 0x67, 0x0F, 0x54, 0x15, 0xF3, 0x93,
288 0x9F, 0x3E, 0x4E, 0x27, 0x27, 0xA8, 0x2A, 0xF3, 0x87, 0x8F, 0x3E, 0x4E, 0x07, 0x27,
289 0x54, 0x55, 0xF3, 0x93, 0x9F, 0x3E, 0x0E, 0x47, 0x27, 0xAA, 0xFF, 0xF3, 0x9B, 0x87,
290 0x0E, 0x4E, 0x67, 0x0F, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
291 0x00, ];
293 let decoder = crate::otb::OtbDecoder::new(Cursor::new(otb_data)).unwrap();
294 let (width, height) = decoder.dimensions();
295 assert!(width == 0x48);
296 assert!(height == 0x1C);
297 let mut img_bytes = vec![0; 2016];
298 decoder.read_image(&mut img_bytes).unwrap();
299 }
300
301 #[test]
302 fn test_decoder_irregular_width() {
303 use image::ImageDecoder;
304 use std::io::Cursor;
305 let expected_data = [
306 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ];
317 #[allow(clippy::unusual_byte_groupings)]
318 let image_data: [u8; 17] = [
319 0,
320 10,
321 10,
322 1, 0b_00000000,
324 0b00_000011,
325 0b0000_0001,
326 0b001000_00,
327 0b10000100_,
328 0b_01000000,
329 0b10_010000,
330 0b0010_0010,
331 0b000100_00,
332 0b01001000_,
333 0b_00001100,
334 0b00_000000,
335 0b0000_0000,
336 ];
337 let decoder = crate::otb::OtbDecoder::new(Cursor::new(image_data)).unwrap();
338 let (width, height) = decoder.dimensions();
339 assert!(width == 10);
340 assert!(height == 10);
341 let mut img_bytes = vec![0; 100];
342 decoder.read_image(&mut img_bytes).unwrap();
343 img_bytes.iter().enumerate().for_each(|(i, byte)| {
344 assert_eq!(*byte, expected_data[i]);
345 });
346 }
347
348 #[test]
349 fn test_decoder() {
350 use image::ImageDecoder;
351 use std::io::Cursor;
352 let expected_data = [
353 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, ];
362 let image_data: [u8; 12] = [
363 0, 8, 8, 1, 0b00011000, 0b00100100, 0b01000010, 0b10000001, 0b10000001, 0b01000010, 0b00100100, 0b00011000, ];
373 let decoder = crate::otb::OtbDecoder::new(Cursor::new(image_data)).unwrap();
374 let (width, height) = decoder.dimensions();
375 assert!(width == 8);
376 assert!(height == 8);
377 let mut img_bytes = vec![0; 64];
378 decoder.read_image(&mut img_bytes).unwrap();
379 img_bytes.iter().enumerate().for_each(|(i, byte)| {
380 assert_eq!(*byte, expected_data[i]);
381 });
382 }
383
384 #[test]
385 fn test_encoder() {
386 use image::ImageEncoder;
387 let img_data = [
388 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, ];
397 let expected_data: [u8; 12] = [
398 0, 8, 8, 1, 0b00011000, 0b00100100, 0b01000010, 0b10000001, 0b10000001, 0b01000010, 0b00100100, 0b00011000, ];
408 let mut encoded_data = Vec::<u8>::with_capacity(expected_data.len());
409 let encoder = crate::otb::OtbEncoder::new(&mut encoded_data);
410 encoder
411 .write_image(&img_data, 8, 8, image::ExtendedColorType::L8)
412 .unwrap();
413 encoded_data.iter().enumerate().for_each(|(i, byte)| {
414 assert_eq!(*byte, expected_data[i]);
415 });
416 }
417
418 #[test]
419 fn test_encoder_irregular_width() {
420 use image::ImageEncoder;
421 let img_data = [
422 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, ];
433 #[allow(clippy::unusual_byte_groupings)]
434 let expected_data: [u8; 17] = [
435 0,
436 10,
437 10,
438 1, 0b_00000000,
440 0b00_000011,
441 0b0000_0001,
442 0b001000_00,
443 0b10000100_,
444 0b_01000000,
445 0b10_010000,
446 0b0010_0010,
447 0b000100_00,
448 0b01001000_,
449 0b_00001100,
450 0b00_000000,
451 0b0000_0000,
452 ];
453 let mut encoded_data = Vec::<u8>::with_capacity(expected_data.len());
454 let encoder = crate::otb::OtbEncoder::new(&mut encoded_data);
455 encoder
456 .write_image(&img_data, 10, 10, image::ExtendedColorType::L8)
457 .unwrap();
458 encoded_data.iter().enumerate().for_each(|(i, byte)| {
459 assert_eq!(*byte, expected_data[i]);
460 });
461 }
462}