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.

@@ -52,6 +52,7 @@ class SupportsBounds(Protocol):
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
  """Apply a transformation to the object."""
57
58
  ...
@@ -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 membersh and to provide access to cumulative
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
- self.bbox.transformation = mat_dot(tmat, self.bbox.transformation)
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(min_x, -max_y, max_x - min_x, max_y - min_y)
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(min_x, -max_y, max_x - min_x, max_y - min_y)
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 BoundingBox(*bbox.values())
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(elem: EtreeElement, matrix: _Matrix) -> EtreeElement:
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
- :param matrix: transformation matrix
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
- elem.attrib["transform"] = svg_matrix(mat_dot(matrix, current))
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: svg-ultralight
3
- Version: 0.51.0
3
+ Version: 0.52.1
4
4
  Summary: a sensible way to create svg files with Python
5
5
  Author: Shay Hill
6
6
  Author-email: Shay Hill <shay_public@hotmail.com>
@@ -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=zoJr7goYEbiVsr5Vl2RlqCsbyBe5RHZGrU0B5WMBRbY,4427
8
- svg_ultralight/bounding_boxes/type_bound_collection.py,sha256=vzZPJoUg4Joaj7nTl4VpDFFHihIoBfBNvu6IaIprYKM,2582
9
- svg_ultralight/bounding_boxes/type_bound_element.py,sha256=CdbL48NMauCX5qZGlJes3aYFZHyVE3rby99HN-Kr7GI,2147
10
- svg_ultralight/bounding_boxes/type_bounding_box.py,sha256=81tyPpCHxRH1CXELO_qSCtueCyHYWBeEJO_JIxpl88Q,13101
11
- svg_ultralight/bounding_boxes/type_padded_text.py,sha256=1IV0DGjxem8celN4GAT8l60fLYhJwsES3O4tkHG7v60,14248
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=9nSj8qjzbT3bEe2Qgr-Rtfzb6RyFFCiXHbvv4Oyfxw0,29332
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=fnPMdMQFgT6OEUIDwb_A7tvuILraPFW1jR9I1RaI1cA,4325
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.51.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
33
- svg_ultralight-0.51.0.dist-info/METADATA,sha256=qvOlGkyOA8KxGifWkMETlzsu--3Nf8qFCyqhet7VoyM,8691
34
- svg_ultralight-0.51.0.dist-info/RECORD,,
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,,