mazeir/map/orthogonal/
image.rs

1use std::error::Error;
2use std::fmt::{Display, Formatter};
3use std::io::Write;
4
5use png::{Encoder, BitDepth, ColorType};
6
7use super::{Orthogonal, LEFT_WALL, UP_WALL};
8use crate::output::Draw;
9
10
11impl Draw for Orthogonal {
12    type Error = DrawError;
13    fn draw<W: Write>(&self, writer: W) -> Result<(), Self::Error> {
14        let image_width = (self.width * 2 + 1) as u32;
15        let image_height = (self.height * 2 + 1) as u32;
16        let image_width_byte_count = (image_width as usize / 8) + if image_width % 8 == 0 { 0 } else { 1 };
17        let mut encoder = Encoder::new(writer, image_width, image_height);
18        encoder.set_depth(BitDepth::One);
19        encoder.set_color(ColorType::Indexed);
20        encoder.set_palette(vec![0, 0, 0, 255, 255, 255]);
21        let mut writer = encoder.write_header().map_err(|_| DrawError::WriteHeaderFailed)?;
22        let mut writer = writer.stream_writer_with_size(128 * 1024).map_err(|_| DrawError::CreateStreamWriterFailed)?;
23        if self.width == 0 || self.height == 0 {
24            writer.write(&[0b0]).map_err(|_| DrawError::StreamWriteFailed)?;
25            return Ok(());
26        }
27        for line in self.map.chunks(self.width) {
28            for cell in line.chunks(4) {
29                let mut byte = 0b0000_0000;
30                for (i, v) in cell.iter().enumerate() {
31                    if *v & UP_WALL != 0 { byte |= 0b1 << (6 - i * 2); }  // 如果上墙不存在,上墙位置设置为白色(1)
32                }
33                writer.write(&[byte]).map_err(|_| DrawError::StreamWriteFailed)?;
34            }
35            if line.len() % 4 == 0 { writer.write(&[0b0]).map_err(|_| DrawError::StreamWriteFailed)?; }
36            for cell in line.chunks(4) {
37                let mut byte = 0b0101_0101;
38                for (i, v) in cell.iter().enumerate() {
39                    if *v & LEFT_WALL != 0 { byte |= 0b1 << (7 - i * 2); }  // 如果左墙不存在,左墙位置设置为白色(1)
40                }
41                writer.write(&[byte]).map_err(|_| DrawError::StreamWriteFailed)?;
42            }
43            if line.len() % 4 == 0 { writer.write(&[0b0]).map_err(|_| DrawError::StreamWriteFailed)?; }
44        }
45        for _ in 0..image_width_byte_count { writer.write(&[0b0]).map_err(|_| DrawError::CreateStreamWriterFailed)?; }
46        Ok(())
47    }
48}
49
50#[derive(Debug)]
51pub enum DrawError {
52    WriteHeaderFailed,
53    CreateStreamWriterFailed,
54    StreamWriteFailed,
55
56}
57
58impl Display for DrawError {
59    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
60        match self {
61            DrawError::WriteHeaderFailed => write!(f, "Write header failed"),
62            DrawError::CreateStreamWriterFailed => write!(f, "Create stream writer failed"),
63            DrawError::StreamWriteFailed => write!(f, "Stream write failed"),
64        }
65    }
66}
67
68impl Error for DrawError {}