svg-ultralight 0.47.0__py3-none-any.whl → 0.50.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of svg-ultralight might be problematic. Click here for more details.
- svg_ultralight/__init__.py +108 -105
- svg_ultralight/animate.py +40 -40
- svg_ultralight/attrib_hints.py +13 -14
- svg_ultralight/bounding_boxes/__init__.py +5 -5
- svg_ultralight/bounding_boxes/bound_helpers.py +189 -201
- svg_ultralight/bounding_boxes/padded_text_initializers.py +207 -206
- svg_ultralight/bounding_boxes/supports_bounds.py +166 -166
- svg_ultralight/bounding_boxes/type_bound_collection.py +71 -71
- svg_ultralight/bounding_boxes/type_bound_element.py +65 -65
- svg_ultralight/bounding_boxes/type_bounding_box.py +396 -396
- svg_ultralight/bounding_boxes/type_padded_text.py +411 -411
- svg_ultralight/constructors/__init__.py +14 -14
- svg_ultralight/constructors/new_element.py +115 -115
- svg_ultralight/font_tools/__init__.py +5 -5
- svg_ultralight/font_tools/comp_results.py +295 -293
- svg_ultralight/font_tools/font_info.py +793 -784
- svg_ultralight/image_ops.py +156 -156
- svg_ultralight/inkscape.py +261 -261
- svg_ultralight/layout.py +290 -291
- svg_ultralight/main.py +183 -198
- svg_ultralight/metadata.py +122 -122
- svg_ultralight/nsmap.py +36 -36
- svg_ultralight/py.typed +5 -0
- svg_ultralight/query.py +254 -249
- svg_ultralight/read_svg.py +58 -0
- svg_ultralight/root_elements.py +87 -87
- svg_ultralight/string_conversion.py +244 -244
- svg_ultralight/strings/__init__.py +21 -13
- svg_ultralight/strings/svg_strings.py +106 -67
- svg_ultralight/transformations.py +140 -141
- svg_ultralight/unit_conversion.py +247 -248
- {svg_ultralight-0.47.0.dist-info → svg_ultralight-0.50.1.dist-info}/METADATA +208 -214
- svg_ultralight-0.50.1.dist-info/RECORD +34 -0
- svg_ultralight-0.50.1.dist-info/WHEEL +4 -0
- svg_ultralight-0.47.0.dist-info/RECORD +0 -34
- svg_ultralight-0.47.0.dist-info/WHEEL +0 -5
- svg_ultralight-0.47.0.dist-info/top_level.txt +0 -1
svg_ultralight/inkscape.py
CHANGED
|
@@ -1,261 +1,261 @@
|
|
|
1
|
-
"""Operations on existing svg files.
|
|
2
|
-
|
|
3
|
-
This module contains Inkscape calls for manipulating svg files after they have been
|
|
4
|
-
created, but not necessarily written to disk. These are just wrappers around
|
|
5
|
-
selections from the Inkscape command line interface.
|
|
6
|
-
|
|
7
|
-
Inkscape cli calls generally take the form
|
|
8
|
-
|
|
9
|
-
inkscape --some-option input_filename.svg --export-filename=export_filename.svg
|
|
10
|
-
|
|
11
|
-
This module allows you to optionally make these calls with svg root elements instead
|
|
12
|
-
of filenames. In such cases, the root elements will be written to a temporary file,
|
|
13
|
-
the Inkscape CLI called, and something returned.
|
|
14
|
-
|
|
15
|
-
:author: Shay Hill
|
|
16
|
-
:created: 2023-02-14
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from __future__ import annotations
|
|
20
|
-
|
|
21
|
-
import os
|
|
22
|
-
import subprocess
|
|
23
|
-
import tempfile
|
|
24
|
-
from pathlib import Path
|
|
25
|
-
from tempfile import NamedTemporaryFile
|
|
26
|
-
from typing import TYPE_CHECKING
|
|
27
|
-
|
|
28
|
-
from lxml import etree
|
|
29
|
-
|
|
30
|
-
from svg_ultralight import main
|
|
31
|
-
|
|
32
|
-
if TYPE_CHECKING:
|
|
33
|
-
from lxml.etree import (
|
|
34
|
-
_Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def write_png_from_svg(
|
|
39
|
-
inkscape: str | os.PathLike[str],
|
|
40
|
-
svg: str | os.PathLike[str],
|
|
41
|
-
png: str | os.PathLike[str] | None = None,
|
|
42
|
-
) -> str:
|
|
43
|
-
"""Convert an svg file to a png.
|
|
44
|
-
|
|
45
|
-
:param inkscape: path to inkscape executable
|
|
46
|
-
:param svg: path to svg file
|
|
47
|
-
:param png: optional path to png output file
|
|
48
|
-
:return: png filename
|
|
49
|
-
:effects: creates a new png from svg filename
|
|
50
|
-
:raises ValueError: if unable to write png. This could result from an error with
|
|
51
|
-
Inkscape.
|
|
52
|
-
|
|
53
|
-
If no output png path is given, the output path will be inferred from the ``svg``
|
|
54
|
-
filename.
|
|
55
|
-
"""
|
|
56
|
-
inkscape = Path(inkscape).with_suffix("") # remove .exe if present
|
|
57
|
-
png = str(Path(svg).with_suffix(".png")) if png is None else str(png)
|
|
58
|
-
|
|
59
|
-
# inkscape versions >= 1.0
|
|
60
|
-
options = [f'"{svg}"', "--export-type=png", f'--export-filename="{png}"']
|
|
61
|
-
return_code = subprocess.call(f'"{inkscape}" ' + " ".join(options))
|
|
62
|
-
if return_code == 0:
|
|
63
|
-
return png
|
|
64
|
-
|
|
65
|
-
# inkscape versions < 1.0
|
|
66
|
-
return_code = subprocess.call(f'"{inkscape}" -f "{svg}" -e "{png}"')
|
|
67
|
-
if return_code == 0:
|
|
68
|
-
return png
|
|
69
|
-
|
|
70
|
-
msg = f"failed to write {png} with inkscape {inkscape}"
|
|
71
|
-
raise ValueError(msg)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def write_png(
|
|
75
|
-
inkscape: str | os.PathLike[str],
|
|
76
|
-
png: str | os.PathLike[str],
|
|
77
|
-
root: EtreeElement,
|
|
78
|
-
stylesheet: str | os.PathLike[str] | None = None,
|
|
79
|
-
) -> str:
|
|
80
|
-
"""Create a png file without writing an intermediate svg file.
|
|
81
|
-
|
|
82
|
-
:param inkscape: path to inkscape executable
|
|
83
|
-
:param png: path to output png file
|
|
84
|
-
:param root: root node of your svg geometry
|
|
85
|
-
:param stylesheet: optional path to css stylesheet
|
|
86
|
-
:return: png filename (the same you input as ``png``)
|
|
87
|
-
:effects: creates a new png file
|
|
88
|
-
|
|
89
|
-
This just creates a tempfile, writes the svg to the tempfile, then calls
|
|
90
|
-
``write_png_from_svg`` with the tempfile. This isn't faster (it might be slightly
|
|
91
|
-
slower), but it keeps the filesystem clean when you only want the png.
|
|
92
|
-
"""
|
|
93
|
-
with NamedTemporaryFile(mode="wb", delete=False) as svg_file:
|
|
94
|
-
svg = main.write_svg(svg_file, root, stylesheet)
|
|
95
|
-
_ = write_png_from_svg(inkscape, svg, png)
|
|
96
|
-
os.unlink(svg)
|
|
97
|
-
return str(png)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def write_pdf_from_svg(
|
|
101
|
-
inkscape: str | os.PathLike[str],
|
|
102
|
-
svg: str | os.PathLike[str],
|
|
103
|
-
pdf: str | os.PathLike[str] | None = None,
|
|
104
|
-
) -> str:
|
|
105
|
-
"""Convert an svg file to a pdf.
|
|
106
|
-
|
|
107
|
-
:param inkscape: path to inkscape executable
|
|
108
|
-
:param svg: path to svg file
|
|
109
|
-
:param pdf: optional path to png output file
|
|
110
|
-
:return: pdf filename
|
|
111
|
-
:effects: creates a new pfd from svg filename
|
|
112
|
-
:raises ValueError: if unable to write pdf. This could result from an error with
|
|
113
|
-
Inkscape.
|
|
114
|
-
|
|
115
|
-
If no output png path is given, the output path will be inferred from the ``svg``
|
|
116
|
-
filename.
|
|
117
|
-
"""
|
|
118
|
-
inkscape = Path(inkscape).with_suffix("") # remove .exe if present
|
|
119
|
-
pdf = str(Path(svg).with_suffix(".pdf")) if pdf is None else str(pdf)
|
|
120
|
-
|
|
121
|
-
# inkscape versions >= 1.0
|
|
122
|
-
options = [f'"{svg}"', "--export-type=pdf", f'--export-filename="{pdf}"']
|
|
123
|
-
return_code = subprocess.call(f'"{inkscape}" ' + " ".join(options))
|
|
124
|
-
if return_code == 0:
|
|
125
|
-
return pdf
|
|
126
|
-
|
|
127
|
-
# inkscape versions < 1.0
|
|
128
|
-
return_code = subprocess.call(f'"{inkscape}" -f "{svg}" -e "{pdf}"')
|
|
129
|
-
if return_code == 0:
|
|
130
|
-
return pdf
|
|
131
|
-
|
|
132
|
-
msg = f"failed to write {pdf} from {svg}"
|
|
133
|
-
raise ValueError(msg)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def write_pdf(
|
|
137
|
-
inkscape: str | os.PathLike[str],
|
|
138
|
-
pdf: str | os.PathLike[str],
|
|
139
|
-
root: EtreeElement,
|
|
140
|
-
stylesheet: str | os.PathLike[str] | None = None,
|
|
141
|
-
) -> str:
|
|
142
|
-
"""Create a pdf file without writing an intermediate svg file.
|
|
143
|
-
|
|
144
|
-
:param inkscape: path to inkscape executable
|
|
145
|
-
:param pdf: path to output pdf file
|
|
146
|
-
:param root: root node of your svg geometry
|
|
147
|
-
:param stylesheet: optional path to css stylesheet
|
|
148
|
-
:return: pdf filename (the same you input as ``pdf``)
|
|
149
|
-
:effects: creates a new pdf file
|
|
150
|
-
|
|
151
|
-
This just creates a tempfile, writes the svg to the tempfile, then calls
|
|
152
|
-
``write_pdf_from_svg`` with the tempfile. This isn't faster (it might be slightly
|
|
153
|
-
slower), but it keeps the filesystem clean when you only want the pdf.
|
|
154
|
-
"""
|
|
155
|
-
with NamedTemporaryFile(mode="wb", delete=False) as svg_file:
|
|
156
|
-
svg = main.write_svg(svg_file, root, stylesheet)
|
|
157
|
-
_ = write_pdf_from_svg(inkscape, svg, pdf)
|
|
158
|
-
os.unlink(svg)
|
|
159
|
-
return str(pdf)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def export_text_to_path(
|
|
163
|
-
inkscape: str | os.PathLike[str],
|
|
164
|
-
input_file: str | os.PathLike[str],
|
|
165
|
-
export_file: str | os.PathLike[str],
|
|
166
|
-
) -> str:
|
|
167
|
-
"""Export copy of svg file with text converted to paths.
|
|
168
|
-
|
|
169
|
-
:param inkscape: Path to inkscape executable.
|
|
170
|
-
:param input_file: Path to svg file.
|
|
171
|
-
:param export_file: Path to result.
|
|
172
|
-
:return: Path to result.
|
|
173
|
-
:effect: Writes to export_file.
|
|
174
|
-
|
|
175
|
-
Find any text objects in an svg file and convert them to paths.
|
|
176
|
-
"""
|
|
177
|
-
inkscape = Path(inkscape).with_suffix("") # remove .exe if present
|
|
178
|
-
command = [
|
|
179
|
-
str(inkscape),
|
|
180
|
-
"--export-text-to-path",
|
|
181
|
-
"--export-plain-svg",
|
|
182
|
-
str(input_file),
|
|
183
|
-
f"--export-filename={export_file}",
|
|
184
|
-
]
|
|
185
|
-
_ = subprocess.call(command)
|
|
186
|
-
return str(export_file)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
def convert_text_to_path(
|
|
190
|
-
inkscape: str | os.PathLike[str], root: EtreeElement
|
|
191
|
-
) -> EtreeElement:
|
|
192
|
-
"""Convert text to path in a root svg element.
|
|
193
|
-
|
|
194
|
-
:param inkscape: Path to inkscape executable.
|
|
195
|
-
:param root: SVG root element.
|
|
196
|
-
:return: SVG root element with text converted to path.
|
|
197
|
-
"""
|
|
198
|
-
with tempfile.NamedTemporaryFile(suffix=".svg", delete=False) as f:
|
|
199
|
-
_ = main.write_svg(f, root)
|
|
200
|
-
temp_input = f.name
|
|
201
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
|
202
|
-
temp_export = Path(temp_dir) / "export.svg"
|
|
203
|
-
_ = export_text_to_path(inkscape, temp_input, temp_export)
|
|
204
|
-
root = etree.parse(temp_export).getroot()
|
|
205
|
-
os.unlink(temp_input)
|
|
206
|
-
return root
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
def write_root(
|
|
210
|
-
inkscape: str | os.PathLike[str],
|
|
211
|
-
filename: str | os.PathLike[str],
|
|
212
|
-
root: EtreeElement,
|
|
213
|
-
*,
|
|
214
|
-
do_text_to_path: bool = True,
|
|
215
|
-
do_svg: bool = True,
|
|
216
|
-
do_png: bool | str | os.PathLike[str] = False,
|
|
217
|
-
do_pdf: bool | str | os.PathLike[str] = False,
|
|
218
|
-
) -> EtreeElement:
|
|
219
|
-
"""Save xml in multiple file formats, optionally updating text to paths.
|
|
220
|
-
|
|
221
|
-
:param inkscape: Path to the Inkscape executable or command.
|
|
222
|
-
:param filename: Path to the output svg file.
|
|
223
|
-
:param root: The XML element to be saved.
|
|
224
|
-
:param do_text_to_path: Whether to convert text to paths.
|
|
225
|
-
:param do_svg: Whether to save the file in SVG format.
|
|
226
|
-
:param do_png: Whether to save the file in PNG format. If True, the output
|
|
227
|
-
filename will be generated from the filename argument. Optionally
|
|
228
|
-
explicity specify an output path.
|
|
229
|
-
:param do_pdf: Whether to save the file in PDF format. If True, the output
|
|
230
|
-
filename will be generated from the filename argument. Optionally
|
|
231
|
-
explicity specify an output path.
|
|
232
|
-
:return: The XML element that was saved.
|
|
233
|
-
|
|
234
|
-
This is an umbrella function over the other functions in this module. If you
|
|
235
|
-
have Inkscape installed, this function will likeley be a better choice than
|
|
236
|
-
`write_svg`, even if it will not accept IO objects as filename arguments.
|
|
237
|
-
|
|
238
|
-
The largest errors between Inkscape and browsers have to do with text. If the
|
|
239
|
-
browser doesn't know about your font (even if it *should*), your svg will
|
|
240
|
-
not look the same in your browser (or book) as it does in Inkscape. It's
|
|
241
|
-
good practice to save all svg images with text using this function.
|
|
242
|
-
"""
|
|
243
|
-
output_svg = Path(filename).with_suffix(".svg")
|
|
244
|
-
output_png = output_svg.with_suffix(".png") if isinstance(do_png, bool) else do_png
|
|
245
|
-
output_pdf = output_svg.with_suffix(".pdf") if isinstance(do_pdf, bool) else do_pdf
|
|
246
|
-
|
|
247
|
-
if do_text_to_path and next(root.itertext(), None) is not None:
|
|
248
|
-
root = convert_text_to_path(inkscape, root)
|
|
249
|
-
if do_svg:
|
|
250
|
-
_ = main.write_svg(output_svg, root)
|
|
251
|
-
if do_png:
|
|
252
|
-
if do_svg:
|
|
253
|
-
_ = write_png_from_svg(inkscape, output_svg, output_png)
|
|
254
|
-
else:
|
|
255
|
-
_ = write_png(inkscape, output_png, root)
|
|
256
|
-
if do_pdf:
|
|
257
|
-
if do_svg:
|
|
258
|
-
_ = write_pdf_from_svg(inkscape, output_svg, output_pdf)
|
|
259
|
-
else:
|
|
260
|
-
_ = write_pdf(inkscape, output_pdf, root)
|
|
261
|
-
return root
|
|
1
|
+
"""Operations on existing svg files.
|
|
2
|
+
|
|
3
|
+
This module contains Inkscape calls for manipulating svg files after they have been
|
|
4
|
+
created, but not necessarily written to disk. These are just wrappers around
|
|
5
|
+
selections from the Inkscape command line interface.
|
|
6
|
+
|
|
7
|
+
Inkscape cli calls generally take the form
|
|
8
|
+
|
|
9
|
+
inkscape --some-option input_filename.svg --export-filename=export_filename.svg
|
|
10
|
+
|
|
11
|
+
This module allows you to optionally make these calls with svg root elements instead
|
|
12
|
+
of filenames. In such cases, the root elements will be written to a temporary file,
|
|
13
|
+
the Inkscape CLI called, and something returned.
|
|
14
|
+
|
|
15
|
+
:author: Shay Hill
|
|
16
|
+
:created: 2023-02-14
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import os
|
|
22
|
+
import subprocess
|
|
23
|
+
import tempfile
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from tempfile import NamedTemporaryFile
|
|
26
|
+
from typing import TYPE_CHECKING
|
|
27
|
+
|
|
28
|
+
from lxml import etree
|
|
29
|
+
|
|
30
|
+
from svg_ultralight import main
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from lxml.etree import (
|
|
34
|
+
_Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def write_png_from_svg(
|
|
39
|
+
inkscape: str | os.PathLike[str],
|
|
40
|
+
svg: str | os.PathLike[str],
|
|
41
|
+
png: str | os.PathLike[str] | None = None,
|
|
42
|
+
) -> str:
|
|
43
|
+
"""Convert an svg file to a png.
|
|
44
|
+
|
|
45
|
+
:param inkscape: path to inkscape executable
|
|
46
|
+
:param svg: path to svg file
|
|
47
|
+
:param png: optional path to png output file
|
|
48
|
+
:return: png filename
|
|
49
|
+
:effects: creates a new png from svg filename
|
|
50
|
+
:raises ValueError: if unable to write png. This could result from an error with
|
|
51
|
+
Inkscape.
|
|
52
|
+
|
|
53
|
+
If no output png path is given, the output path will be inferred from the ``svg``
|
|
54
|
+
filename.
|
|
55
|
+
"""
|
|
56
|
+
inkscape = Path(inkscape).with_suffix("") # remove .exe if present
|
|
57
|
+
png = str(Path(svg).with_suffix(".png")) if png is None else str(png)
|
|
58
|
+
|
|
59
|
+
# inkscape versions >= 1.0
|
|
60
|
+
options = [f'"{svg}"', "--export-type=png", f'--export-filename="{png}"']
|
|
61
|
+
return_code = subprocess.call(f'"{inkscape}" ' + " ".join(options))
|
|
62
|
+
if return_code == 0:
|
|
63
|
+
return png
|
|
64
|
+
|
|
65
|
+
# inkscape versions < 1.0
|
|
66
|
+
return_code = subprocess.call(f'"{inkscape}" -f "{svg}" -e "{png}"')
|
|
67
|
+
if return_code == 0:
|
|
68
|
+
return png
|
|
69
|
+
|
|
70
|
+
msg = f"failed to write {png} with inkscape {inkscape}"
|
|
71
|
+
raise ValueError(msg)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def write_png(
|
|
75
|
+
inkscape: str | os.PathLike[str],
|
|
76
|
+
png: str | os.PathLike[str],
|
|
77
|
+
root: EtreeElement,
|
|
78
|
+
stylesheet: str | os.PathLike[str] | None = None,
|
|
79
|
+
) -> str:
|
|
80
|
+
"""Create a png file without writing an intermediate svg file.
|
|
81
|
+
|
|
82
|
+
:param inkscape: path to inkscape executable
|
|
83
|
+
:param png: path to output png file
|
|
84
|
+
:param root: root node of your svg geometry
|
|
85
|
+
:param stylesheet: optional path to css stylesheet
|
|
86
|
+
:return: png filename (the same you input as ``png``)
|
|
87
|
+
:effects: creates a new png file
|
|
88
|
+
|
|
89
|
+
This just creates a tempfile, writes the svg to the tempfile, then calls
|
|
90
|
+
``write_png_from_svg`` with the tempfile. This isn't faster (it might be slightly
|
|
91
|
+
slower), but it keeps the filesystem clean when you only want the png.
|
|
92
|
+
"""
|
|
93
|
+
with NamedTemporaryFile(mode="wb", delete=False) as svg_file:
|
|
94
|
+
svg = main.write_svg(svg_file, root, stylesheet)
|
|
95
|
+
_ = write_png_from_svg(inkscape, svg, png)
|
|
96
|
+
os.unlink(svg)
|
|
97
|
+
return str(png)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def write_pdf_from_svg(
|
|
101
|
+
inkscape: str | os.PathLike[str],
|
|
102
|
+
svg: str | os.PathLike[str],
|
|
103
|
+
pdf: str | os.PathLike[str] | None = None,
|
|
104
|
+
) -> str:
|
|
105
|
+
"""Convert an svg file to a pdf.
|
|
106
|
+
|
|
107
|
+
:param inkscape: path to inkscape executable
|
|
108
|
+
:param svg: path to svg file
|
|
109
|
+
:param pdf: optional path to png output file
|
|
110
|
+
:return: pdf filename
|
|
111
|
+
:effects: creates a new pfd from svg filename
|
|
112
|
+
:raises ValueError: if unable to write pdf. This could result from an error with
|
|
113
|
+
Inkscape.
|
|
114
|
+
|
|
115
|
+
If no output png path is given, the output path will be inferred from the ``svg``
|
|
116
|
+
filename.
|
|
117
|
+
"""
|
|
118
|
+
inkscape = Path(inkscape).with_suffix("") # remove .exe if present
|
|
119
|
+
pdf = str(Path(svg).with_suffix(".pdf")) if pdf is None else str(pdf)
|
|
120
|
+
|
|
121
|
+
# inkscape versions >= 1.0
|
|
122
|
+
options = [f'"{svg}"', "--export-type=pdf", f'--export-filename="{pdf}"']
|
|
123
|
+
return_code = subprocess.call(f'"{inkscape}" ' + " ".join(options))
|
|
124
|
+
if return_code == 0:
|
|
125
|
+
return pdf
|
|
126
|
+
|
|
127
|
+
# inkscape versions < 1.0
|
|
128
|
+
return_code = subprocess.call(f'"{inkscape}" -f "{svg}" -e "{pdf}"')
|
|
129
|
+
if return_code == 0:
|
|
130
|
+
return pdf
|
|
131
|
+
|
|
132
|
+
msg = f"failed to write {pdf} from {svg}"
|
|
133
|
+
raise ValueError(msg)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def write_pdf(
|
|
137
|
+
inkscape: str | os.PathLike[str],
|
|
138
|
+
pdf: str | os.PathLike[str],
|
|
139
|
+
root: EtreeElement,
|
|
140
|
+
stylesheet: str | os.PathLike[str] | None = None,
|
|
141
|
+
) -> str:
|
|
142
|
+
"""Create a pdf file without writing an intermediate svg file.
|
|
143
|
+
|
|
144
|
+
:param inkscape: path to inkscape executable
|
|
145
|
+
:param pdf: path to output pdf file
|
|
146
|
+
:param root: root node of your svg geometry
|
|
147
|
+
:param stylesheet: optional path to css stylesheet
|
|
148
|
+
:return: pdf filename (the same you input as ``pdf``)
|
|
149
|
+
:effects: creates a new pdf file
|
|
150
|
+
|
|
151
|
+
This just creates a tempfile, writes the svg to the tempfile, then calls
|
|
152
|
+
``write_pdf_from_svg`` with the tempfile. This isn't faster (it might be slightly
|
|
153
|
+
slower), but it keeps the filesystem clean when you only want the pdf.
|
|
154
|
+
"""
|
|
155
|
+
with NamedTemporaryFile(mode="wb", delete=False) as svg_file:
|
|
156
|
+
svg = main.write_svg(svg_file, root, stylesheet)
|
|
157
|
+
_ = write_pdf_from_svg(inkscape, svg, pdf)
|
|
158
|
+
os.unlink(svg)
|
|
159
|
+
return str(pdf)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def export_text_to_path(
|
|
163
|
+
inkscape: str | os.PathLike[str],
|
|
164
|
+
input_file: str | os.PathLike[str],
|
|
165
|
+
export_file: str | os.PathLike[str],
|
|
166
|
+
) -> str:
|
|
167
|
+
"""Export copy of svg file with text converted to paths.
|
|
168
|
+
|
|
169
|
+
:param inkscape: Path to inkscape executable.
|
|
170
|
+
:param input_file: Path to svg file.
|
|
171
|
+
:param export_file: Path to result.
|
|
172
|
+
:return: Path to result.
|
|
173
|
+
:effect: Writes to export_file.
|
|
174
|
+
|
|
175
|
+
Find any text objects in an svg file and convert them to paths.
|
|
176
|
+
"""
|
|
177
|
+
inkscape = Path(inkscape).with_suffix("") # remove .exe if present
|
|
178
|
+
command = [
|
|
179
|
+
str(inkscape),
|
|
180
|
+
"--export-text-to-path",
|
|
181
|
+
"--export-plain-svg",
|
|
182
|
+
str(input_file),
|
|
183
|
+
f"--export-filename={export_file}",
|
|
184
|
+
]
|
|
185
|
+
_ = subprocess.call(command)
|
|
186
|
+
return str(export_file)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def convert_text_to_path(
|
|
190
|
+
inkscape: str | os.PathLike[str], root: EtreeElement
|
|
191
|
+
) -> EtreeElement:
|
|
192
|
+
"""Convert text to path in a root svg element.
|
|
193
|
+
|
|
194
|
+
:param inkscape: Path to inkscape executable.
|
|
195
|
+
:param root: SVG root element.
|
|
196
|
+
:return: SVG root element with text converted to path.
|
|
197
|
+
"""
|
|
198
|
+
with tempfile.NamedTemporaryFile(suffix=".svg", delete=False) as f:
|
|
199
|
+
_ = main.write_svg(f, root)
|
|
200
|
+
temp_input = f.name
|
|
201
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
202
|
+
temp_export = Path(temp_dir) / "export.svg"
|
|
203
|
+
_ = export_text_to_path(inkscape, temp_input, temp_export)
|
|
204
|
+
root = etree.parse(temp_export).getroot()
|
|
205
|
+
os.unlink(temp_input)
|
|
206
|
+
return root
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def write_root(
|
|
210
|
+
inkscape: str | os.PathLike[str],
|
|
211
|
+
filename: str | os.PathLike[str],
|
|
212
|
+
root: EtreeElement,
|
|
213
|
+
*,
|
|
214
|
+
do_text_to_path: bool = True,
|
|
215
|
+
do_svg: bool = True,
|
|
216
|
+
do_png: bool | str | os.PathLike[str] = False,
|
|
217
|
+
do_pdf: bool | str | os.PathLike[str] = False,
|
|
218
|
+
) -> EtreeElement:
|
|
219
|
+
"""Save xml in multiple file formats, optionally updating text to paths.
|
|
220
|
+
|
|
221
|
+
:param inkscape: Path to the Inkscape executable or command.
|
|
222
|
+
:param filename: Path to the output svg file.
|
|
223
|
+
:param root: The XML element to be saved.
|
|
224
|
+
:param do_text_to_path: Whether to convert text to paths.
|
|
225
|
+
:param do_svg: Whether to save the file in SVG format.
|
|
226
|
+
:param do_png: Whether to save the file in PNG format. If True, the output
|
|
227
|
+
filename will be generated from the filename argument. Optionally
|
|
228
|
+
explicity specify an output path.
|
|
229
|
+
:param do_pdf: Whether to save the file in PDF format. If True, the output
|
|
230
|
+
filename will be generated from the filename argument. Optionally
|
|
231
|
+
explicity specify an output path.
|
|
232
|
+
:return: The XML element that was saved.
|
|
233
|
+
|
|
234
|
+
This is an umbrella function over the other functions in this module. If you
|
|
235
|
+
have Inkscape installed, this function will likeley be a better choice than
|
|
236
|
+
`write_svg`, even if it will not accept IO objects as filename arguments.
|
|
237
|
+
|
|
238
|
+
The largest errors between Inkscape and browsers have to do with text. If the
|
|
239
|
+
browser doesn't know about your font (even if it *should*), your svg will
|
|
240
|
+
not look the same in your browser (or book) as it does in Inkscape. It's
|
|
241
|
+
good practice to save all svg images with text using this function.
|
|
242
|
+
"""
|
|
243
|
+
output_svg = Path(filename).with_suffix(".svg")
|
|
244
|
+
output_png = output_svg.with_suffix(".png") if isinstance(do_png, bool) else do_png
|
|
245
|
+
output_pdf = output_svg.with_suffix(".pdf") if isinstance(do_pdf, bool) else do_pdf
|
|
246
|
+
|
|
247
|
+
if do_text_to_path and next(root.itertext(), None) is not None:
|
|
248
|
+
root = convert_text_to_path(inkscape, root)
|
|
249
|
+
if do_svg:
|
|
250
|
+
_ = main.write_svg(output_svg, root)
|
|
251
|
+
if do_png:
|
|
252
|
+
if do_svg:
|
|
253
|
+
_ = write_png_from_svg(inkscape, output_svg, output_png)
|
|
254
|
+
else:
|
|
255
|
+
_ = write_png(inkscape, output_png, root)
|
|
256
|
+
if do_pdf:
|
|
257
|
+
if do_svg:
|
|
258
|
+
_ = write_pdf_from_svg(inkscape, output_svg, output_pdf)
|
|
259
|
+
else:
|
|
260
|
+
_ = write_pdf(inkscape, output_pdf, root)
|
|
261
|
+
return root
|