svg-ultralight 0.37.0__py3-none-any.whl → 0.39.0__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/bound_helpers.py +4 -11
- svg_ultralight/bounding_boxes/supports_bounds.py +4 -9
- svg_ultralight/bounding_boxes/type_bound_collection.py +2 -2
- svg_ultralight/bounding_boxes/type_bound_element.py +4 -5
- svg_ultralight/bounding_boxes/type_bounding_box.py +155 -262
- svg_ultralight/bounding_boxes/type_padded_text.py +65 -205
- svg_ultralight/constructors/new_element.py +3 -1
- svg_ultralight/inkscape.py +3 -1
- svg_ultralight/layout.py +22 -13
- svg_ultralight/main.py +12 -4
- svg_ultralight/metadata.py +1 -1
- svg_ultralight/query.py +72 -40
- svg_ultralight/root_elements.py +3 -1
- svg_ultralight/string_conversion.py +7 -3
- svg_ultralight/transformations.py +17 -9
- {svg_ultralight-0.37.0.dist-info → svg_ultralight-0.39.0.dist-info}/METADATA +5 -4
- svg_ultralight-0.39.0.dist-info/RECORD +29 -0
- {svg_ultralight-0.37.0.dist-info → svg_ultralight-0.39.0.dist-info}/WHEEL +1 -1
- svg_ultralight-0.37.0.dist-info/RECORD +0 -29
- {svg_ultralight-0.37.0.dist-info → svg_ultralight-0.39.0.dist-info}/top_level.txt +0 -0
|
@@ -12,7 +12,7 @@ There is a getter and setter for each of the four padding values. These *do not*
|
|
|
12
12
|
the text element. For instance, if you decrease the left padding, the left margin
|
|
13
13
|
will move, *not* the text element.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
_There is a getter and setter for each of lmargin, rmargin, baseline, and capline.
|
|
16
16
|
These *do* move the element, but do not scale it. For instance, if you move the
|
|
17
17
|
leftmargin to the left, the right margin (and the text element with it) will move to
|
|
18
18
|
the left.
|
|
@@ -66,16 +66,19 @@ from __future__ import annotations
|
|
|
66
66
|
|
|
67
67
|
from typing import TYPE_CHECKING
|
|
68
68
|
|
|
69
|
-
from svg_ultralight.bounding_boxes.
|
|
69
|
+
from svg_ultralight.bounding_boxes.type_bound_element import BoundElement
|
|
70
70
|
from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
|
|
71
|
+
from svg_ultralight.transformations import new_transformation_matrix, transform_element
|
|
71
72
|
|
|
72
73
|
if TYPE_CHECKING:
|
|
73
|
-
from lxml.etree import
|
|
74
|
+
from lxml.etree import (
|
|
75
|
+
_Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
|
|
76
|
+
)
|
|
74
77
|
|
|
75
78
|
_Matrix = tuple[float, float, float, float, float, float]
|
|
76
79
|
|
|
77
80
|
|
|
78
|
-
class PaddedText(
|
|
81
|
+
class PaddedText(BoundElement):
|
|
79
82
|
"""A line of text with a bounding box and padding."""
|
|
80
83
|
|
|
81
84
|
def __init__(
|
|
@@ -97,14 +100,14 @@ class PaddedText(SupportsBounds):
|
|
|
97
100
|
:param lpad: Left padding.
|
|
98
101
|
"""
|
|
99
102
|
self.elem = elem
|
|
100
|
-
self.
|
|
103
|
+
self.unpadded_bbox = bbox
|
|
101
104
|
self.base_tpad = tpad
|
|
102
105
|
self.rpad = rpad
|
|
103
106
|
self.base_bpad = bpad
|
|
104
107
|
self.lpad = lpad
|
|
105
108
|
|
|
106
109
|
@property
|
|
107
|
-
def
|
|
110
|
+
def bbox(self) -> BoundingBox:
|
|
108
111
|
"""Return a BoundingBox around the margins and cap/baseline.
|
|
109
112
|
|
|
110
113
|
:return: A BoundingBox around the margins and cap/baseline.
|
|
@@ -115,22 +118,28 @@ class PaddedText(SupportsBounds):
|
|
|
115
118
|
instance around multiple text elements (a <g> elem).
|
|
116
119
|
"""
|
|
117
120
|
return BoundingBox(
|
|
118
|
-
self.
|
|
121
|
+
self.x,
|
|
122
|
+
self.y,
|
|
123
|
+
self.width,
|
|
124
|
+
self.height,
|
|
125
|
+
self.unpadded_bbox.transformation,
|
|
119
126
|
)
|
|
120
127
|
|
|
121
|
-
@
|
|
122
|
-
def
|
|
123
|
-
"""
|
|
124
|
-
return self.bbox.transformation
|
|
128
|
+
@bbox.setter
|
|
129
|
+
def bbox(self, value: BoundingBox) -> None:
|
|
130
|
+
"""Set the bounding box of this PaddedText.
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
:param value: The new bounding box.
|
|
133
|
+
:effects: The text element is transformed to fit the new bounding box.
|
|
134
|
+
"""
|
|
135
|
+
msg = "Cannot set bbox of PaddedText, use transform() instead."
|
|
136
|
+
raise NotImplementedError(msg)
|
|
128
137
|
|
|
129
138
|
def transform(
|
|
130
139
|
self,
|
|
131
140
|
transformation: _Matrix | None = None,
|
|
132
141
|
*,
|
|
133
|
-
scale: float | None = None,
|
|
142
|
+
scale: tuple[float, float] | None = None,
|
|
134
143
|
dx: float | None = None,
|
|
135
144
|
dy: float | None = None,
|
|
136
145
|
):
|
|
@@ -141,8 +150,9 @@ class PaddedText(SupportsBounds):
|
|
|
141
150
|
:param dx: the x translation
|
|
142
151
|
:param dy: the y translation
|
|
143
152
|
"""
|
|
144
|
-
|
|
145
|
-
self.
|
|
153
|
+
tmat = new_transformation_matrix(transformation, scale=scale, dx=dx, dy=dy)
|
|
154
|
+
self.unpadded_bbox.transform(tmat)
|
|
155
|
+
_ = transform_element(self.elem, tmat)
|
|
146
156
|
|
|
147
157
|
@property
|
|
148
158
|
def tpad(self) -> float:
|
|
@@ -150,7 +160,7 @@ class PaddedText(SupportsBounds):
|
|
|
150
160
|
|
|
151
161
|
:return: The scaled top padding of this line of text.
|
|
152
162
|
"""
|
|
153
|
-
return self.base_tpad * self.
|
|
163
|
+
return self.base_tpad * self.unpadded_bbox.scale[1]
|
|
154
164
|
|
|
155
165
|
@tpad.setter
|
|
156
166
|
def tpad(self, value: float) -> None:
|
|
@@ -158,7 +168,7 @@ class PaddedText(SupportsBounds):
|
|
|
158
168
|
|
|
159
169
|
:param value: The new top padding.
|
|
160
170
|
"""
|
|
161
|
-
self.base_tpad = value / self.
|
|
171
|
+
self.base_tpad = value / self.unpadded_bbox.scale[1]
|
|
162
172
|
|
|
163
173
|
@property
|
|
164
174
|
def bpad(self) -> float:
|
|
@@ -166,7 +176,7 @@ class PaddedText(SupportsBounds):
|
|
|
166
176
|
|
|
167
177
|
:return: The scaled bottom padding of this line of text.
|
|
168
178
|
"""
|
|
169
|
-
return self.base_bpad * self.
|
|
179
|
+
return self.base_bpad * self.unpadded_bbox.scale[1]
|
|
170
180
|
|
|
171
181
|
@bpad.setter
|
|
172
182
|
def bpad(self, value: float) -> None:
|
|
@@ -174,82 +184,18 @@ class PaddedText(SupportsBounds):
|
|
|
174
184
|
|
|
175
185
|
:param value: The new bottom padding.
|
|
176
186
|
"""
|
|
177
|
-
self.base_bpad = value / self.
|
|
178
|
-
|
|
179
|
-
@property
|
|
180
|
-
def lmargin(self) -> float:
|
|
181
|
-
"""The left margin of this line of text.
|
|
182
|
-
|
|
183
|
-
:return: The left margin of this line of text.
|
|
184
|
-
"""
|
|
185
|
-
return self.bbox.x - self.lpad
|
|
186
|
-
|
|
187
|
-
@lmargin.setter
|
|
188
|
-
def lmargin(self, value: float) -> None:
|
|
189
|
-
"""Set the left margin of this line of text.
|
|
190
|
-
|
|
191
|
-
:param value: The left margin of this line of text.
|
|
192
|
-
"""
|
|
193
|
-
self.transform(dx=value + self.lpad - self.bbox.x)
|
|
194
|
-
|
|
195
|
-
@property
|
|
196
|
-
def rmargin(self) -> float:
|
|
197
|
-
"""The right margin of this line of text.
|
|
198
|
-
|
|
199
|
-
:return: The right margin of this line of text.
|
|
200
|
-
"""
|
|
201
|
-
return self.bbox.x2 + self.rpad
|
|
202
|
-
|
|
203
|
-
@rmargin.setter
|
|
204
|
-
def rmargin(self, value: float) -> None:
|
|
205
|
-
"""Set the right margin of this line of text.
|
|
206
|
-
|
|
207
|
-
:param value: The right margin of this line of text.
|
|
208
|
-
"""
|
|
209
|
-
self.transform(dx=value - self.rpad - self.bbox.x2)
|
|
210
|
-
|
|
211
|
-
@property
|
|
212
|
-
def capline(self) -> float:
|
|
213
|
-
"""The top of this line of text.
|
|
214
|
-
|
|
215
|
-
:return: The top of this line of text.
|
|
216
|
-
"""
|
|
217
|
-
return self.bbox.y - self.tpad
|
|
218
|
-
|
|
219
|
-
@capline.setter
|
|
220
|
-
def capline(self, value: float) -> None:
|
|
221
|
-
"""Set the top of this line of text.
|
|
222
|
-
|
|
223
|
-
:param value: The top of this line of text.
|
|
224
|
-
"""
|
|
225
|
-
self.transform(dy=value + self.tpad - self.bbox.y)
|
|
187
|
+
self.base_bpad = value / self.unpadded_bbox.scale[1]
|
|
226
188
|
|
|
227
189
|
@property
|
|
228
|
-
def
|
|
229
|
-
"""The bottom of this line of text.
|
|
230
|
-
|
|
231
|
-
:return: The bottom of this line of text.
|
|
232
|
-
"""
|
|
233
|
-
return self.bbox.y2 + self.bpad
|
|
234
|
-
|
|
235
|
-
@baseline.setter
|
|
236
|
-
def baseline(self, value: float) -> None:
|
|
237
|
-
"""Set the bottom of this line of text.
|
|
238
|
-
|
|
239
|
-
:param value: The bottom of this line of text.
|
|
240
|
-
"""
|
|
241
|
-
self.transform(dy=value - self.bpad - self.bbox.y2)
|
|
242
|
-
|
|
243
|
-
@property
|
|
244
|
-
def padded_width(self) -> float:
|
|
190
|
+
def width(self) -> float:
|
|
245
191
|
"""The width of this line of text with padding.
|
|
246
192
|
|
|
247
193
|
:return: The scaled width of this line of text with padding.
|
|
248
194
|
"""
|
|
249
|
-
return self.
|
|
195
|
+
return self.unpadded_bbox.width + self.lpad + self.rpad
|
|
250
196
|
|
|
251
|
-
@
|
|
252
|
-
def
|
|
197
|
+
@width.setter
|
|
198
|
+
def width(self, value: float) -> None:
|
|
253
199
|
"""Scale to padded_width = width without scaling padding.
|
|
254
200
|
|
|
255
201
|
:param width: The new width of this line of text.
|
|
@@ -261,27 +207,26 @@ class PaddedText(SupportsBounds):
|
|
|
261
207
|
baseline is near y2 (y + height) not y. So, we preserve baseline (alter y
|
|
262
208
|
*and* y2) when scaling.
|
|
263
209
|
"""
|
|
264
|
-
|
|
265
|
-
self.
|
|
266
|
-
self.
|
|
267
|
-
self._update_elem()
|
|
210
|
+
y2 = self.y2
|
|
211
|
+
self.unpadded_bbox.width = value - self.lpad - self.rpad
|
|
212
|
+
self.y2 = y2
|
|
268
213
|
|
|
269
214
|
@property
|
|
270
|
-
def
|
|
215
|
+
def height(self) -> float:
|
|
271
216
|
"""The height of this line of text with padding.
|
|
272
217
|
|
|
273
218
|
:return: The scaled height of this line of text with padding.
|
|
274
219
|
"""
|
|
275
|
-
return self.
|
|
220
|
+
return self.unpadded_bbox.height + self.tpad + self.bpad
|
|
276
221
|
|
|
277
|
-
@
|
|
278
|
-
def
|
|
279
|
-
"""Scale to
|
|
222
|
+
@height.setter
|
|
223
|
+
def height(self, value: float) -> None:
|
|
224
|
+
"""Scale to height without scaling padding.
|
|
280
225
|
|
|
281
226
|
:param height: The new height of this line of text.
|
|
282
227
|
:effects: the text_element bounding box is scaled to height - tpad - bpad.
|
|
283
228
|
"""
|
|
284
|
-
self.
|
|
229
|
+
self.width *= value / self.height
|
|
285
230
|
|
|
286
231
|
@property
|
|
287
232
|
def x(self) -> float:
|
|
@@ -289,15 +234,15 @@ class PaddedText(SupportsBounds):
|
|
|
289
234
|
|
|
290
235
|
:return: The left margin of this line of text.
|
|
291
236
|
"""
|
|
292
|
-
return self.
|
|
237
|
+
return self.unpadded_bbox.x - self.lpad
|
|
293
238
|
|
|
294
239
|
@x.setter
|
|
295
240
|
def x(self, value: float) -> None:
|
|
296
241
|
"""Set the left margin of this line of text.
|
|
297
242
|
|
|
298
|
-
:param value: The
|
|
243
|
+
:param value: The left margin of this line of text.
|
|
299
244
|
"""
|
|
300
|
-
self.
|
|
245
|
+
self.transform(dx=value + self.lpad - self.unpadded_bbox.x)
|
|
301
246
|
|
|
302
247
|
@property
|
|
303
248
|
def x2(self) -> float:
|
|
@@ -305,134 +250,49 @@ class PaddedText(SupportsBounds):
|
|
|
305
250
|
|
|
306
251
|
:return: The right margin of this line of text.
|
|
307
252
|
"""
|
|
308
|
-
return self.
|
|
253
|
+
return self.unpadded_bbox.x2 + self.rpad
|
|
309
254
|
|
|
310
255
|
@x2.setter
|
|
311
256
|
def x2(self, value: float) -> None:
|
|
312
257
|
"""Set the right margin of this line of text.
|
|
313
258
|
|
|
314
|
-
:param value: The
|
|
259
|
+
:param value: The right margin of this line of text.
|
|
315
260
|
"""
|
|
316
|
-
self.
|
|
261
|
+
self.transform(dx=value - self.rpad - self.unpadded_bbox.x2)
|
|
317
262
|
|
|
318
263
|
@property
|
|
319
264
|
def y(self) -> float:
|
|
320
|
-
"""The
|
|
265
|
+
"""The top of this line of text.
|
|
321
266
|
|
|
322
|
-
:return: The
|
|
267
|
+
:return: The top of this line of text.
|
|
323
268
|
"""
|
|
324
|
-
return self.
|
|
269
|
+
return self.unpadded_bbox.y - self.tpad
|
|
325
270
|
|
|
326
271
|
@y.setter
|
|
327
272
|
def y(self, value: float) -> None:
|
|
328
|
-
"""Set the
|
|
273
|
+
"""Set the top of this line of text.
|
|
329
274
|
|
|
330
|
-
:param value: The
|
|
275
|
+
:param value: The top of this line of text.
|
|
331
276
|
"""
|
|
332
|
-
self.
|
|
277
|
+
self.transform(dy=value + self.tpad - self.unpadded_bbox.y)
|
|
333
278
|
|
|
334
279
|
@property
|
|
335
280
|
def y2(self) -> float:
|
|
336
|
-
"""The
|
|
281
|
+
"""The bottom of this line of text.
|
|
337
282
|
|
|
338
|
-
:return: The
|
|
283
|
+
:return: The bottom of this line of text.
|
|
339
284
|
"""
|
|
340
|
-
return self.
|
|
285
|
+
return self.unpadded_bbox.y2 + self.bpad
|
|
341
286
|
|
|
342
287
|
@y2.setter
|
|
343
288
|
def y2(self, value: float) -> None:
|
|
344
|
-
"""Set the
|
|
345
|
-
|
|
346
|
-
:param value: The new baseline of this line of text.
|
|
347
|
-
"""
|
|
348
|
-
self.baseline = value
|
|
349
|
-
|
|
350
|
-
@property
|
|
351
|
-
def width(self) -> float:
|
|
352
|
-
"""The width of this line of text with padding.
|
|
353
|
-
|
|
354
|
-
:return: The scaled width of this line of text with padding.
|
|
355
|
-
"""
|
|
356
|
-
return self.padded_width
|
|
357
|
-
|
|
358
|
-
@width.setter
|
|
359
|
-
def width(self, value: float) -> None:
|
|
360
|
-
"""Scale to width without scaling padding.
|
|
361
|
-
|
|
362
|
-
:param value: The new width of this line of text.
|
|
363
|
-
:effects: the text_element bounding box is scaled to width - lpad - rpad.
|
|
364
|
-
|
|
365
|
-
Svg_Ultralight BoundingBoxes preserve x and y when scaling. This is
|
|
366
|
-
consistent with how rectangles, viewboxes, and anything else defined by x, y,
|
|
367
|
-
width, height behaves in SVG. This is unintuitive for text, because the
|
|
368
|
-
baseline is near y2 (y + height) not y. So, we preserve baseline (alter y
|
|
369
|
-
*and* y2) when scaling.
|
|
370
|
-
"""
|
|
371
|
-
baseline = self.baseline
|
|
372
|
-
self.padded_width = value
|
|
373
|
-
self.baseline = baseline
|
|
374
|
-
|
|
375
|
-
@property
|
|
376
|
-
def height(self) -> float:
|
|
377
|
-
"""The height of this line of text with padding.
|
|
378
|
-
|
|
379
|
-
:return: The scaled height of this line of text with padding.
|
|
380
|
-
"""
|
|
381
|
-
return self.padded_height
|
|
382
|
-
|
|
383
|
-
@height.setter
|
|
384
|
-
def height(self, value: float) -> None:
|
|
385
|
-
"""Scale to height without scaling padding.
|
|
386
|
-
|
|
387
|
-
:param value: The new height of this line of text.
|
|
388
|
-
:effects: the text_element bounding box is scaled to height - tpad - bpad.
|
|
389
|
-
"""
|
|
390
|
-
self.padded_height = value
|
|
391
|
-
|
|
392
|
-
@property
|
|
393
|
-
def cx(self) -> float:
|
|
394
|
-
"""The x coordinate of the center between margins.
|
|
395
|
-
|
|
396
|
-
:return: the x coordinate of the center between margins
|
|
397
|
-
"""
|
|
398
|
-
return self.lmargin + self.padded_width / 2
|
|
399
|
-
|
|
400
|
-
@cx.setter
|
|
401
|
-
def cx(self, value: float):
|
|
402
|
-
"""Set the x coordinate of the center between margins.
|
|
403
|
-
|
|
404
|
-
:param value: the new x coordinate of the center between margins
|
|
405
|
-
"""
|
|
406
|
-
self.lmargin = value - self.padded_width / 2
|
|
407
|
-
|
|
408
|
-
@property
|
|
409
|
-
def cy(self) -> float:
|
|
410
|
-
"""The y coordinate of the center between baseline and capline.
|
|
411
|
-
|
|
412
|
-
:return: the y coordinate of the center between baseline and capline
|
|
413
|
-
"""
|
|
414
|
-
return self.capline + self.padded_height / 2
|
|
415
|
-
|
|
416
|
-
@cy.setter
|
|
417
|
-
def cy(self, value: float):
|
|
418
|
-
"""Set the y coordinate of the center between baseline and capline.
|
|
419
|
-
|
|
420
|
-
:param value: the new y coordinate of the center between baseline and capline
|
|
421
|
-
"""
|
|
422
|
-
self.capline = value - self.padded_height / 2
|
|
423
|
-
|
|
424
|
-
@property
|
|
425
|
-
def scale(self) -> float:
|
|
426
|
-
"""The scale of the text element.
|
|
289
|
+
"""Set the bottom of this line of text.
|
|
427
290
|
|
|
428
|
-
:
|
|
291
|
+
:param value: The bottom of this line of text.
|
|
429
292
|
"""
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
@scale.setter
|
|
433
|
-
def scale(self, value: float):
|
|
434
|
-
"""Set the scale of the text element.
|
|
293
|
+
self.transform(dy=value - self.bpad - self.unpadded_bbox.y2)
|
|
435
294
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
295
|
+
lmargin = x
|
|
296
|
+
rmargin = x2
|
|
297
|
+
capline = y
|
|
298
|
+
baseline = y2
|
|
@@ -21,7 +21,9 @@ from svg_ultralight.string_conversion import set_attributes
|
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
23
23
|
from lxml.etree import QName
|
|
24
|
-
from lxml.etree import
|
|
24
|
+
from lxml.etree import (
|
|
25
|
+
_Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
|
|
26
|
+
)
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
def new_element(tag: str | QName, **attributes: str | float) -> EtreeElement:
|
svg_ultralight/inkscape.py
CHANGED
|
@@ -30,7 +30,9 @@ from lxml import etree
|
|
|
30
30
|
from svg_ultralight import main
|
|
31
31
|
|
|
32
32
|
if TYPE_CHECKING:
|
|
33
|
-
from lxml.etree import
|
|
33
|
+
from lxml.etree import (
|
|
34
|
+
_Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
|
|
35
|
+
)
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
def write_png_from_svg(
|
svg_ultralight/layout.py
CHANGED
|
@@ -144,11 +144,11 @@ def pad_and_scale(
|
|
|
144
144
|
"""Expand and scale the pad argument. If necessary, scale image.
|
|
145
145
|
|
|
146
146
|
:param viewbox: viewbox to pad (x, y, width height)
|
|
147
|
-
:param pad: padding to add around image, in user units or inches.
|
|
147
|
+
:param pad: padding to add around image, in user units or inches. If a
|
|
148
148
|
sequence, it should be (top, right, bottom, left). if a single float or
|
|
149
|
-
string, it will be applied to all sides.
|
|
150
|
-
then left and right.
|
|
151
|
-
|
|
149
|
+
string, it will be applied to all sides. If two floats, top and bottom
|
|
150
|
+
then left and right. If three floats, top, left and right, then bottom.
|
|
151
|
+
If four floats, top, right, bottom, left.
|
|
152
152
|
:param print_width: width of print area, in user units (float), a string
|
|
153
153
|
with a unit specifier (e.g., "452mm"), or just a unit specifier (e.g.,
|
|
154
154
|
"pt")
|
|
@@ -169,7 +169,7 @@ def pad_and_scale(
|
|
|
169
169
|
If the width and height *are* specified, the user units become whatever they
|
|
170
170
|
need to be to fit that requirement. For instance, if the viewbox width is 96
|
|
171
171
|
and the width argument is "1in", then the user units are *still* pixels,
|
|
172
|
-
because there are 96 pixels in an inch. If the viewbox
|
|
172
|
+
because there are 96 pixels in an inch. If the viewbox width is 2 and the
|
|
173
173
|
width argument is "1in", then the user units are 1/2 of an inch (i.e., 48
|
|
174
174
|
pixels) each, because there are 2 user units in an inch. If the viewbox
|
|
175
175
|
width is 3 and the width argument is "1yd", the each user unit is 1 foot.
|
|
@@ -195,17 +195,26 @@ def pad_and_scale(
|
|
|
195
195
|
the unit designators without changing the scale.
|
|
196
196
|
|
|
197
197
|
Print aspect ratio is ignored. Viewbox aspect ratio is preserved. For
|
|
198
|
-
instance,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
198
|
+
instance, if you created two images
|
|
199
|
+
|
|
200
|
+
* x_=0, y_=0, width_=1, height_=2, pad_="0.25in", print_width_="6in"
|
|
201
|
+
|
|
202
|
+
* x_=0, y_=0, width_=1, height_=2, pad_="0.25in", print_width_="12in"
|
|
203
|
+
|
|
204
|
+
... (note that the images only vary in print_width_), the first image would be
|
|
205
|
+
rendered at 6.5x12.5 inches and the second at 12.5x24.5 inches. The visible
|
|
206
|
+
content in the viewbox would be exactly twice as wide in the larger image, but
|
|
207
|
+
the padding would remain 0.25 in both images. Despite setting `print_width_` to
|
|
208
|
+
exactly 6 or 12 inches, you would not get an image exactly 6 or 12 inches wide.
|
|
209
|
+
Despite a viewbox aspect ratio of 1:2, you would not get an output image of
|
|
210
|
+
exactly 1:2. If you want to use padding and need a specific output image size or
|
|
211
|
+
aspect ratio, remember to subtract the padding width from your print_width or
|
|
212
|
+
print_height.
|
|
204
213
|
|
|
205
214
|
Scaling attributes are returned as a dictonary that can be "exploded" into
|
|
206
215
|
the element constructor, e.g., {"width": "12.5in", "height": "12.5in"}.
|
|
207
216
|
|
|
208
|
-
* If
|
|
217
|
+
* If neither a print_width nor print_height is specified, no scaling
|
|
209
218
|
attributes will be returned.
|
|
210
219
|
|
|
211
220
|
* If either is specified, both a width and height will be returned (even if
|
|
@@ -242,7 +251,7 @@ def pad_and_scale(
|
|
|
242
251
|
a 16" x 9" image with viwebox(0, 0, 14, 7), pad_="1in", print_width_="14in"
|
|
243
252
|
... then scale the printout with dpu_=2 to get a 32" x 18" image with the
|
|
244
253
|
same viewbox. This means the padding will be 2" on all sides, but the image
|
|
245
|
-
will be identical (just twice as
|
|
254
|
+
will be identical (just twice as wide and twice as high) as the 16" x 9" image.
|
|
246
255
|
"""
|
|
247
256
|
pads = expand_pad_arg(pad)
|
|
248
257
|
|
svg_ultralight/main.py
CHANGED
|
@@ -13,6 +13,7 @@ should work with all Inkscape versions. Please report any issues.
|
|
|
13
13
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
|
+
import sys
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
from typing import IO, TYPE_CHECKING
|
|
18
19
|
|
|
@@ -23,8 +24,15 @@ from svg_ultralight.layout import pad_and_scale
|
|
|
23
24
|
from svg_ultralight.nsmap import NSMAP
|
|
24
25
|
from svg_ultralight.string_conversion import get_viewBox_str, svg_tostring
|
|
25
26
|
|
|
27
|
+
if sys.version_info >= (3, 10):
|
|
28
|
+
from typing import TypeGuard
|
|
29
|
+
else:
|
|
30
|
+
from typing_extensions import TypeGuard
|
|
31
|
+
|
|
26
32
|
if TYPE_CHECKING:
|
|
27
|
-
from lxml.etree import
|
|
33
|
+
from lxml.etree import (
|
|
34
|
+
_Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
|
|
35
|
+
)
|
|
28
36
|
|
|
29
37
|
from svg_ultralight.layout import PadArg
|
|
30
38
|
|
|
@@ -38,7 +46,7 @@ def _is_four_floats(objs: tuple[object, ...]) -> bool:
|
|
|
38
46
|
return len(objs) == 4 and all(isinstance(x, (float, int)) for x in objs)
|
|
39
47
|
|
|
40
48
|
|
|
41
|
-
def _is_io_bytes(obj: object) ->
|
|
49
|
+
def _is_io_bytes(obj: object) -> TypeGuard[IO[bytes]]:
|
|
42
50
|
"""Determine if an object is file-like.
|
|
43
51
|
|
|
44
52
|
:param obj: object
|
|
@@ -172,8 +180,8 @@ def write_svg(
|
|
|
172
180
|
svg_contents = svg_tostring(root, **tostring_kwargs)
|
|
173
181
|
|
|
174
182
|
if _is_io_bytes(svg):
|
|
175
|
-
_ = svg.write(svg_contents)
|
|
176
|
-
return svg.name
|
|
183
|
+
_ = svg.write(svg_contents)
|
|
184
|
+
return svg.name
|
|
177
185
|
if isinstance(svg, (Path, str)):
|
|
178
186
|
with Path(svg).open("wb") as svg_file:
|
|
179
187
|
_ = svg_file.write(svg_contents)
|
svg_ultralight/metadata.py
CHANGED
|
@@ -9,7 +9,7 @@ fields.
|
|
|
9
9
|
|
|
10
10
|
import warnings
|
|
11
11
|
|
|
12
|
-
from lxml.etree import _Element as EtreeElement #
|
|
12
|
+
from lxml.etree import _Element as EtreeElement # pyright: ignore[reportPrivateUsage]
|
|
13
13
|
|
|
14
14
|
from svg_ultralight.constructors.new_element import new_element, new_sub_element
|
|
15
15
|
from svg_ultralight.nsmap import new_qname
|