fondi 0.2.0__tar.gz → 0.2.1.dev22__tar.gz

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.
Files changed (99) hide show
  1. {fondi-0.2.0/src/fondi.egg-info → fondi-0.2.1.dev22}/PKG-INFO +1 -1
  2. {fondi-0.2.0 → fondi-0.2.1.dev22}/pyproject.toml +1 -1
  3. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/backends/svg.py +11 -1
  4. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/scene_builder.py +13 -1
  5. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/sqrt.py +4 -2
  6. {fondi-0.2.0 → fondi-0.2.1.dev22/src/fondi.egg-info}/PKG-INFO +1 -1
  7. {fondi-0.2.0 → fondi-0.2.1.dev22}/tests/test.py +6 -1
  8. {fondi-0.2.0 → fondi-0.2.1.dev22}/tests/test_svg.py +31 -0
  9. {fondi-0.2.0 → fondi-0.2.1.dev22}/LICENSE +0 -0
  10. {fondi-0.2.0 → fondi-0.2.1.dev22}/MANIFEST.in +0 -0
  11. {fondi-0.2.0 → fondi-0.2.1.dev22}/readme.md +0 -0
  12. {fondi-0.2.0 → fondi-0.2.1.dev22}/setup.cfg +0 -0
  13. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/__init__.py +0 -0
  14. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/backends/__init__.py +0 -0
  15. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/backends/pillow.py +0 -0
  16. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/fileloader.py +0 -0
  17. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/__init__.py +0 -0
  18. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/cases.py +0 -0
  19. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/decoration.py +0 -0
  20. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/delimiter_data.py +0 -0
  21. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/delimiter_geom.py +0 -0
  22. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/fraction.py +0 -0
  23. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/helper.py +0 -0
  24. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/ignore.py +0 -0
  25. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/integral.py +0 -0
  26. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/layout.py +0 -0
  27. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/parenthesis.py +0 -0
  28. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/spaces.py +0 -0
  29. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/supersub.py +0 -0
  30. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/symbols.py +0 -0
  31. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/layout/text.py +0 -0
  32. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/mathtext.py +0 -0
  33. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/metrics.py +0 -0
  34. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/parser/__init__.py +0 -0
  35. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/parser/helper.py +0 -0
  36. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/parser/parser.py +3 -3
  37. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/parser/tokens.py +0 -0
  38. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/path_util.py +0 -0
  39. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/plain/__init__.py +0 -0
  40. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/plain/helper.py +0 -0
  41. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/plain/image.py +0 -0
  42. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/plain/plain.py +0 -0
  43. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/plain/symbol.py +0 -0
  44. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/raster_symbols.py +0 -0
  45. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/NewCM10-Italic.otf +0 -0
  46. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/NewCM10-Regular.otf +0 -0
  47. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/__init__.py +0 -0
  48. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/cmu.serif-roman.ttf +0 -0
  49. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/contour-integral.png +0 -0
  50. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM08-Book.otf +0 -0
  51. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM08-BookItalic.otf +0 -0
  52. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM08-Italic.otf +0 -0
  53. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM08-Regular.otf +0 -0
  54. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM08Devanagari-Book.otf +0 -0
  55. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM08Devanagari-Regular.otf +0 -0
  56. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM10-Bold.otf +0 -0
  57. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM10-BoldItalic.otf +0 -0
  58. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM10-Book.otf +0 -0
  59. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM10-BookItalic.otf +0 -0
  60. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM10-Italic.otf +0 -0
  61. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM10-Regular.otf +0 -0
  62. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM10Devanagari-Bold.otf +0 -0
  63. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM10Devanagari-Book.otf +0 -0
  64. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCM10Devanagari-Regular.otf +0 -0
  65. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMMath-Book.otf +0 -0
  66. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMMath-Regular.otf +0 -0
  67. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMMono10-Bold.otf +0 -0
  68. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMMono10-BoldOblique.otf +0 -0
  69. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMMono10-Book.otf +0 -0
  70. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMMono10-BookItalic.otf +0 -0
  71. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMMono10-Italic.otf +0 -0
  72. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMMono10-Regular.otf +0 -0
  73. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans08-Book.otf +0 -0
  74. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans08-BookOblique.otf +0 -0
  75. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans08-Oblique.otf +0 -0
  76. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans08-Regular.otf +0 -0
  77. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans10-Bold.otf +0 -0
  78. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans10-BoldOblique.otf +0 -0
  79. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans10-Book.otf +0 -0
  80. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans10-BookOblique.otf +0 -0
  81. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans10-Oblique.otf +0 -0
  82. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMSans10-Regular.otf +0 -0
  83. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMUncial08-Bold.otf +0 -0
  84. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMUncial08-Book.otf +0 -0
  85. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMUncial08-Regular.otf +0 -0
  86. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMUncial10-Bold.otf +0 -0
  87. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMUncial10-Book.otf +0 -0
  88. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/NewCMUncial10-Regular.otf +0 -0
  89. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/fonts/__init__.py +0 -0
  90. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/integral.png +0 -0
  91. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/normpara_left.png +0 -0
  92. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/normpara_right.png +0 -0
  93. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/tuborpara_left.png +0 -0
  94. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/resources/tuborpara_right.png +0 -0
  95. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi/scene.py +0 -0
  96. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi.egg-info/SOURCES.txt +0 -0
  97. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi.egg-info/dependency_links.txt +0 -0
  98. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi.egg-info/requires.txt +0 -0
  99. {fondi-0.2.0 → fondi-0.2.1.dev22}/src/fondi.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fondi
