svg-ultralight 0.51.0__py3-none-any.whl → 0.52.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/bounding_boxes/supports_bounds.py +1 -0
- svg_ultralight/bounding_boxes/type_bound_collection.py +6 -3
- svg_ultralight/bounding_boxes/type_bound_element.py +5 -2
- svg_ultralight/bounding_boxes/type_bounding_box.py +7 -1
- svg_ultralight/bounding_boxes/type_padded_text.py +17 -3
- svg_ultralight/font_tools/font_info.py +15 -3
- svg_ultralight/transformations.py +15 -3
- {svg_ultralight-0.51.0.dist-info → svg_ultralight-0.52.1.dist-info}/METADATA +1 -1
- {svg_ultralight-0.51.0.dist-info → svg_ultralight-0.52.1.dist-info}/RECORD +10 -10
- {svg_ultralight-0.51.0.dist-info → svg_ultralight-0.52.1.dist-info}/WHEEL +0 -0
|
@@ -47,6 +47,7 @@ class BoundCollection(HasBoundingBox):
|
|
|
47
47
|
scale: tuple[float, float] | float | None = None,
|
|
48
48
|
dx: float | None = None,
|
|
49
49
|
dy: float | None = None,
|
|
50
|
+
reverse: bool = False,
|
|
50
51
|
) -> None:
|
|
51
52
|
"""Transform each bound element in self.blems.
|
|
52
53
|
|
|
@@ -54,9 +55,11 @@ class BoundCollection(HasBoundingBox):
|
|
|
54
55
|
:param scale: optional scale factor
|
|
55
56
|
:param dx: optional x translation
|
|
56
57
|
:param dy: optional y translation
|
|
58
|
+
:param reverse: Transform the element as if it were in a <g> element
|
|
59
|
+
transformed by tmat.
|
|
57
60
|
|
|
58
61
|
Keep track of all compounding transformations in order to have a value for
|
|
59
|
-
self.scale (required for
|
|
62
|
+
self.scale (required for members and to provide access to cumulative
|
|
60
63
|
transforms should this be useful for any reason. This means all
|
|
61
64
|
transformations must be applied to two bounding boxes: a persistant bbox to
|
|
62
65
|
keep track of the scale property and a temporary bbox to isolate each
|
|
@@ -66,6 +69,6 @@ class BoundCollection(HasBoundingBox):
|
|
|
66
69
|
self.bbox.transform(tmat)
|
|
67
70
|
for blem in self.blems:
|
|
68
71
|
if isinstance(blem, EtreeElement):
|
|
69
|
-
_ = transform_element(blem, tmat)
|
|
72
|
+
_ = transform_element(blem, tmat, reverse=reverse)
|
|
70
73
|
else:
|
|
71
|
-
blem.transform(tmat)
|
|
74
|
+
blem.transform(tmat, reverse=reverse)
|
|
@@ -52,6 +52,7 @@ class BoundElement(HasBoundingBox):
|
|
|
52
52
|
scale: tuple[float, float] | float | None = None,
|
|
53
53
|
dx: float | None = None,
|
|
54
54
|
dy: float | None = None,
|
|
55
|
+
reverse: bool = False,
|
|
55
56
|
) -> None:
|
|
56
57
|
"""Transform the element and bounding box.
|
|
57
58
|
|
|
@@ -59,7 +60,9 @@ class BoundElement(HasBoundingBox):
|
|
|
59
60
|
:param scale: a scaling factor
|
|
60
61
|
:param dx: the x translation
|
|
61
62
|
:param dy: the y translation
|
|
63
|
+
:param reverse: Transform the element as if it were in a <g> element
|
|
64
|
+
transformed by tmat.
|
|
62
65
|
"""
|
|
63
66
|
tmat = new_transformation_matrix(transformation, scale=scale, dx=dx, dy=dy)
|
|
64
|
-
self.bbox.transform(tmat)
|
|
65
|
-
_ = transform_element(self.elem, tmat)
|
|
67
|
+
self.bbox.transform(tmat, reverse=reverse)
|
|
68
|
+
_ = transform_element(self.elem, tmat, reverse=reverse)
|
|
@@ -78,6 +78,7 @@ class HasBoundingBox(SupportsBounds):
|
|
|
78
78
|
scale: tuple[float, float] | float | None = None,
|
|
79
79
|
dx: float | None = None,
|
|
80
80
|
dy: float | None = None,
|
|
81
|
+
reverse: bool = False,
|
|
81
82
|
) -> None:
|
|
82
83
|
"""Transform the bounding box by updating the transformation attribute.
|
|
83
84
|
|
|
@@ -85,6 +86,8 @@ class HasBoundingBox(SupportsBounds):
|
|
|
85
86
|
:param scale: scale factor
|
|
86
87
|
:param dx: x translation
|
|
87
88
|
:param dy: y translation
|
|
89
|
+
:param reverse: Transform the element as if it were in a <g> element
|
|
90
|
+
transformed by tmat.
|
|
88
91
|
|
|
89
92
|
All parameters are optional. Scale, dx, and dy are optional and applied after
|
|
90
93
|
the transformation matrix if both are given. This shouldn't be necessary in
|
|
@@ -94,7 +97,10 @@ class HasBoundingBox(SupportsBounds):
|
|
|
94
97
|
when applying a transformation from another bounding box instance.
|
|
95
98
|
"""
|
|
96
99
|
tmat = new_transformation_matrix(transformation, scale=scale, dx=dx, dy=dy)
|
|
97
|
-
|
|
100
|
+
if reverse:
|
|
101
|
+
self.bbox.transformation = mat_dot(self.bbox.transformation, tmat)
|
|
102
|
+
else:
|
|
103
|
+
self.bbox.transformation = mat_dot(tmat, self.bbox.transformation)
|
|
98
104
|
|
|
99
105
|
@property
|
|
100
106
|
def scale(self) -> tuple[float, float]:
|
|
@@ -64,6 +64,7 @@ enough to lay out text on a business card.
|
|
|
64
64
|
|
|
65
65
|
from __future__ import annotations
|
|
66
66
|
|
|
67
|
+
import copy
|
|
67
68
|
import math
|
|
68
69
|
from typing import TYPE_CHECKING
|
|
69
70
|
|
|
@@ -112,13 +113,23 @@ class PaddedText(BoundElement):
|
|
|
112
113
|
:param lpad: Left padding.
|
|
113
114
|
"""
|
|
114
115
|
self.elem = elem
|
|
115
|
-
self.unpadded_bbox = bbox
|
|
116
|
+
self.unpadded_bbox = copy.copy(bbox)
|
|
116
117
|
self.base_tpad = tpad
|
|
117
118
|
self.rpad = rpad
|
|
118
119
|
self.base_bpad = bpad
|
|
119
120
|
self.lpad = lpad
|
|
120
121
|
self._line_gap = line_gap
|
|
121
122
|
|
|
123
|
+
@property
|
|
124
|
+
def tbox(self) -> BoundingBox:
|
|
125
|
+
"""Return the unpadded BoundingBox around the text element.
|
|
126
|
+
|
|
127
|
+
Tight bbox or True bbox. An alias for unpadded_bbox.
|
|
128
|
+
|
|
129
|
+
:return: The unpadded BoundingBox around the text element.
|
|
130
|
+
"""
|
|
131
|
+
return self.unpadded_bbox
|
|
132
|
+
|
|
122
133
|
@property
|
|
123
134
|
def bbox(self) -> BoundingBox:
|
|
124
135
|
"""Return a BoundingBox around the margins and cap/baseline.
|
|
@@ -154,6 +165,7 @@ class PaddedText(BoundElement):
|
|
|
154
165
|
scale: tuple[float, float] | float | None = None,
|
|
155
166
|
dx: float | None = None,
|
|
156
167
|
dy: float | None = None,
|
|
168
|
+
reverse: bool = False,
|
|
157
169
|
) -> None:
|
|
158
170
|
"""Transform the element and bounding box.
|
|
159
171
|
|
|
@@ -161,10 +173,12 @@ class PaddedText(BoundElement):
|
|
|
161
173
|
:param scale: a scaling factor
|
|
162
174
|
:param dx: the x translation
|
|
163
175
|
:param dy: the y translation
|
|
176
|
+
:param reverse: Transform the element as if it were in a <g> element
|
|
177
|
+
transformed by tmat.
|
|
164
178
|
"""
|
|
165
179
|
tmat = new_transformation_matrix(transformation, scale=scale, dx=dx, dy=dy)
|
|
166
|
-
self.unpadded_bbox.transform(tmat)
|
|
167
|
-
_ = transform_element(self.elem, tmat)
|
|
180
|
+
self.unpadded_bbox.transform(tmat, reverse=reverse)
|
|
181
|
+
_ = transform_element(self.elem, tmat, reverse=reverse)
|
|
168
182
|
|
|
169
183
|
@property
|
|
170
184
|
def line_gap(self) -> float:
|
|
@@ -425,7 +425,13 @@ class FTFontInfo:
|
|
|
425
425
|
coordinates (+y is down).
|
|
426
426
|
"""
|
|
427
427
|
min_x, min_y, max_x, max_y = self.get_char_bounds(char)
|
|
428
|
-
return BoundingBox(
|
|
428
|
+
return BoundingBox(
|
|
429
|
+
min_x,
|
|
430
|
+
min_y,
|
|
431
|
+
max_x - min_x,
|
|
432
|
+
max_y - min_y,
|
|
433
|
+
transformation=(1, 0, 0, -1, 0, 0),
|
|
434
|
+
)
|
|
429
435
|
|
|
430
436
|
def get_text_bounds(self, text: str) -> tuple[int, int, int, int]:
|
|
431
437
|
"""Return bounds of a string as xmin, ymin, xmax, ymax.
|
|
@@ -484,7 +490,13 @@ class FTFontInfo:
|
|
|
484
490
|
coordinates (+y is down).
|
|
485
491
|
"""
|
|
486
492
|
min_x, min_y, max_x, max_y = self.get_text_bounds(text)
|
|
487
|
-
return BoundingBox(
|
|
493
|
+
return BoundingBox(
|
|
494
|
+
min_x,
|
|
495
|
+
min_y,
|
|
496
|
+
max_x - min_x,
|
|
497
|
+
max_y - min_y,
|
|
498
|
+
transformation=(1, 0, 0, -1, 0, 0),
|
|
499
|
+
)
|
|
488
500
|
|
|
489
501
|
def get_lsb(self, char: str) -> float:
|
|
490
502
|
"""Return the left side bearing of a character."""
|
|
@@ -567,7 +579,7 @@ class FTTextInfo:
|
|
|
567
579
|
"""
|
|
568
580
|
bbox = self.font.get_text_bbox(self.text)
|
|
569
581
|
bbox.transform(scale=self.scale)
|
|
570
|
-
return
|
|
582
|
+
return bbox
|
|
571
583
|
|
|
572
584
|
@property
|
|
573
585
|
def ascent(self) -> float:
|
|
@@ -129,12 +129,24 @@ def new_transformation_matrix(
|
|
|
129
129
|
return mat_dot((float(scale_x), 0, 0, float(scale_y), dx, dy), transformation)
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
def transform_element(
|
|
132
|
+
def transform_element(
|
|
133
|
+
elem: EtreeElement, matrix: _Matrix, *, reverse: bool = False
|
|
134
|
+
) -> EtreeElement:
|
|
133
135
|
"""Apply a transformation matrix to an svg element.
|
|
134
136
|
|
|
135
137
|
:param elem: svg element
|
|
136
|
-
:
|
|
138
|
+
:par m matrix: transformation matrix
|
|
139
|
+
|
|
140
|
+
:param reverse: If you have a transformation matrix, A, and wish to apply an
|
|
141
|
+
additional transform, B, the result is B @ A. This is how an element can be
|
|
142
|
+
cumulatively transformed in svg.
|
|
143
|
+
|
|
144
|
+
If the element is transformed by A and is a part of a GROUP transformed by B,
|
|
145
|
+
then the result is the reverse: A @ B.
|
|
137
146
|
"""
|
|
138
147
|
current = get_transform_matrix(elem)
|
|
139
|
-
|
|
148
|
+
if reverse:
|
|
149
|
+
elem.attrib["transform"] = svg_matrix(mat_dot(current, matrix))
|
|
150
|
+
else:
|
|
151
|
+
elem.attrib["transform"] = svg_matrix(mat_dot(matrix, current))
|
|
140
152
|
return elem
|
|
@@ -4,16 +4,16 @@ svg_ultralight/attrib_hints.py,sha256=_p85b77mcmj15IUnsDtgbYJ3FFd-Q1qM2OERv2UEZ2
|
|
|
4
4
|
svg_ultralight/bounding_boxes/__init__.py,sha256=YNCwgN-Ja2MFoCxIYxC3KZTCx_gFvPfRQ-8zBR5Q9mk,73
|
|
5
5
|
svg_ultralight/bounding_boxes/bound_helpers.py,sha256=o_NlH3bBU6lvn8KPTvp7hrEDb5OLqwO3t-gc51d44Rk,6583
|
|
6
6
|
svg_ultralight/bounding_boxes/padded_text_initializers.py,sha256=7LD7VzmDSaNA2S9QTW0sNzMwLpjjReWGV0e5f4uglk8,10002
|
|
7
|
-
svg_ultralight/bounding_boxes/supports_bounds.py,sha256=
|
|
8
|
-
svg_ultralight/bounding_boxes/type_bound_collection.py,sha256=
|
|
9
|
-
svg_ultralight/bounding_boxes/type_bound_element.py,sha256=
|
|
10
|
-
svg_ultralight/bounding_boxes/type_bounding_box.py,sha256=
|
|
11
|
-
svg_ultralight/bounding_boxes/type_padded_text.py,sha256=
|
|
7
|
+
svg_ultralight/bounding_boxes/supports_bounds.py,sha256=8rIklGICIx-DXELN7FjDwrzOi8iUrlstGrCIuN9ew3o,4458
|
|
8
|
+
svg_ultralight/bounding_boxes/type_bound_collection.py,sha256=ct8BLjqyHSCNhOGG0eYuubdOajI2KVo1nbTP3JxXZ00,2756
|
|
9
|
+
svg_ultralight/bounding_boxes/type_bound_element.py,sha256=gXsHCSJ6lxIGODm1oJ5yYAPzuIi7NkBIIzD_GX-cgo8,2322
|
|
10
|
+
svg_ultralight/bounding_boxes/type_bounding_box.py,sha256=r3XcdW_U8VvRauylw54aMwPsmC6A3HY72rz_sTcd1Uo,13359
|
|
11
|
+
svg_ultralight/bounding_boxes/type_padded_text.py,sha256=LXVsdCU7j_TzVEx652WKQLICFeYn_Zqjw6KCP6p1nzo,14740
|
|
12
12
|
svg_ultralight/constructors/__init__.py,sha256=fb-A50G3YTZNMQXpxcCl_QAcfssS0Us065_kdJRybDQ,313
|
|
13
13
|
svg_ultralight/constructors/new_element.py,sha256=hVQG7WBHQoTUmGiZNtVadGOitdTFBrHOQeVKKVOWGaA,3526
|
|
14
14
|
svg_ultralight/font_tools/__init__.py,sha256=b_VSvk5aODzS2wv48EMU2sey_mxq1o1SL8ecWTdy4kc,78
|
|
15
15
|
svg_ultralight/font_tools/comp_results.py,sha256=KR6RtVGWjGGfHX2d_-XRx_Jr9CQ36kPbQxLVK1yzgTI,10421
|
|
16
|
-
svg_ultralight/font_tools/font_info.py,sha256=
|
|
16
|
+
svg_ultralight/font_tools/font_info.py,sha256=RkxhxMdhuIDNDn8OUfEOTRPf9Y2PoYdxoBRFp70KQes,29521
|
|
17
17
|
svg_ultralight/image_ops.py,sha256=cwR038ECUuiceIrk-9Peh5Ijp4tzjuaV5Y1cvYOt4TI,5454
|
|
18
18
|
svg_ultralight/inkscape.py,sha256=_aQ42ZQ1JP9TFdHmtxgCRsXvxfZPpdZWTGKEea9BgIU,9336
|
|
19
19
|
svg_ultralight/layout.py,sha256=yiTAYtSsYywdCObIdjkK3A4fiEYLNPqD3BOQKxfj6gQ,12514
|
|
@@ -27,8 +27,8 @@ svg_ultralight/root_elements.py,sha256=N4BBO1j2iUDIGbk70FRrtfElZo0AG-3Olqugxz7LD
|
|
|
27
27
|
svg_ultralight/string_conversion.py,sha256=pzqkbGb-wXdhGd8ojEx4Hy-HBCC8fOfcloaLrNMh8TM,8607
|
|
28
28
|
svg_ultralight/strings/__init__.py,sha256=iaRwr9AF9bPDkG3XvgGRSf8JPAS2GQ8ds9yCNpPN4ng,365
|
|
29
29
|
svg_ultralight/strings/svg_strings.py,sha256=XlXQ5RqueGrROXBI4VzR2cK7e1NdNhYx5S84bgyqFUQ,3132
|
|
30
|
-
svg_ultralight/transformations.py,sha256=
|
|
30
|
+
svg_ultralight/transformations.py,sha256=YyhehH0Hlui2U9t7hjwgHgRyHzUR7UCMSSo-G85J-bo,4784
|
|
31
31
|
svg_ultralight/unit_conversion.py,sha256=Y32GZ5TLkvjDHM2kBw52M8ZxDNlpVSlDkSdRa1S_X-A,8985
|
|
32
|
-
svg_ultralight-0.
|
|
33
|
-
svg_ultralight-0.
|
|
34
|
-
svg_ultralight-0.
|
|
32
|
+
svg_ultralight-0.52.1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
33
|
+
svg_ultralight-0.52.1.dist-info/METADATA,sha256=HZfZfYDByPXr1IUnuTRSThw4fZdYPQJYrFKrrZvybvg,8691
|
|
34
|
+
svg_ultralight-0.52.1.dist-info/RECORD,,
|
|
File without changes
|