svg-ultralight 0.40.0__py3-none-any.whl → 0.41.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.

@@ -30,6 +30,7 @@ from svg_ultralight.constructors.new_element import (
30
30
  new_sub_element,
31
31
  update_element,
32
32
  )
33
+ from svg_ultralight.font_tools.comp_results import check_font_tools_alignment
33
34
  from svg_ultralight.inkscape import (
34
35
  write_pdf,
35
36
  write_pdf_from_svg,
@@ -67,6 +68,7 @@ __all__ = [
67
68
  "PaddedText",
68
69
  "SupportsBounds",
69
70
  "bbox_dict",
71
+ "check_font_tools_alignment",
70
72
  "clear_svg_ultralight_cache",
71
73
  "cut_bbox",
72
74
  "deepcopy_element",
@@ -17,7 +17,6 @@ Three variants:
17
17
  from __future__ import annotations
18
18
 
19
19
  from copy import deepcopy
20
- from pathlib import Path
21
20
  from typing import TYPE_CHECKING
22
21
 
23
22
  from svg_ultralight.bounding_boxes.type_padded_text import PaddedText
@@ -29,7 +28,6 @@ from svg_ultralight.font_tools.font_info import (
29
28
  from svg_ultralight.font_tools.globs import DEFAULT_FONT_SIZE
30
29
  from svg_ultralight.query import get_bounding_boxes
31
30
  from svg_ultralight.string_conversion import (
32
- encode_to_css_class_name,
33
31
  format_attr_dict,
34
32
  format_number,
35
33
  )
@@ -123,8 +121,8 @@ def pad_text_ft(
123
121
  :return: a PaddedText instance with a line_gap defined.
124
122
  """
125
123
  attributes_ = format_attr_dict(**attributes)
124
+ attributes_.update(get_svg_font_attributes(font))
126
125
  attributes_["font-size"] = attributes_.get("font-size", format_number(font_size))
127
- attributes_["class"] = encode_to_css_class_name(Path(font).name)
128
126
 
129
127
  elem = new_element("text", text=text, **attributes_)
130
128
  info = get_padded_text_info(
@@ -24,16 +24,16 @@ import sys
24
24
  from pathlib import Path
25
25
  from typing import TYPE_CHECKING
26
26
 
27
- from svg_ultralight import new_bbox_rect, new_svg_root_around_bounds, pad_bbox
27
+ from svg_ultralight.bounding_boxes.bound_helpers import new_bbox_rect, pad_bbox
28
28
  from svg_ultralight.bounding_boxes.padded_text_initializers import (
29
29
  DEFAULT_Y_BOUNDS_REFERENCE,
30
30
  pad_text,
31
31
  pad_text_ft,
32
32
  )
33
33
  from svg_ultralight.constructors import new_element
34
- from svg_ultralight.font_tools.font_css import add_svg_font_class
35
34
  from svg_ultralight.font_tools.font_info import get_svg_font_attributes
36
35
  from svg_ultralight.main import write_svg
36
+ from svg_ultralight.root_elements import new_svg_root_around_bounds
37
37
 
38
38
  if TYPE_CHECKING:
39
39
  import os
@@ -214,7 +214,6 @@ def draw_comparison(
214
214
  )
215
215
 
216
216
  root = new_svg_root_around_bounds(pad_bbox(padded_pt.bbox, 10))
217
- _ = add_svg_font_class(root, font)
218
217
  root.append(
219
218
  new_bbox_rect(
220
219
  padded_pt.unpadded_bbox, fill="none", stroke_width=0.07, stroke="red"
@@ -383,7 +383,7 @@ class FTTextInfo:
383
383
  @property
384
384
  def bpad(self) -> float:
385
385
  """Return the bottom padding for the text."""
386
- return self.descent - self.bbox.y2
386
+ return -self.descent - self.bbox.y2
387
387
 
388
388
  @property
389
389
  def lpad(self) -> float:
@@ -433,8 +433,8 @@ def get_padded_text_info(
433
433
  :param font_size: the font size to use.
434
434
  :param ascent: the ascent of the font. If not provided, it will be calculated
435
435
  from the font file.
436
- :param descent: the descent of the font. If not provided, it will be calculated
437
- from the font file.
436
+ :param descent: the descent of the font, usually a negative number. If not
437
+ provided, it will be calculated from the font file.
438
438
  :param y_bounds_reference: optional character or string to use as a reference
439
439
  for the ascent and descent. If provided, the ascent and descent will be the y
440
440
  extents of the capline reference. This argument is provided to mimic the
@@ -447,7 +447,7 @@ def get_padded_text_info(
447
447
  if y_bounds_reference:
448
448
  capline_info = FTTextInfo(font_info, y_bounds_reference, font_size)
449
449
  ascent = -capline_info.bbox.y
450
- descent = capline_info.bbox.y2
450
+ descent = -capline_info.bbox.y2
451
451
 
452
452
  return FTTextInfo(font_info, text, font_size, ascent, descent)
453
453
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: svg-ultralight
3
- Version: 0.40.0
3
+ Version: 0.41.0
4
4
  Summary: a sensible way to create svg files with Python
5
5
  Author-email: Shay Hill <shay_public@hotmail.com>
6
6
  License: MIT
@@ -1,4 +1,4 @@
1
- svg_ultralight/__init__.py,sha256=vINKVO2LVeGHBpD18mSWGC4qh-eS4ULk9JoGZSBuYoU,2705
1
+ svg_ultralight/__init__.py,sha256=A398qxoBmywPj3WR2sLgxhctsQZGgk_Dwd8jUIB87dU,2819
2
2
  svg_ultralight/animate.py,sha256=SMcQkeWAP9dD08Iyzy9qGG8Qk1p-14WfrB7WSN8Pj_4,1133
3
3
  svg_ultralight/image_ops.py,sha256=6V9YkxnhZCBw_hbVyY0uxDj0pZgiEWBSGRuPuOYKY4w,4694
4
4
  svg_ultralight/inkscape.py,sha256=ySCxWnQwEt1sosa1b4mEkR-ugpfoAeg9gs1OLPS69iI,9597
@@ -14,7 +14,7 @@ svg_ultralight/transformations.py,sha256=T3vSxcTWOwWnwu3OF610LHMbKScUIVWICUAvru5
14
14
  svg_ultralight/unit_conversion.py,sha256=g07nhzXdjPvGcJmkhLdFbeDLrSmbI8uFoVgPo7G62Bg,9258
15
15
  svg_ultralight/bounding_boxes/__init__.py,sha256=qUEn3r4s-1QNHaguhWhhaNfdP4tl_B6YEqxtiTFuzhQ,78
16
16
  svg_ultralight/bounding_boxes/bound_helpers.py,sha256=LFkVsdYFKYCnEL6vLvEa_5cfu8D44ZGYeEEb7_0MnC0,7146
17
- svg_ultralight/bounding_boxes/padded_text_initializers.py,sha256=ZR5IsRKuH8beU0Qe2aVldmWXwH4aji003uxU353ulFg,7611
17
+ svg_ultralight/bounding_boxes/padded_text_initializers.py,sha256=fce6gLBAX7Q0L5t8ECwyfvnelTqZRVCPex8TnV7mIv8,7539
18
18
  svg_ultralight/bounding_boxes/supports_bounds.py,sha256=T7LGse58fDBgmlzupSC63C1ZMXjFbyzBTsTUaqD_4Sw,4513
19
19
  svg_ultralight/bounding_boxes/type_bound_collection.py,sha256=NAEpqo9H9ewhuLcOmBnMWUE0zQ1t4bvckovgvWy6hIo,2645
20
20
  svg_ultralight/bounding_boxes/type_bound_element.py,sha256=Sc-R0uXkb0aS8-OcyM5pDukKhFUka0G6KCp6LcYDcIU,2204
@@ -23,13 +23,12 @@ svg_ultralight/bounding_boxes/type_padded_text.py,sha256=WNIoqC9pfB8g_00P6RHcBdN
23
23
  svg_ultralight/constructors/__init__.py,sha256=XLOInLhzMERWNnFAs-itMs-OZrBOpvQthZJ2T5duqBE,327
24
24
  svg_ultralight/constructors/new_element.py,sha256=hRUW2hR_BTkthEqPClYV7-IeFe9iv2zwb6ehp1k1xDk,3475
25
25
  svg_ultralight/font_tools/__init__.py,sha256=NX3C0vvoB-G4S-h1f0NLWePjYAMMR37D1cl_G4WBjHc,83
26
- svg_ultralight/font_tools/comp_results.py,sha256=gB1RHIHcltbOqWZ0s4xCRKEIMob7MWgPWjKv5hA7B8Q,10481
27
- svg_ultralight/font_tools/font_css.py,sha256=oKChLEwE18q-rKrt7hEkpBzGQBp8u9VWFxPpIKH67o4,2780
28
- svg_ultralight/font_tools/font_info.py,sha256=8bXdsbIY2rbZ3Q1UnxR3B4nPf31MZivS40mEOcCsb44,20849
26
+ svg_ultralight/font_tools/comp_results.py,sha256=iEDbExO3D7ffo0NZxrqf-WjtzUCJZbdHmqwjjac4laY,10444
27
+ svg_ultralight/font_tools/font_info.py,sha256=00iNrJwWH2-de9CbaG1TqulRFmp_3aOyjRAlqOpT0II,20878
29
28
  svg_ultralight/font_tools/globs.py,sha256=JdrrGMqDtD4WcY7YGUWV43DUW63RVev-x9vWqsQUhxU,119
30
29
  svg_ultralight/strings/__init__.py,sha256=BMGhF1pulscIgkiYvZLr6kPRR0L4lW0jUNFxkul4_EM,295
31
30
  svg_ultralight/strings/svg_strings.py,sha256=FQNxNmMkR2M-gCFo_woQKXLgCHi3ncUlRMiaRR_a9nQ,1978
32
- svg_ultralight-0.40.0.dist-info/METADATA,sha256=hUDb0ZUHgfMWRmLELiaw9XW55FtZlFV0CF5f36S4Ms8,9022
33
- svg_ultralight-0.40.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
- svg_ultralight-0.40.0.dist-info/top_level.txt,sha256=se-6yqM_0Yg5orJKvKWdjQZ4iR4G_EjhL7oRgju-fdY,15
35
- svg_ultralight-0.40.0.dist-info/RECORD,,
31
+ svg_ultralight-0.41.0.dist-info/METADATA,sha256=jJ9sHbqg4zJ3WcCuAMbiGb69FEtUcpZappC5LeZYl3Y,9022
32
+ svg_ultralight-0.41.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
+ svg_ultralight-0.41.0.dist-info/top_level.txt,sha256=se-6yqM_0Yg5orJKvKWdjQZ4iR4G_EjhL7oRgju-fdY,15
34
+ svg_ultralight-0.41.0.dist-info/RECORD,,
@@ -1,82 +0,0 @@
1
- """Link local fonts as css in an svg file.
2
-
3
- :author: Shay Hill
4
- :created: 2025-06-04
5
- """
6
-
7
- # pyright: reportUnknownMemberType = false
8
- # pyright: reportAttributeAccessIssue = false
9
- # pyright: reportUnknownArgumentType = false
10
- # pyright: reportUnknownVariableType = false
11
- # pyright: reportUnknownParameterType = false
12
- # pyright: reportMissingTypeStubs = false
13
-
14
- from __future__ import annotations
15
-
16
- from pathlib import Path
17
- from typing import TYPE_CHECKING
18
-
19
- import cssutils
20
-
21
- from svg_ultralight.constructors import new_element
22
- from svg_ultralight.string_conversion import encode_to_css_class_name
23
-
24
- if TYPE_CHECKING:
25
- import os
26
-
27
- from lxml.etree import (
28
- _Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
29
- )
30
-
31
-
32
- def _get_class_names_from_stylesheet(
33
- stylesheet: cssutils.css.CSSStyleSheet,
34
- ) -> list[str]:
35
- """Extract all class names from a given CSS stylesheet.
36
-
37
- :param stylesheet: A cssutils.css.CSSStyleSheet object.
38
- :return: A list of class names (without the leading dot).
39
- """
40
- class_names: list[str] = []
41
- for rule in stylesheet.cssRules:
42
- if rule.type == rule.STYLE_RULE:
43
- selectors = (s.strip() for s in rule.selectorText.split(","))
44
- class_names.extend(s[1:] for s in selectors if s.startswith("."))
45
- return class_names
46
-
47
-
48
- def add_svg_font_class(root: EtreeElement, font: str | os.PathLike[str]) -> str:
49
- """Add a css class for the font to the root element.
50
-
51
- :param root: The root element of the SVG document.
52
- :param font: Path to the font file.
53
- :return: The class name for the font, e.g., "bahnschrift_2e_ttf"
54
- """
55
- assert Path(font).exists()
56
- family_name = encode_to_css_class_name(Path(font).stem)
57
- class_name = encode_to_css_class_name(Path(font).name)
58
- style = root.find("style")
59
- if style is None:
60
- style = new_element("style", type="text/css")
61
- root.insert(0, style)
62
- css = style.text or ""
63
-
64
- stylesheet = cssutils.parseString(css)
65
- existing_class_names = _get_class_names_from_stylesheet(stylesheet)
66
- if class_name in existing_class_names:
67
- return class_name
68
-
69
- font_face_rule = cssutils.css.CSSFontFaceRule()
70
- font_face_rule.style = cssutils.css.CSSStyleDeclaration()
71
- font_face_rule.style["font-family"] = f'"{family_name}"'
72
- font_face_rule.style["src"] = rf"url('{Path(font).as_posix()}')"
73
- stylesheet.add(font_face_rule)
74
-
75
- style_rule = cssutils.css.CSSStyleRule(selectorText=f".{class_name}")
76
- style_rule.style = cssutils.css.CSSStyleDeclaration()
77
- style_rule.style["font-family"] = f'"{family_name}"'
78
- stylesheet.add(style_rule)
79
-
80
- style.text = stylesheet.cssText.decode("utf-8")
81
-
82
- return class_name