mirror of
https://github.com/enzet/map-machine.git
synced 2025-05-06 13:46:47 +02:00
72 lines
2.3 KiB
Python
72 lines
2.3 KiB
Python
"""
|
||
Extract icons from SVG file.
|
||
|
||
Author: Sergey Vartanov (me@enzet.ru).
|
||
"""
|
||
import re
|
||
import xml.dom.minidom
|
||
|
||
from typing import Dict
|
||
|
||
from roentgen import ui
|
||
|
||
|
||
class IconExtractor:
|
||
"""
|
||
Extract icons from SVG file.
|
||
|
||
Icon is a single path with "id" attribute that aligned to 16×16 grid.
|
||
"""
|
||
def __init__(self, svg_file_name: str):
|
||
"""
|
||
:param svg_file_name: input SVG file name with icons. File may contain
|
||
any other irrelevant graphics.
|
||
"""
|
||
self.icons: Dict[str, (str, float, float)] = {}
|
||
|
||
with open(svg_file_name) as input_file:
|
||
content = xml.dom.minidom.parse(input_file)
|
||
for element in content.childNodes:
|
||
if element.nodeName == "svg":
|
||
for node in element.childNodes:
|
||
if node.nodeName in ["g", "path"]:
|
||
self.parse(node)
|
||
|
||
def parse(self, node) -> None:
|
||
"""
|
||
Extract icon paths into a map.
|
||
|
||
:param node: XML node that contains icon
|
||
"""
|
||
if node.nodeName == "path":
|
||
if "id" in node.attributes.keys() and \
|
||
"d" in node.attributes.keys() and \
|
||
node.attributes["id"].value:
|
||
path = node.attributes["d"].value
|
||
m = re.match("[Mm] ([0-9.e-]*)[, ]([0-9.e-]*)", path)
|
||
if not m:
|
||
ui.error(f"invalid path: {path}")
|
||
else:
|
||
x = int(float(m.group(1)) / 16)
|
||
y = int(float(m.group(2)) / 16)
|
||
self.icons[node.attributes["id"].value] = \
|
||
(node.attributes["d"].value, x, y)
|
||
else:
|
||
for sub_node in node.childNodes:
|
||
self.parse(sub_node)
|
||
|
||
def get_path(self, id_: str) -> (str, float, float, bool):
|
||
"""
|
||
Get SVG path of the icon.
|
||
|
||
:param id_: string icon ID
|
||
"""
|
||
if id_ in self.icons:
|
||
return list(self.icons[id_]) + [True]
|
||
else:
|
||
if id_ == "no":
|
||
return "M 4,4 L 4,10 10,10 10,4 z", 0, 0, False
|
||
if id_ == "small":
|
||
return "M 6,6 L 6,8 8,8 8,6 z", 0, 0, False
|
||
ui.error(f"no such icon ID {id_}")
|
||
return "M 4,4 L 4,10 10,10 10,4 z", 0, 0, False
|