1use std::io::{Cursor, Read, Seek, SeekFrom};
20
21use byteorder::{LittleEndian as LE, ReadBytesExt};
22use encoding_rs::*;
23use log::debug;
24
25pub use crate::error::*;
26use std::ops::Range;
27use image::{ImageBuffer, RgbImage, Rgb, imageops, FilterType};
28use bit_vec::BitVec;
29
30pub mod error;
31
32#[derive(Clone, Debug, PartialEq)]
34pub struct ImageInfo {
35 pub machine_code: String,
38 pub user_name: String,
40 pub memo: String,
42 pub x: u16,
44 pub y: u16,
46 pub width: u16,
48 pub height: u16,
50 pub num_colors: u16,
52 pub is_200_line_mode: bool,
54}
55
56#[derive(Copy, Clone, Debug)]
57enum ColorMode { Palette16, Palette256 }
58
59pub struct Decoder {
61 info: ImageInfo,
62 header_offset: u32,
63 color_mode: ColorMode,
64 buf: Vec<u8>,
65}
66
67struct Palette {
69 grb_colors: Vec<u8>,
70}
71
72impl Palette {
73 pub fn new(grb_colors: &[u8]) -> Palette {
74 Palette { grb_colors: grb_colors.to_owned() }
75 }
76
77 pub fn rgb(&self, index: u8) -> Rgb<u8> {
78 let index = index as usize * 3;
79 let g = self.grb_colors[index];
80 let r = self.grb_colors[index + 1];
81 let b = self.grb_colors[index + 2];
82 Rgb([r, g, b])
83 }
84}
85
86const MAGIC_NUMBER: &[u8; 8] = b"MAKI02 ";
87const TEXT_ENCODING: &str = "Shift_JIS";
88const HEADER_SIZE: u32 = 32;
89
90
91fn range(start: u32, size: u32) -> Range<usize> {
92 start as usize..(start + size) as usize
93}
94
95fn pixel_unit(c: ColorMode) -> u16 {
96 match c {
97 ColorMode::Palette16 => 8,
98 ColorMode::Palette256 => 4,
99 }
100}
101
102fn nibble_high(b: u8) -> u8 {
103 b >> 4
104}
105
106fn nibble_low(b: u8) -> u8 {
107 b & 0xf
108}
109
110impl Decoder {
111 pub fn new<R: Read>(mut reader: R) -> Result<Decoder> {
113 let mut buf = Vec::new();
114 reader.read_to_end(&mut buf).unwrap();
115
116 let encoding = Encoding::for_label(TEXT_ENCODING.as_bytes())
117 .ok_or_else(|| other_err(format!("Unknown encoding; {}", TEXT_ENCODING)))?;
118
119 if &buf[..8] != MAGIC_NUMBER {
120 return Err(Error::InvalidFormat("Magic number mismatch".into()));
121 }
122
123 let machine_code = String::from_utf8(buf[8..12].to_owned()).unwrap();
124 let (user_name, _, _) = encoding.decode(&buf[range(12, 19)]);
125 debug!("machine_code: '{}', user_name: '{}'", machine_code, user_name);
126
127 let memo = &buf.iter().skip(31).take_while(|&b| *b != 0x1au8)
128 .cloned().collect::<Vec<u8>>();
129 let header_offset = 31 + memo.len() as u32 + 1;
130 debug!("header_offset: {}", header_offset);
131 let mut header_buf = Cursor::new(buf[range(header_offset, HEADER_SIZE)].to_owned());
132 let (memo, _, _) = encoding.decode(&memo);
133 debug!("memo: '{}'", memo);
134
135 if header_buf.read_u8()? != 0 {
136 return Err(Error::InvalidFormat("header offset 0x00".into()));
137 }
138 header_buf.seek(SeekFrom::Current(2))?;
139 let screen_mode = header_buf.read_u8()?;
140 let color_mode =
141 if screen_mode & 0x80 != 0 { ColorMode::Palette256 } else { ColorMode::Palette16 };
142 debug!("screen_mode: {}, color_mode: {:?}", screen_mode, color_mode);
143
144 let x = header_buf.read_u16::<LE>()?;
145 let y = header_buf.read_u16::<LE>()?;
146 let end_x = header_buf.read_u16::<LE>()?;
147 let end_y = header_buf.read_u16::<LE>()?;
148 debug!("x: {}, y: {}, end_x: {}, end_y: {}", x, y, end_x, end_y);
149 let pixel_unit = pixel_unit(color_mode);
150
151 Ok(Decoder {
152 info: ImageInfo {
153 machine_code,
154 user_name: user_name.to_string(),
155 memo: memo.to_string(),
156 x,
157 y,
158 width: (((end_x / pixel_unit) - (x / pixel_unit)) + 1) * pixel_unit,
159 height: end_y - y + 1,
160 num_colors: match color_mode {
161 ColorMode::Palette16 => 16,
162 ColorMode::Palette256 => 256,
163 },
164 is_200_line_mode: screen_mode & 1 != 0,
165 },
166 header_offset,
167 color_mode,
168 buf,
169 })
170 }
171
172 pub fn info(&self) -> &ImageInfo {
174 &self.info
175 }
176
177 pub fn decode(&self) -> Result<RgbImage> {
179 let buf = &self.buf;
180 let mut header_buf = Cursor::new(buf[range(self.header_offset, HEADER_SIZE)].to_owned());
181 header_buf.seek(SeekFrom::Start(12))?;
182
183 let flag_a_offset = header_buf.read_u32::<LE>()?;
184 let flag_b_offset = header_buf.read_u32::<LE>()?;
185 let flag_b_size = header_buf.read_u32::<LE>()?;
186 let flag_a_size = flag_b_offset - flag_a_offset;
187 let pixel_offset = header_buf.read_u32::<LE>()?;
188 let pixel_size = header_buf.read_u32::<LE>()?;
189 debug!("flag_a_offset: {}, flag_b_offset: {}, flag_a_size: {}, flag_b_size: {}, pixel_offset: {}, pixel_size: {}",
190 flag_a_offset, flag_b_offset, flag_a_size, flag_b_size, pixel_offset, pixel_size);
191 assert_eq!(header_buf.position() as u32, HEADER_SIZE);
192
193 let palette = &buf[range(self.header_offset + HEADER_SIZE, u32::from(self.info.num_colors * 3))];
194 let flag_a = &buf[range(self.header_offset + flag_a_offset, flag_a_size)];
195 let flag_b = &buf[range(self.header_offset + flag_b_offset, flag_b_size)];
196 let pixels = &buf[range(self.header_offset + pixel_offset, pixel_size)];
197let mut img: RgbImage = ImageBuffer::new(u32::from(self.info.width), u32::from(self.info.height));
201 let pixel_unit = pixel_unit(self.color_mode);
202 let num_x_units = self.info.width / pixel_unit;
203
204 let mut flag_a_bits = BitVec::from_bytes(flag_a).into_iter();
205 let mut flag_b = Cursor::new(flag_b);
206 let mut pixels = Cursor::new(pixels);
207 let palette = Palette::new(palette);
208 let mut line_flags = vec![0u8; num_x_units as usize];
209 let copy_vec = self.init_copy_vec();
210
211 for y in 0..u32::from(self.info.height) {
212 for x in 0..num_x_units as usize {
213 if let Some(true) = flag_a_bits.next() {
214 line_flags[x] ^= flag_b.read_u8()?;
215 }
216 }
217
218 let mut dst_x = 0;
219 let mut decode_nibble = |flag: u8| {
220 if flag == 0 {
221 match self.color_mode {
222 ColorMode::Palette16 => {
223 for _ in 0..2 {
224 let pixel_byte = pixels.read_u8().unwrap();
225 img.put_pixel(dst_x, y, palette.rgb(nibble_high(pixel_byte)));
226 dst_x += 1;
227 img.put_pixel(dst_x, y, palette.rgb(nibble_low(pixel_byte)));
228 dst_x += 1;
229 }
230 }
231 ColorMode::Palette256 => {
232 for _ in 0..2 {
233 let pixel_byte = pixels.read_u8().unwrap();
234 img.put_pixel(dst_x, y, palette.rgb(pixel_byte));
235 dst_x += 1;
236 }
237 }
238 }
239 } else {
240 dst_x += self.copy_pixel_unit(&mut img, dst_x, y, copy_vec[flag as usize]);
241 }
242 };
243
244 for x in 0..num_x_units as usize {
245 let flag = line_flags[x];
246 decode_nibble(nibble_high(flag));
247 decode_nibble(nibble_low(flag));
248 }
249 }
250
251 if self.info.is_200_line_mode {
252 Ok(imageops::resize(&img, u32::from(self.info.width), u32::from(self.info.height) * 2,
253 FilterType::Nearest))
254 } else {
255 Ok(img)
256 }
257 }
258
259 fn init_copy_vec(&self) -> Vec<(u32, u32)> {
260 let x = [0, 1, 2, 4, 0, 1, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0];
261 let y = [0, 0, 0, 0, 1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16];
262 x.iter().zip(y.iter()).map(|(a, b)| (*a, *b)).collect()
263 }
264
265 fn copy_pixel_unit(&self, img: &mut RgbImage, x: u32, y: u32, copy_from: (u32, u32)) -> u32 {
266 let copy_pixels = match self.color_mode {
267 ColorMode::Palette16 => 4,
268 ColorMode::Palette256 => 2,
269 };
270 let src_x = x - (copy_from.0 * copy_pixels);
271 let src_y = y - copy_from.1;
272
273 for i in 0..copy_pixels {
274 img.put_pixel(x + i, y, img[(src_x + i, src_y)]);
275 }
276
277 copy_pixels
278 }
279}