boxespy/boxes/svgutil.py

90 lines
2.7 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# Copyright (C) 2016 Florian Festi
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2023-01-23 00:24:55 +01:00
from __future__ import annotations
import re
from xml.etree import ElementTree
2023-01-23 00:24:54 +01:00
ElementTree.register_namespace("", "http://www.w3.org/2000/svg")
ElementTree.register_namespace("xlink", "http://www.w3.org/1999/xlink")
2023-01-23 00:24:55 +01:00
unit2mm: dict[str, float] = {
"mm": 1.0,
"cm": 10.0,
"in": 25.4,
"px": 90.0 / 25.4,
"pt": 90.0 / 25.4 / 1.25,
"pc": 90.0 / 25.4 / 15,
}
2023-01-23 00:24:54 +01:00
def getSizeInMM(tree):
root = tree.getroot()
m = re.match(r"(-?\d+\.?\d*)(\D+)", root.get("height"))
height, units = m.groups()
height = float(height) * unit2mm.get(units, 1.0)
m = re.match(r"(-?\d+\.?\d*)(\D+)", root.get("width"))
width, units = m.groups()
width = float(width) * unit2mm.get(units, 1.0)
return width, height
2023-01-23 00:24:54 +01:00
def getViewBox(tree):
root = tree.getroot()
m = re.match(r"\s*(-?\d+\.?\d*)\s+"
2023-01-23 00:24:54 +01:00
r"(-?\d+\.?\d*)\s+"
r"(-?\d+\.?\d*)\s+"
r"(-?\d+\.?\d)\s*", root.get("viewBox"))
return [float(m) for m in m.groups()]
2023-01-23 00:24:54 +01:00
2023-01-23 00:24:55 +01:00
def ticksPerMM(tree) -> tuple[float, float]:
width, height = getSizeInMM(tree)
x1, y1, x2, y2 = getViewBox(tree)
2023-01-23 00:24:54 +01:00
return x2 / width, y2 / height
2023-01-23 00:24:55 +01:00
def svgMerge(box, inkscape, output) -> None:
src_tree = ElementTree.parse(box)
dest_tree = ElementTree.parse(inkscape)
dest_root = dest_tree.getroot()
src_width, src_height = getSizeInMM(src_tree)
dest_width, dest_height = getSizeInMM(dest_tree)
src_scale_x, src_scale_y = ticksPerMM(src_tree)
dest_scale_x, dest_scale_y = ticksPerMM(dest_tree)
scale_x = dest_scale_x / src_scale_x
scale_y = dest_scale_y / src_scale_y
src_view = getViewBox(src_tree)
off_x = src_view[0] * -scale_x
2023-01-23 00:24:54 +01:00
off_y = (src_view[1] + src_view[3]) * -scale_y + dest_height * scale_y
for el in src_tree.getroot():
dest_root.append(el)
if el.tag.endswith("g"):
2023-01-23 00:24:55 +01:00
el.set("transform", f"matrix({scale_x:f},0,0,{scale_y:f}, {off_x:f}, {off_y:f})")
# write the xml file
ElementTree.ElementTree(dest_root).write(output, encoding='utf-8', xml_declaration=True)