114 lines
4.1 KiB
Python
Executable file
114 lines
4.1 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# coding=utf-8
|
|
#
|
|
# Copyright (C) 2023 Jan Winkler
|
|
# based on pdflatex.py (C) by 2019 Marc Jeanmougin
|
|
#
|
|
#
|
|
# 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 2 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, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
#
|
|
"""
|
|
Compile typst code directly into and insert svg into document
|
|
"""
|
|
|
|
import os
|
|
|
|
import inkex
|
|
from inkex.base import TempDirMixin
|
|
from inkex.command import ProgramRunError, call
|
|
from inkex import load_svg, ShapeElement
|
|
from inkex.units import convert_unit
|
|
from inkex.localization import inkex_gettext as _
|
|
from copy import deepcopy
|
|
|
|
|
|
class TypstFormula(TempDirMixin, inkex.GenerateExtension):
|
|
"""
|
|
Class for compilation of typst code into svg. Ensures proper setup
|
|
of the generated svg for insertion into Inkscape.
|
|
"""
|
|
|
|
def add_arguments(self, pars):
|
|
pars.add_argument(
|
|
"--typst_code",
|
|
type=str,
|
|
default=r"$ sum_(k=0)^n k = 1 + ... + n = (n(n+1)) / 2 $",
|
|
)
|
|
pars.add_argument("--font_size", type=int, default=10)
|
|
pars.add_argument("--page", choices=["basic"])
|
|
|
|
def generate(self):
|
|
"""Generator for a svg group holding the formula"""
|
|
typst_file = os.path.join(self.tempdir, "input.typ")
|
|
svg_file = os.path.join(self.tempdir, "output.svg")
|
|
|
|
with open(typst_file, "w") as fhl:
|
|
self.write_typst_code(fhl)
|
|
|
|
try:
|
|
call("typst", "compile", typst_file, svg_file)
|
|
except ProgramRunError as err:
|
|
inkex.errormsg(_("An exception occurred during typst compilation: ") + "\n")
|
|
inkex.errormsg(err.stderr.decode("utf8").replace("\r\n", "\n"))
|
|
raise inkex.AbortExtension()
|
|
|
|
if not os.path.isfile(svg_file):
|
|
inkex.errormsg(_("No svg has been produced by compilation: ") + "\n")
|
|
inkex.errormsg(_(f"Expected file name was: {svg_file}."))
|
|
raise inkex.AbortExtension()
|
|
|
|
with open(svg_file, "r") as fhl:
|
|
svg: inkex.SvgDocumentElement = load_svg(fhl).getroot()
|
|
self.expand_defs(svg)
|
|
scale = convert_unit("1pt", "px") / self.svg.scale
|
|
for child in svg:
|
|
if isinstance(child, ShapeElement):
|
|
# Scale node correctly and also ensure that it is placed
|
|
# in the center of the view
|
|
child.transform = (
|
|
inkex.Transform(scale=scale)
|
|
@ inkex.Transform(translate=-child.bounding_box().center)
|
|
@ child.transform
|
|
)
|
|
yield child
|
|
|
|
def write_typst_code(self, stream):
|
|
"""Takes a formula and wraps it in typst"""
|
|
stream.write(
|
|
f"""#set page(margin: (x: 0pt, y: 0pt))
|
|
#set text({self.options.font_size}pt)
|
|
{self.options.typst_code}"""
|
|
)
|
|
stream.flush()
|
|
|
|
def expand_defs(self, root):
|
|
"""Replaces references to glyph definitions by the content of the definition"""
|
|
for child in root:
|
|
if isinstance(child, inkex.Use):
|
|
group = inkex.Group()
|
|
for el in child.href:
|
|
group.append(deepcopy(el))
|
|
group.transform = inkex.Transform(
|
|
translate=(float(child.get("x", "0")), float(child.get("y", "0")))
|
|
)
|
|
parent = child.getparent()
|
|
parent.remove(child)
|
|
parent.add(group)
|
|
child = group # required for recursive def
|
|
self.expand_defs(child)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
TypstFormula().run()
|