3
- Version: 0.2.0
3
+ Version: 0.2.1.dev22
4
4
  Summary: LaTeX-like math renderer with PNG and SVG output
5
5
  Author-email: Valter Yde Daugberg <valteryde@hotmail.com>
6
6
  License: GPL-3.0-or-later
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fondi"
3
- version = "0.2.0"
3
+ version = "0.2.1.dev22"
4
4
  authors = [
5
5
  { name="Valter Yde Daugberg", email="valteryde@hotmail.com" },
6
6
  ]
@@ -85,6 +85,14 @@ def _fondi_y_to_svg(y: float, scene_height: float) -> float:
85
85
  return scene_height - y
86
86
 
87
87
 
88
+ def _ascii_safe_svg_markup(svg: str) -> str:
89
+ """Replace non-ASCII with numeric entities for pdflatex / includesvg."""
90
+ return "".join(
91
+ ch if ord(ch) < 128 else f"&#{ord(ch)};"
92
+ for ch in svg
93
+ )
94
+
95
+
88
96
  def _flip_x_transform(x: float, width: float) -> str:
89
97
  cx = round(x + width / 2, 3)
90
98
  return f"translate({cx},0) scale(-1,1) translate({-cx},0)"
@@ -203,7 +211,9 @@ def render_svg(
203
211
  group = SubElement(root, "g")
204
212
  for node in scene.children:
205
213
  _append_node(group, node, height)
206
- return '<?xml version="1.0" encoding="UTF-8"?>\n' + tostring(root, encoding="unicode")
214
+ return '<?xml version="1.0" encoding="UTF-8"?>\n' + _ascii_safe_svg_markup(
215
+ tostring(root, encoding="unicode")
216
+ )
207
217
 
208
218
 
209
219
  def save_svg_bundle(
@@ -101,8 +101,20 @@ def collect_children(
101
101
  )
102
102
  )
103
103
  elif isinstance(layout, MathText):
104
+ if scene_corner is not None:
105
+ child_corner = (
106
+ corner_x + layout.getLeft() - lx,
107
+ corner_y + layout.getBottom() - ly,
108
+ )
109
+ else:
110
+ child_corner = (
111
+ layout.getLeft() - rox,
112
+ layout.getBottom() - roy,
113
+ )
104
114
  nodes.extend(
105
- layout.collect_scene(relayout=False, root=(rox, roy))
115
+ layout.collect_scene(
116
+ child_corner, relayout=False, root=(rox, roy)
117
+ )
106
118
  )
107
119
  else:
108
120
  if scene_corner is not None:
@@ -2,7 +2,7 @@
2
2
  from .helper import boundingBox, unwrap_macro_arg
3
3
  from .layout import Layout, MACROS
4
4
  from ..mathtext import MathText
5
- from .scene_builder import collect_children, composite_origin
5
+ from .scene_builder import collect_children
6
6
  from ..scene import Polyline
7
7
  import math
8
8
 
@@ -47,8 +47,10 @@ class SqrtLayout(Layout):
47
47
  nodes = collect_children(
48
48
  self, (bx, by), self.inner, root=root, scene_corner=corner
49
49
  )
50
+ # Radical points were authored for top-down image coords; flip y for fondi.
50
51
  points = [
51
- (origin_x + px, origin_y + py) for px, py in self._sqrt_points
52
+ (origin_x + px, origin_y + self.height - py)
53
+ for px, py in self._sqrt_points
52
54
  ]
53
55
  nodes.append(
54
56
  Polyline(points, self.color, self.linewidth)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fondi
3
- Version: 0.2.0
3
+ Version: 0.2.1.dev22
4
4
  Summary: LaTeX-like math renderer with PNG and SVG output
5
5
  Author-email: Valter Yde Daugberg <valteryde@hotmail.com>
6
6
  License: GPL-3.0-or-later
@@ -16,7 +16,7 @@ class TestMethods:
16
16
  def __createMathText__(self, mathtext, filename, fontsize=50, color=(255,255,255,255)):
17
17
  txt = fondi.MathText(mathtext, fontsize, color)
18
18
  txt.image.save(BASEDIR / filename)
19
-
19
+ txt.save_svg(BASEDIR / filename.replace('.png', '.svg'))
20
20
 
21
21
  def testPolynomen(self):
22
22
  self.__createMathText__('2*x_{5}^{2}+7^{2}_{1}', 'images/polynomen.png')
@@ -87,6 +87,11 @@ class TestMethods:
87
87
  self.__createMathText__('a_{ijk} + b^{xyz} + c_{a+b}^{m+n} + a_{bc_{ak}}', 'images/subscript_multiple_characters.png')
88
88
 
89
89
 
90
+ def testGreekLetters(self):
91
+ self.__createMathText__('\\alpha + \\beta + \\gamma + \\Gamma + \\delta + \\Delta + \\eta + \\epsilon + \\theta + \\kappa + \\mu + \\lambda + \\tau + \\sigma + \\Sigma + \\phi + \\chi + \\psi + \\omega + \\Omega + \\pi + \\prime', 'images/greek_letters.png')
92
+
93
+
94
+
90
95
  if __name__ == '__main__':
91
96
  TestMethods().run()
92
97
  #TestMethods().testPara()
@@ -110,6 +110,22 @@ def test_svg_raster_symbols_are_tinted():
110
110
  assert pixel is not None
111
111
 
112
112
 
113
+ def test_nested_mathtext_argument_after_text_is_visible():
114
+ from fondi.scene import TextRun
115
+
116
+ mt = fondi.MathText(
117
+ r"\text{ [s] }{ v_q=12.5 }",
118
+ 50,
119
+ COLOR,
120
+ )
121
+ scene = mt.scene()
122
+ runs = [n for n in scene.children if isinstance(n, TextRun)]
123
+ assert {n.text for n in runs} == {" [s] ", "v", "q", "=", "12.5"}
124
+ assert all(n.x >= 0 for n in runs)
125
+ xs = sorted(n.x for n in runs)
126
+ assert xs == sorted(xs), "text runs should appear left-to-right"
127
+
128
+
113
129
  def test_cases_scene_fits_rightmost_text():
114
130
  from fondi.metrics import measure_text
115
131
  from fondi.scene import TextRun
@@ -200,6 +216,19 @@ def test_square_brackets_in_cases_do_not_overlap_brace():
200
216
  assert bracket_left > brace_right
201
217
 
202
218
 
219
+ def test_svg_greek_letters_are_ascii_safe():
220
+ mt = fondi.MathText(r"\alpha + \omega", 50, COLOR)
221
+ svg = mt.to_svg(embed_fonts=False)
222
+ assert "ω" not in svg
223
+ assert "α" not in svg
224
+ assert "&#969;" in svg
225
+ assert "&#945;" in svg
226
+ root = ET.fromstring(svg)
227
+ texts = [el.text for el in root.iter() if el.tag.endswith("text")]
228
+ assert "ω" in texts
229
+ assert "α" in texts
230
+
231
+
203
232
  def test_save_svg_skip_copy_fonts():
204
233
  import tempfile
205
234
 
@@ -260,10 +289,12 @@ if __name__ == "__main__":
260
289
  test_save_svg_bundle_writes_fonts()
261
290
  test_svg_raster_symbols_are_tinted()
262
291
  test_cases_scene_fits_rightmost_text()
292
+ test_nested_mathtext_argument_after_text_is_visible()
263
293
  test_svg_raster_symbols_use_y_up_placement()
264
294
  test_square_brackets_wrap_content()
265
295
  test_round_parens_use_vector_delimiters()
266
296
  test_square_brackets_in_cases_do_not_overlap_brace()
267
297
  test_save_svg_skip_copy_fonts()
298
+ test_svg_greek_letters_are_ascii_safe()
268
299
  write_gallery()
269
300
  print(f"test_svg: ok — SVG files written to {SVG_DIR}")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -328,12 +328,12 @@ def parse_(expr):
328
328
  cprint(tokens)
329
329
  tokens = catchDoubleBiCommands(tokens)
330
330
  cprint(tokens)
331
+ tokens = combineCharsToWords(tokens)
332
+ cprint(tokens)
331
333
  tokens = rearrangeBidirection(tokens)
332
334
  cprint(tokens)
333
335
  tokens = combine(tokens)
334
336
  cprint(tokens)
335
- tokens = combineCharsToWords(tokens)
336
- cprint(tokens)
337
337
 
338
338
  print('---------E----------')
339
339
 
@@ -345,9 +345,9 @@ def parse(expr):
345
345
  tokens = combine(tokens)
346
346
  tokens = translate(tokens)
347
347
  tokens = catchDoubleBiCommands(tokens)
348
+ tokens = combineCharsToWords(tokens)
348
349
  tokens = rearrangeBidirection(tokens)
349
350
  tokens = combine(tokens)
350
- tokens = combineCharsToWords(tokens)
351
351
 
352
352
  return tokens
353
353
 
File without changes