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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Read SVG file and extract text content.
|
|
2
|
+
|
|
3
|
+
Note about svg resolution: Despite the fact that vector graphics have effectively
|
|
4
|
+
infinite resolution, ePub apparently uses the actual geometry size to determine the
|
|
5
|
+
resolution of the image. For images ike a business card drawn in real-world inches
|
|
6
|
+
(3.5" width), an ePub will assume a size of 3.5 pixels. There may be some unit for
|
|
7
|
+
the width and height variables (for InDesign, it's pnt) that addresses this, but I
|
|
8
|
+
don't trust it to be consistent across ePub readers. I adjust the units to something
|
|
9
|
+
large, then use CSS to scale it down to the correct size.
|
|
10
|
+
|
|
11
|
+
:author: Shay Hill
|
|
12
|
+
:created: 2025-07-28
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from lxml import etree
|
|
19
|
+
from lxml.etree import _Element as EtreeElement # pyright: ignore[reportPrivateUsage]
|
|
20
|
+
|
|
21
|
+
import svg_ultralight as su
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_bounding_box_from_root(root: EtreeElement) -> su.BoundingBox:
|
|
25
|
+
"""Extract bounding box from SVG root element.
|
|
26
|
+
|
|
27
|
+
:param root: the root element of the SVG file
|
|
28
|
+
:raise ValueError: if the viewBox attribute is not present
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
viewbox = root.get("viewBox", "")
|
|
32
|
+
try:
|
|
33
|
+
x, y, width, height = map(float, viewbox.split())
|
|
34
|
+
except ValueError as e:
|
|
35
|
+
msg = f"Invalid or missing viewBox attribute: '{viewbox}'"
|
|
36
|
+
raise ValueError(msg) from e
|
|
37
|
+
return su.BoundingBox(x, y, width, height)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def parse(svg_file: str | os.PathLike[str]) -> su.BoundElement:
|
|
41
|
+
"""Import an SVG file and return an SVG object.
|
|
42
|
+
|
|
43
|
+
:param svg_file: Path to the SVG file.
|
|
44
|
+
:return: A BoundElement containing the SVG content and the svg viewBox as a
|
|
45
|
+
BoundingBox.
|
|
46
|
+
|
|
47
|
+
Near equivalent to `etree.parse(file).getroot()`, but returns a BoundElement
|
|
48
|
+
instance. This will only work with SVG files that have a viewBox attribute.
|
|
49
|
+
"""
|
|
50
|
+
with Path(svg_file).open("r", encoding="utf-8") as f:
|
|
51
|
+
root = etree.parse(f).getroot()
|
|
52
|
+
if len(root) == 1:
|
|
53
|
+
elem = root[0]
|
|
54
|
+
else:
|
|
55
|
+
elem = su.new_element("g")
|
|
56
|
+
elem.extend(list(root))
|
|
57
|
+
bbox = get_bounding_box_from_root(root)
|
|
58
|
+
return su.BoundElement(elem, bbox)
|
svg_ultralight/root_elements.py
CHANGED
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
"""Build root elements in various ways.
|
|
2
|
-
|
|
3
|
-
:author: Shay Hill
|
|
4
|
-
:created: 2023-09-23
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from typing import TYPE_CHECKING
|
|
10
|
-
|
|
11
|
-
from svg_ultralight.bounding_boxes import bound_helpers as bound
|
|
12
|
-
from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
|
|
13
|
-
from svg_ultralight.main import new_svg_root
|
|
14
|
-
|
|
15
|
-
if TYPE_CHECKING:
|
|
16
|
-
from lxml.etree import (
|
|
17
|
-
_Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
from svg_ultralight.attrib_hints import ElemAttrib, OptionalElemAttribMapping
|
|
21
|
-
from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
|
|
22
|
-
from svg_ultralight.layout import PadArg
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def _viewbox_args_from_bboxes(*bboxes: BoundingBox) -> dict[str, float]:
|
|
26
|
-
"""Create x_, y_, width_, height_ new_svg_root arguments from bounding boxes.
|
|
27
|
-
|
|
28
|
-
:param bbox: bounding boxes to merge
|
|
29
|
-
:return: dict of new_svg_root arguments
|
|
30
|
-
"""
|
|
31
|
-
merged = BoundingBox.merged(*bboxes)
|
|
32
|
-
return {
|
|
33
|
-
"x_": merged.x,
|
|
34
|
-
"y_": merged.y,
|
|
35
|
-
"width_": merged.width,
|
|
36
|
-
"height_": merged.height,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def new_svg_root_around_bounds(
|
|
41
|
-
*bounded: SupportsBounds | EtreeElement,
|
|
42
|
-
pad_: PadArg = 0,
|
|
43
|
-
print_width_: float | str | None = None,
|
|
44
|
-
print_height_: float | str | None = None,
|
|
45
|
-
dpu_: float = 1,
|
|
46
|
-
nsmap: dict[str | None, str] | None = None,
|
|
47
|
-
attrib: OptionalElemAttribMapping = None,
|
|
48
|
-
**attributes: ElemAttrib,
|
|
49
|
-
) -> EtreeElement:
|
|
50
|
-
"""Create svg root around BoundElements.
|
|
51
|
-
|
|
52
|
-
:param bounded: BoundingBox istances, BoundElement instances, PaddedText
|
|
53
|
-
instances, or any other EtreeElement instances. Anything that isn't a
|
|
54
|
-
bounding box or SupportsBounds will be ignored.
|
|
55
|
-
:param pad_: optionally increase viewBox by pad in all directions. Acceps a
|
|
56
|
-
single value or a tuple of values applied to (cycled over) top, right,
|
|
57
|
-
bottom, left. pad can be floats or dimension strings*
|
|
58
|
-
:param print_width_: optionally explicitly set unpadded width in units
|
|
59
|
-
(float) or a dimension string*
|
|
60
|
-
:param print_height_: optionally explicitly set unpadded height in units
|
|
61
|
-
(float) or a dimension string*
|
|
62
|
-
:param dpu_: dots per unit. Scale the output by this factor. This is
|
|
63
|
-
different from print_width_ and print_height_ in that dpu_ scales the
|
|
64
|
-
*padded* output.
|
|
65
|
-
:param nsmap: optionally pass a namespace map of your choosing
|
|
66
|
-
:param attrib: optionally pass additional attributes as a mapping instead of as
|
|
67
|
-
anonymous kwargs. This is useful for pleasing the linter when unpacking a
|
|
68
|
-
dictionary into a function call.
|
|
69
|
-
:param attributes: element attribute names and values
|
|
70
|
-
:return: root svg element
|
|
71
|
-
:raise ValueError: if no bounding boxes are found in bounded
|
|
72
|
-
"""
|
|
73
|
-
attributes.update(attrib or {})
|
|
74
|
-
bbox = bound.new_bbox_union(*bounded)
|
|
75
|
-
viewbox = _viewbox_args_from_bboxes(bbox)
|
|
76
|
-
return new_svg_root(
|
|
77
|
-
x_=viewbox["x_"],
|
|
78
|
-
y_=viewbox["y_"],
|
|
79
|
-
width_=viewbox["width_"],
|
|
80
|
-
height_=viewbox["height_"],
|
|
81
|
-
pad_=pad_,
|
|
82
|
-
print_width_=print_width_,
|
|
83
|
-
print_height_=print_height_,
|
|
84
|
-
dpu_=dpu_,
|
|
85
|
-
nsmap=nsmap,
|
|
86
|
-
attrib=attributes,
|
|
87
|
-
)
|
|
1
|
+
"""Build root elements in various ways.
|
|
2
|
+
|
|
3
|
+
:author: Shay Hill
|
|
4
|
+
:created: 2023-09-23
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
from svg_ultralight.bounding_boxes import bound_helpers as bound
|
|
12
|
+
from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
|
|
13
|
+
from svg_ultralight.main import new_svg_root
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from lxml.etree import (
|
|
17
|
+
_Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from svg_ultralight.attrib_hints import ElemAttrib, OptionalElemAttribMapping
|
|
21
|
+
from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
|
|
22
|
+
from svg_ultralight.layout import PadArg
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _viewbox_args_from_bboxes(*bboxes: BoundingBox) -> dict[str, float]:
|
|
26
|
+
"""Create x_, y_, width_, height_ new_svg_root arguments from bounding boxes.
|
|
27
|
+
|
|
28
|
+
:param bbox: bounding boxes to merge
|
|
29
|
+
:return: dict of new_svg_root arguments
|
|
30
|
+
"""
|
|
31
|
+
merged = BoundingBox.merged(*bboxes)
|
|
32
|
+
return {
|
|
33
|
+
"x_": merged.x,
|
|
34
|
+
"y_": merged.y,
|
|
35
|
+
"width_": merged.width,
|
|
36
|
+
"height_": merged.height,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def new_svg_root_around_bounds(
|
|
41
|
+
*bounded: SupportsBounds | EtreeElement,
|
|
42
|
+
pad_: PadArg = 0,
|
|
43
|
+
print_width_: float | str | None = None,
|
|
44
|
+
print_height_: float | str | None = None,
|
|
45
|
+
dpu_: float = 1,
|
|
46
|
+
nsmap: dict[str | None, str] | None = None,
|
|
47
|
+
attrib: OptionalElemAttribMapping = None,
|
|
48
|
+
**attributes: ElemAttrib,
|
|
49
|
+
) -> EtreeElement:
|
|
50
|
+
"""Create svg root around BoundElements.
|
|
51
|
+
|
|
52
|
+
:param bounded: BoundingBox istances, BoundElement instances, PaddedText
|
|
53
|
+
instances, or any other EtreeElement instances. Anything that isn't a
|
|
54
|
+
bounding box or SupportsBounds will be ignored.
|
|
55
|
+
:param pad_: optionally increase viewBox by pad in all directions. Acceps a
|
|
56
|
+
single value or a tuple of values applied to (cycled over) top, right,
|
|
57
|
+
bottom, left. pad can be floats or dimension strings*
|
|
58
|
+
:param print_width_: optionally explicitly set unpadded width in units
|
|
59
|
+
(float) or a dimension string*
|
|
60
|
+
:param print_height_: optionally explicitly set unpadded height in units
|
|
61
|
+
(float) or a dimension string*
|
|
62
|
+
:param dpu_: dots per unit. Scale the output by this factor. This is
|
|
63
|
+
different from print_width_ and print_height_ in that dpu_ scales the
|
|
64
|
+
*padded* output.
|
|
65
|
+
:param nsmap: optionally pass a namespace map of your choosing
|
|
66
|
+
:param attrib: optionally pass additional attributes as a mapping instead of as
|
|
67
|
+
anonymous kwargs. This is useful for pleasing the linter when unpacking a
|
|
68
|
+
dictionary into a function call.
|
|
69
|
+
:param attributes: element attribute names and values
|
|
70
|
+
:return: root svg element
|
|
71
|
+
:raise ValueError: if no bounding boxes are found in bounded
|
|
72
|
+
"""
|
|
73
|
+
attributes.update(attrib or {})
|
|
74
|
+
bbox = bound.new_bbox_union(*bounded)
|
|
75
|
+
viewbox = _viewbox_args_from_bboxes(bbox)
|
|
76
|
+
return new_svg_root(
|
|
77
|
+
x_=viewbox["x_"],
|
|
78
|
+
y_=viewbox["y_"],
|
|
79
|
+
width_=viewbox["width_"],
|
|
80
|
+
height_=viewbox["height_"],
|
|
81
|
+
pad_=pad_,
|
|
82
|
+
print_width_=print_width_,
|
|
83
|
+
print_height_=print_height_,
|
|
84
|
+
dpu_=dpu_,
|
|
85
|
+
nsmap=nsmap,
|
|
86
|
+
attrib=attributes,
|
|
87
|
+
)
|