原文
def write_svg(strokes, out: Path, flip_y=True, stroke_w=2):
bb = bbox(strokes)
if not bb:
return False
xmin, ymin, xmax, ymax = bb
w, h = xmax - xmin + 1, ymax - ymin + 1
with out.open("w", encoding="utf-8") as f:
if flip_y:
f.write(f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="{xmin} {ymin} {w} {h}" '
f'width="{w}" height="{h}" stroke="black" fill="none" stroke-width="{stroke_w}">\n')
f.write(f' <g transform="translate(0,{ymin + ymax}) scale(1,-1)">\n')
for s in strokes:
f.write(' <path d="M{},{} {}"/>\n'.format(
s[0][0], s[0][1], " ".join(f"L{x},{y}" for x, y in s[1:])))
f.write(' </g>\n</svg>\n')
else:
f.write(f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="{xmin} {ymin} {w} {h}" '
f'width="{w}" height="{h}" stroke="black" fill="none" stroke-width="{stroke_w}">\n')
for s in strokes:
f.write(' <path d="M{},{} {}"/>\n'.format(
s[0][0], s[0][1], " ".join(f"L{x},{y}" for x, y in s[1:])))
f.write('</svg>\n')
return True
def main():
ap = argparse.ArgumentParser(description="Extract SVGs from fixed slots")
ap.add_argument("bin", type=Path, help="full flash dump (e.g., full.bin)")
ap.add_argument("--out", type=Path, default=Path("svgs"), help="output directory")
ap.add_argument("--base", type=lambda x:int(x,0), default=0x04, help="first slot start offset (default 0x04)")
ap.add_argument("--slot", type=lambda x:int(x,0), default=0xEA60, help="slot size (default 0xEA60)")
ap.add_argument("--count", type=int, default=None, help="number of slots (default: autodetect from file size)")
ap.add_argument("--min-pts", type=int, default=2, help="min points to export (default 2)")
ap.add_argument("--no-flip-y", action="store_true", help="do not flip Y axis")
args = ap.parse_args()
data = args.bin.read_bytes()
size = len(data)
if args.count is None:
# Best-effort autodetect
usable = max(0, size - args.base)
args.count = usable // args.slot
args.out.mkdir(parents=True, exist_ok=True)
exported = 0
for i in range(args.count):
off = args.base + i * args.slot
if off >= size:
break
slot = data[off : min(off + args.slot, size)]
words = u16be_words(slot)
strokes = strokes_from_slot(words)
if sum(len(s) for s in strokes) < args.min_pts:
continue
svg_path = args.out / f"drawing_{i:03d}.svg"
if write_svg(strokes, svg_path, flip_y=not args.no_flip_y, stroke_w=2):
exported += 1
# uncomment for debug:
# print(f"{i:03d} @ 0x{off:08X} -> {svg_path.name}")
print(f"Exported {exported} SVGs to {args.out} from {args.count} slots "
f"(base=0x{args.base:X}, slot=0x{args.slot:X}).")