use crate::error::Error;
use crate::types::{ResolvedDesign, StitchCommand};
const STITCH_DATA_OFFSET: usize = 0x1D78;
const SEW_PALETTE: [(u8, u8, u8); 80] = [
(0, 0, 0), (0, 0, 0), (255, 255, 255), (255, 255, 23), (250, 160, 96), (92, 118, 73), (64, 192, 48), (101, 194, 200), (172, 128, 190), (245, 188, 203), (255, 0, 0), (192, 128, 0), (0, 0, 240), (228, 195, 93), (165, 42, 42), (213, 176, 212), (252, 242, 148), (240, 208, 192), (255, 192, 0), (201, 164, 128), (155, 61, 75), (160, 184, 204), (127, 194, 28), (185, 185, 185), (160, 160, 160), (152, 214, 189), (184, 240, 240), (54, 139, 160), (79, 131, 171), (56, 106, 145), (0, 32, 107), (229, 197, 202), (249, 103, 107), (227, 49, 31), (226, 161, 136), (181, 148, 116), (228, 207, 153), (225, 203, 0), (225, 173, 212), (195, 0, 126), (128, 0, 75), (160, 96, 176), (192, 64, 32), (202, 224, 192), (137, 152, 86), (0, 170, 0), (33, 138, 33), (93, 174, 148), (76, 191, 143), (0, 119, 114), (112, 112, 112), (242, 255, 255), (177, 88, 24), (203, 138, 7), (247, 146, 123), (152, 105, 45), (162, 113, 72), (123, 85, 74), (79, 57, 70), (82, 58, 151), (0, 0, 160), (0, 150, 222), (178, 221, 83), (250, 143, 187), (222, 100, 158), (181, 80, 102), (94, 87, 71), (76, 136, 31), (228, 220, 121), (203, 138, 26), (198, 170, 66), (236, 176, 44), (248, 128, 64), (255, 229, 5), (250, 122, 122), (209, 164, 255), (140, 90, 48), (48, 80, 140), (100, 160, 100), (200, 100, 50), ];
pub fn parse(data: &[u8]) -> Result<(Vec<StitchCommand>, Vec<(u8, u8, u8)>), Error> {
if data.len() < STITCH_DATA_OFFSET + 4 {
return Err(Error::TooShort {
expected: STITCH_DATA_OFFSET + 4,
actual: data.len(),
});
}
let color_count = u16::from_le_bytes([data[0], data[1]]) as usize;
if color_count == 0 {
return Err(Error::InvalidHeader("zero color count".into()));
}
let colors: Vec<(u8, u8, u8)> = (0..color_count)
.map(|i| {
let off = 2 + i * 2;
if off + 1 < data.len() {
let idx = u16::from_le_bytes([data[off], data[off + 1]]) as usize;
SEW_PALETTE[idx % SEW_PALETTE.len()]
} else {
(0, 0, 0)
}
})
.collect();
let mut commands = Vec::new();
let mut i = STITCH_DATA_OFFSET;
while i + 1 < data.len() {
let b0 = data[i];
let b1 = data[i + 1];
i += 2;
if b0 != 0x80 {
let dx = b0 as i8 as i16;
let dy = -(b1 as i8 as i16);
commands.push(StitchCommand::Stitch { dx, dy });
continue;
}
if i + 1 >= data.len() {
break;
}
let c0 = data[i];
let c1 = data[i + 1];
i += 2;
if b1 & 1 != 0 {
commands.push(StitchCommand::ColorChange);
} else if b1 == 0x04 || b1 == 0x02 {
let dx = c0 as i8 as i16;
let dy = -(c1 as i8 as i16);
commands.push(StitchCommand::Jump { dx, dy });
} else if b1 == 0x10 {
let dx = c0 as i8 as i16;
let dy = -(c1 as i8 as i16);
commands.push(StitchCommand::Stitch { dx, dy });
} else {
break;
}
}
if commands.is_empty() {
return Err(Error::NoStitchData);
}
if !matches!(commands.last(), Some(StitchCommand::End)) {
commands.push(StitchCommand::End);
}
Ok((commands, colors))
}
pub fn parse_and_resolve(data: &[u8]) -> Result<ResolvedDesign, Error> {
let (commands, colors) = parse(data)?;
crate::resolve::resolve(&commands, colors)
}