python-fontbro 0.31.0__tar.gz → 0.32.1__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.
- {python_fontbro-0.31.0/python_fontbro.egg-info → python_fontbro-0.32.1}/PKG-INFO +11 -10
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/README.md +8 -8
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/embedding_permissions.py +3 -4
- python_fontbro-0.32.1/fontbro/exceptions.py +53 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/family_classification.py +3 -4
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/font.py +12 -11
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/metadata.py +1 -1
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/monospace.py +3 -1
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/names.py +6 -3
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/pixel.py +2 -1
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/render.py +3 -2
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/tables.py +15 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/variable.py +11 -6
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/pyproject.toml +3 -2
- {python_fontbro-0.31.0 → python_fontbro-0.32.1/python_fontbro.egg-info}/PKG-INFO +11 -10
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/python_fontbro.egg-info/SOURCES.txt +1 -0
- python_fontbro-0.32.1/tests/test_exceptions.py +134 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_instantiation.py +18 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_rename.py +30 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_save.py +7 -5
- python_fontbro-0.32.1/tests/test_update_unicode_data.py +20 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_variable.py +41 -0
- python_fontbro-0.31.0/fontbro/exceptions.py +0 -14
- python_fontbro-0.31.0/tests/test_update_unicode_data.py +0 -11
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/LICENSE.txt +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/MANIFEST.in +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/__init__.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/bitmap.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/color.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/data/family-classifications.json +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/data/features.json +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/data/unicode-blocks.json +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/data/unicode-scripts.json +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/features.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/files.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/fingerprint.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/flags.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/glyphs.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/math.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/metrics.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/py.typed +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/sanitize.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/style_flags.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/subset.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/support.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/unicode.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/utils.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/fontbro/version.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/python_fontbro.egg-info/dependency_links.txt +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/python_fontbro.egg-info/requires.txt +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/python_fontbro.egg-info/top_level.txt +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/setup.cfg +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/setup.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_bitmap.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_characters.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_clone.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_close.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_collection.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_color.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_context_manager.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_embedding_permissions.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_family_classification.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_family_name.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_features.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_filename.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_fingerprint.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_format.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_glyphs.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_image.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_init.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_issues.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_italic_angle.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_monospace.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_names.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_pixel.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_sanitize.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_str.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_style_flags.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_style_name.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_subset.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_support.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_svg.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_tables.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_unicode.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_unicode_blocks_and_scripts.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_version.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_vertical_metrics.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_weight.py +0 -0
- {python_fontbro-0.31.0 → python_fontbro-0.32.1}/tests/test_width.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-fontbro
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.32.1
|
|
4
4
|
Summary: friendly font operations on top of fontTools.
|
|
5
5
|
Author-email: Fabio Caccamo <fabio.caccamo@gmail.com>
|
|
6
6
|
Maintainer-email: Fabio Caccamo <fabio.caccamo@gmail.com>
|
|
@@ -43,15 +43,16 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
43
43
|
Classifier: Natural Language :: English
|
|
44
44
|
Classifier: Operating System :: OS Independent
|
|
45
45
|
Classifier: Programming Language :: Python :: 3
|
|
46
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
47
46
|
Classifier: Programming Language :: Python :: 3.11
|
|
48
47
|
Classifier: Programming Language :: Python :: 3.12
|
|
49
48
|
Classifier: Programming Language :: Python :: 3.13
|
|
50
49
|
Classifier: Programming Language :: Python :: 3.14
|
|
50
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
51
51
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
52
52
|
Classifier: Topic :: Text Processing :: Fonts
|
|
53
53
|
Classifier: Topic :: Multimedia :: Graphics
|
|
54
54
|
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
|
|
55
|
+
Requires-Python: >=3.11
|
|
55
56
|
Description-Content-Type: text/markdown
|
|
56
57
|
License-File: LICENSE.txt
|
|
57
58
|
Requires-Dist: fonttools[lxml,pathops,unicode,woff]<5.0,>=4.43.0
|
|
@@ -184,7 +185,7 @@ font_clone = font.clone()
|
|
|
184
185
|
```python
|
|
185
186
|
"""
|
|
186
187
|
Close the wrapped TTFont instance.
|
|
187
|
-
After closing, any operation on the font raises
|
|
188
|
+
After closing, any operation on the font raises ClosedFontError,
|
|
188
189
|
closing an already closed font does nothing.
|
|
189
190
|
"""
|
|
190
191
|
|
|
@@ -631,7 +632,7 @@ Gets the wrapped TTFont instance.
|
|
|
631
632
|
:returns: The TTFont instance.
|
|
632
633
|
:rtype: TTFont
|
|
633
634
|
|
|
634
|
-
:raises
|
|
635
|
+
:raises ClosedFontError: If the font has been closed.
|
|
635
636
|
"""
|
|
636
637
|
|
|
637
638
|
ttfont = font.get_ttfont()
|
|
@@ -1011,7 +1012,7 @@ If family_name is not defined it will be auto-detected.
|
|
|
1011
1012
|
(only if the default instance style name is renamed)
|
|
1012
1013
|
:type update_style_flags: bool
|
|
1013
1014
|
|
|
1014
|
-
:raises
|
|
1015
|
+
:raises VariableFontRequiredError: if the font is not a variable font.
|
|
1015
1016
|
"""
|
|
1016
1017
|
|
|
1017
1018
|
font.rename_variable_instances(
|
|
@@ -1131,7 +1132,7 @@ Save all instances of a variable font to specified directory in one or more form
|
|
|
1131
1132
|
includes 'instance' (containing instance metadata) and 'files' (a dictionary
|
|
1132
1133
|
with file formats as keys and file-paths as values).
|
|
1133
1134
|
|
|
1134
|
-
:raises
|
|
1135
|
+
:raises VariableFontRequiredError: If the font is not a variable font.
|
|
1135
1136
|
"""
|
|
1136
1137
|
|
|
1137
1138
|
saved_fonts = font.save_variable_instances(
|
|
@@ -1167,7 +1168,7 @@ The fsType field is left untouched if any argument is invalid.
|
|
|
1167
1168
|
:raises ArgumentError: If a value is not a bool or None, if more than one
|
|
1168
1169
|
of the mutually exclusive usage permissions is set to True, or if
|
|
1169
1170
|
installable is set to False while no other usage permission is in effect.
|
|
1170
|
-
:raises
|
|
1171
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1171
1172
|
"""
|
|
1172
1173
|
|
|
1173
1174
|
font.set_embedding_permissions(
|
|
@@ -1187,7 +1188,7 @@ based on provided class_id and subclass_id.
|
|
|
1187
1188
|
|
|
1188
1189
|
:param class_id: Numeric identifier of the font family class.
|
|
1189
1190
|
:param subclass_id: Optional numeric identifier of the font family subclass (default is 0).
|
|
1190
|
-
:raises
|
|
1191
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1191
1192
|
:raises ArgumentError: If class_id is invalid or subclass_id is specified but invalid.
|
|
1192
1193
|
"""
|
|
1193
1194
|
|
|
@@ -1405,7 +1406,7 @@ If an axis min and max values are equal, the axis will be pinned.
|
|
|
1405
1406
|
:param options: The options for the fontTools.varLib.instancer
|
|
1406
1407
|
:type options: dictionary
|
|
1407
1408
|
|
|
1408
|
-
:raises
|
|
1409
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1409
1410
|
:raises ValueError: If the coordinates are not defined (empty)
|
|
1410
1411
|
:raises ValueError: If the coordinates axes are all pinned
|
|
1411
1412
|
"""
|
|
@@ -1438,7 +1439,7 @@ If coordinates are not specified each axis will be pinned at its default value.
|
|
|
1438
1439
|
:param options: The options for the fontTools.varLib.instancer
|
|
1439
1440
|
:type options: dictionary
|
|
1440
1441
|
|
|
1441
|
-
:raises
|
|
1442
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1442
1443
|
:raises ValueError: If the coordinates axes are not all pinned
|
|
1443
1444
|
"""
|
|
1444
1445
|
|
|
@@ -120,7 +120,7 @@ font_clone = font.clone()
|
|
|
120
120
|
```python
|
|
121
121
|
"""
|
|
122
122
|
Close the wrapped TTFont instance.
|
|
123
|
-
After closing, any operation on the font raises
|
|
123
|
+
After closing, any operation on the font raises ClosedFontError,
|
|
124
124
|
closing an already closed font does nothing.
|
|
125
125
|
"""
|
|
126
126
|
|
|
@@ -567,7 +567,7 @@ Gets the wrapped TTFont instance.
|
|
|
567
567
|
:returns: The TTFont instance.
|
|
568
568
|
:rtype: TTFont
|
|
569
569
|
|
|
570
|
-
:raises
|
|
570
|
+
:raises ClosedFontError: If the font has been closed.
|
|
571
571
|
"""
|
|
572
572
|
|
|
573
573
|
ttfont = font.get_ttfont()
|
|
@@ -947,7 +947,7 @@ If family_name is not defined it will be auto-detected.
|
|
|
947
947
|
(only if the default instance style name is renamed)
|
|
948
948
|
:type update_style_flags: bool
|
|
949
949
|
|
|
950
|
-
:raises
|
|
950
|
+
:raises VariableFontRequiredError: if the font is not a variable font.
|
|
951
951
|
"""
|
|
952
952
|
|
|
953
953
|
font.rename_variable_instances(
|
|
@@ -1067,7 +1067,7 @@ Save all instances of a variable font to specified directory in one or more form
|
|
|
1067
1067
|
includes 'instance' (containing instance metadata) and 'files' (a dictionary
|
|
1068
1068
|
with file formats as keys and file-paths as values).
|
|
1069
1069
|
|
|
1070
|
-
:raises
|
|
1070
|
+
:raises VariableFontRequiredError: If the font is not a variable font.
|
|
1071
1071
|
"""
|
|
1072
1072
|
|
|
1073
1073
|
saved_fonts = font.save_variable_instances(
|
|
@@ -1103,7 +1103,7 @@ The fsType field is left untouched if any argument is invalid.
|
|
|
1103
1103
|
:raises ArgumentError: If a value is not a bool or None, if more than one
|
|
1104
1104
|
of the mutually exclusive usage permissions is set to True, or if
|
|
1105
1105
|
installable is set to False while no other usage permission is in effect.
|
|
1106
|
-
:raises
|
|
1106
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1107
1107
|
"""
|
|
1108
1108
|
|
|
1109
1109
|
font.set_embedding_permissions(
|
|
@@ -1123,7 +1123,7 @@ based on provided class_id and subclass_id.
|
|
|
1123
1123
|
|
|
1124
1124
|
:param class_id: Numeric identifier of the font family class.
|
|
1125
1125
|
:param subclass_id: Optional numeric identifier of the font family subclass (default is 0).
|
|
1126
|
-
:raises
|
|
1126
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1127
1127
|
:raises ArgumentError: If class_id is invalid or subclass_id is specified but invalid.
|
|
1128
1128
|
"""
|
|
1129
1129
|
|
|
@@ -1341,7 +1341,7 @@ If an axis min and max values are equal, the axis will be pinned.
|
|
|
1341
1341
|
:param options: The options for the fontTools.varLib.instancer
|
|
1342
1342
|
:type options: dictionary
|
|
1343
1343
|
|
|
1344
|
-
:raises
|
|
1344
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1345
1345
|
:raises ValueError: If the coordinates are not defined (empty)
|
|
1346
1346
|
:raises ValueError: If the coordinates axes are all pinned
|
|
1347
1347
|
"""
|
|
@@ -1374,7 +1374,7 @@ If coordinates are not specified each axis will be pinned at its default value.
|
|
|
1374
1374
|
:param options: The options for the fontTools.varLib.instancer
|
|
1375
1375
|
:type options: dictionary
|
|
1376
1376
|
|
|
1377
|
-
:raises
|
|
1377
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1378
1378
|
:raises ValueError: If the coordinates axes are not all pinned
|
|
1379
1379
|
"""
|
|
1380
1380
|
|
|
@@ -2,8 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from fontTools.ttLib import TTFont
|
|
4
4
|
|
|
5
|
-
from fontbro.exceptions import ArgumentError
|
|
5
|
+
from fontbro.exceptions import ArgumentError
|
|
6
6
|
from fontbro.flags import get_flag, set_flag
|
|
7
|
+
from fontbro.tables import get_table_or_raise
|
|
7
8
|
|
|
8
9
|
# Embedding Permissions:
|
|
9
10
|
# https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fstype
|
|
@@ -95,9 +96,7 @@ def set_embedding_permissions(
|
|
|
95
96
|
Sets the embedding permissions in the OS/2 fsType field of the given font,
|
|
96
97
|
the fsType field is left untouched if any argument is invalid.
|
|
97
98
|
"""
|
|
98
|
-
os2 = ttfont
|
|
99
|
-
if not os2:
|
|
100
|
-
raise OperationError("Invalid OS/2 table (doesn't exist).")
|
|
99
|
+
os2 = get_table_or_raise(ttfont, "OS/2")
|
|
101
100
|
|
|
102
101
|
usage_permissions = {
|
|
103
102
|
"installable": installable,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ArgumentError(ValueError):
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DataError(ValueError):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class OperationError(TypeError):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ClosedFontError(OperationError):
|
|
17
|
+
"""
|
|
18
|
+
The operation was called on a closed font.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MissingTableError(OperationError, KeyError):
|
|
23
|
+
"""
|
|
24
|
+
The operation requires a table the font doesn't have.
|
|
25
|
+
It's also a KeyError, raised before when accessing the missing table.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
table_tag: str,
|
|
31
|
+
message: str | None = None,
|
|
32
|
+
) -> None:
|
|
33
|
+
self.table_tag = table_tag
|
|
34
|
+
super().__init__(message or f"Invalid {table_tag} table (doesn't exist).")
|
|
35
|
+
|
|
36
|
+
def __reduce__(self) -> tuple[type[MissingTableError], tuple[str, str]]:
|
|
37
|
+
# pickle and copy recreate the exception passing its args (the message
|
|
38
|
+
# only) to __init__, the table tag must be passed too
|
|
39
|
+
return (self.__class__, (self.table_tag, str(self)))
|
|
40
|
+
|
|
41
|
+
def __str__(self) -> str:
|
|
42
|
+
# KeyError wraps the message in quotes
|
|
43
|
+
return str(self.args[0])
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class VariableFontRequiredError(OperationError):
|
|
47
|
+
"""
|
|
48
|
+
The operation requires a variable font.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class SanitizationError(Exception):
|
|
53
|
+
pass
|
|
@@ -4,7 +4,8 @@ from typing import Any
|
|
|
4
4
|
|
|
5
5
|
from fontTools.ttLib import TTFont
|
|
6
6
|
|
|
7
|
-
from fontbro.exceptions import ArgumentError
|
|
7
|
+
from fontbro.exceptions import ArgumentError
|
|
8
|
+
from fontbro.tables import get_table_or_raise
|
|
8
9
|
from fontbro.utils import concat_names, find_item, read_json
|
|
9
10
|
|
|
10
11
|
# Family Classification:
|
|
@@ -152,9 +153,7 @@ def set_family_classification(
|
|
|
152
153
|
"""
|
|
153
154
|
Sets the family classification of the given font in the OS/2.sFamilyClass field.
|
|
154
155
|
"""
|
|
155
|
-
os2 = ttfont
|
|
156
|
-
if not os2:
|
|
157
|
-
raise OperationError("Invalid OS/2 table (doesn't exist).")
|
|
156
|
+
os2 = get_table_or_raise(ttfont, "OS/2")
|
|
158
157
|
|
|
159
158
|
# validate class key and subclass key
|
|
160
159
|
class_item, subclass_item = _get_family_classification_items(
|
|
@@ -32,7 +32,8 @@ from fontbro import variable as _variable
|
|
|
32
32
|
from fontbro import version as _version
|
|
33
33
|
from fontbro.exceptions import (
|
|
34
34
|
ArgumentError,
|
|
35
|
-
|
|
35
|
+
ClosedFontError,
|
|
36
|
+
VariableFontRequiredError,
|
|
36
37
|
)
|
|
37
38
|
|
|
38
39
|
|
|
@@ -325,7 +326,7 @@ class Font:
|
|
|
325
326
|
) -> None:
|
|
326
327
|
"""
|
|
327
328
|
Close the wrapped TTFont instance.
|
|
328
|
-
After closing, any operation on the font raises
|
|
329
|
+
After closing, any operation on the font raises ClosedFontError,
|
|
329
330
|
closing an already closed font does nothing.
|
|
330
331
|
"""
|
|
331
332
|
# TTFont.close() is idempotent (it closes the reader and sets it to None)
|
|
@@ -847,13 +848,13 @@ class Font:
|
|
|
847
848
|
:returns: The TTFont instance.
|
|
848
849
|
:rtype: TTFont
|
|
849
850
|
|
|
850
|
-
:raises
|
|
851
|
+
:raises ClosedFontError: If the font has been closed.
|
|
851
852
|
"""
|
|
852
853
|
# all the font operations get the TTFont instance through this method,
|
|
853
854
|
# the TTFont can also be closed directly (bypassing this instance):
|
|
854
855
|
# when closed, fontTools sets its reader to None
|
|
855
856
|
if self._ttfont is None or self._ttfont.reader is None:
|
|
856
|
-
raise
|
|
857
|
+
raise ClosedFontError("Invalid operation, the font is closed.")
|
|
857
858
|
return self._ttfont
|
|
858
859
|
|
|
859
860
|
def get_unicode_block_by_name(
|
|
@@ -1277,7 +1278,7 @@ class Font:
|
|
|
1277
1278
|
(only if the default instance style name is renamed)
|
|
1278
1279
|
:type update_style_flags: bool
|
|
1279
1280
|
|
|
1280
|
-
:raises
|
|
1281
|
+
:raises VariableFontRequiredError: if the font is not a variable font.
|
|
1281
1282
|
:return: None
|
|
1282
1283
|
"""
|
|
1283
1284
|
ttfont = self.get_ttfont()
|
|
@@ -1512,10 +1513,10 @@ class Font:
|
|
|
1512
1513
|
includes 'instance' (containing instance metadata) and 'files' (a dictionary
|
|
1513
1514
|
with file formats as keys and file-paths as values).
|
|
1514
1515
|
|
|
1515
|
-
:raises
|
|
1516
|
+
:raises VariableFontRequiredError: If the font is not a variable font.
|
|
1516
1517
|
"""
|
|
1517
1518
|
if not self.is_variable():
|
|
1518
|
-
raise
|
|
1519
|
+
raise VariableFontRequiredError("Only a variable font can be instantiated.")
|
|
1519
1520
|
|
|
1520
1521
|
fsutil.assert_not_file(dirpath)
|
|
1521
1522
|
fsutil.make_dirs(dirpath)
|
|
@@ -1570,7 +1571,7 @@ class Font:
|
|
|
1570
1571
|
|
|
1571
1572
|
:param class_id: Numeric identifier of the font family class.
|
|
1572
1573
|
:param subclass_id: Optional numeric identifier of the font family subclass (default is 0).
|
|
1573
|
-
:raises
|
|
1574
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1574
1575
|
:raises ArgumentError: If class_id is invalid or subclass_id is specified but invalid.
|
|
1575
1576
|
"""
|
|
1576
1577
|
ttfont = self.get_ttfont()
|
|
@@ -1723,7 +1724,7 @@ class Font:
|
|
|
1723
1724
|
:raises ArgumentError: If a value is not a bool or None, if more than one
|
|
1724
1725
|
of the mutually exclusive usage permissions is set to True, or if
|
|
1725
1726
|
installable is set to False while no other usage permission is in effect.
|
|
1726
|
-
:raises
|
|
1727
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1727
1728
|
"""
|
|
1728
1729
|
ttfont = self.get_ttfont()
|
|
1729
1730
|
_embedding_permissions.set_embedding_permissions(
|
|
@@ -1860,7 +1861,7 @@ class Font:
|
|
|
1860
1861
|
:param options: The options for the fontTools.varLib.instancer
|
|
1861
1862
|
:type options: dictionary
|
|
1862
1863
|
|
|
1863
|
-
:raises
|
|
1864
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1864
1865
|
:raises ValueError: If the coordinates are not defined (blank)
|
|
1865
1866
|
:raises ValueError: If the coordinates axes are all pinned
|
|
1866
1867
|
"""
|
|
@@ -1900,7 +1901,7 @@ class Font:
|
|
|
1900
1901
|
:param options: The options for the fontTools.varLib.instancer
|
|
1901
1902
|
:type options: dictionary
|
|
1902
1903
|
|
|
1903
|
-
:raises
|
|
1904
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1904
1905
|
:raises ValueError: If the coordinates axes are not all pinned
|
|
1905
1906
|
"""
|
|
1906
1907
|
ttfont = self.get_ttfont()
|
|
@@ -6,6 +6,7 @@ from collections import Counter
|
|
|
6
6
|
from fontTools import unicodedata
|
|
7
7
|
from fontTools.ttLib import TTFont
|
|
8
8
|
|
|
9
|
+
from fontbro.tables import get_table_or_raise
|
|
9
10
|
from fontbro.unicode import get_best_cmap
|
|
10
11
|
|
|
11
12
|
# same criteria used by Fontbakery (glyph_metrics_stats condition):
|
|
@@ -36,9 +37,10 @@ def _get_widths(
|
|
|
36
37
|
"""
|
|
37
38
|
Gets the advance widths of the given glyphs, zero widths are ignored.
|
|
38
39
|
"""
|
|
40
|
+
hmtx = get_table_or_raise(ttfont, "hmtx")
|
|
39
41
|
return [
|
|
40
42
|
advance
|
|
41
|
-
for glyph_name, (advance, _) in
|
|
43
|
+
for glyph_name, (advance, _) in hmtx.metrics.items()
|
|
42
44
|
if glyph_name in glyphs_names and advance != 0
|
|
43
45
|
]
|
|
44
46
|
|
|
@@ -6,7 +6,8 @@ from typing import Any
|
|
|
6
6
|
from fontTools.misc.encodingTools import getEncoding
|
|
7
7
|
from fontTools.ttLib import TTFont
|
|
8
8
|
|
|
9
|
-
from fontbro.exceptions import ArgumentError,
|
|
9
|
+
from fontbro.exceptions import ArgumentError, VariableFontRequiredError
|
|
10
|
+
from fontbro.tables import get_table_or_raise
|
|
10
11
|
from fontbro.utils import concat_names, remove_spaces
|
|
11
12
|
|
|
12
13
|
# Names:
|
|
@@ -193,7 +194,7 @@ def set_name(
|
|
|
193
194
|
and unicode flags.
|
|
194
195
|
"""
|
|
195
196
|
name_id = _get_name_id(key)
|
|
196
|
-
name_table = ttfont
|
|
197
|
+
name_table = get_table_or_raise(ttfont, "name")
|
|
197
198
|
if windows:
|
|
198
199
|
# https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/ttLib/tables/_n_a_m_e.py#L568
|
|
199
200
|
# the windows record is always written, it's the one read first by get_name
|
|
@@ -313,7 +314,9 @@ def rename_variable_instances(
|
|
|
313
314
|
so renaming it renames the font style too.
|
|
314
315
|
"""
|
|
315
316
|
if "fvar" not in ttfont:
|
|
316
|
-
raise
|
|
317
|
+
raise VariableFontRequiredError(
|
|
318
|
+
"Only the instances of a variable font can be renamed."
|
|
319
|
+
)
|
|
317
320
|
# style names are matched case-insensitively
|
|
318
321
|
style_names = {key.lower(): value for key, value in (style_names or {}).items()}
|
|
319
322
|
default_style_name = _get_default_instance_style_name(ttfont).lower()
|
|
@@ -9,6 +9,7 @@ from fontTools import unicodedata
|
|
|
9
9
|
from fontTools.pens.recordingPen import DecomposingRecordingPen
|
|
10
10
|
from fontTools.ttLib import TTFont
|
|
11
11
|
|
|
12
|
+
from fontbro.tables import get_table_or_raise
|
|
12
13
|
from fontbro.unicode import get_best_cmap
|
|
13
14
|
|
|
14
15
|
Segment = tuple[float, float]
|
|
@@ -219,7 +220,7 @@ def is_pixel(
|
|
|
219
220
|
|
|
220
221
|
# 2nd check: segments aligned to a plausible pixel grid,
|
|
221
222
|
# it excludes squared ("techno") fonts
|
|
222
|
-
units_per_em = ttfont
|
|
223
|
+
units_per_em = get_table_or_raise(ttfont, "head").unitsPerEm
|
|
223
224
|
pixel_width, pixel_height = (
|
|
224
225
|
_get_pixel_dimension(
|
|
225
226
|
orthogonal_glyphs_segments, axis, units_per_em, min_glyphs_count
|
|
@@ -9,6 +9,7 @@ from fontTools.pens.svgPathPen import SVGPathPen
|
|
|
9
9
|
from fontTools.ttLib import TTFont
|
|
10
10
|
from PIL import Image, ImageDraw, ImageFont
|
|
11
11
|
|
|
12
|
+
from fontbro.tables import get_table_or_raise
|
|
12
13
|
from fontbro.unicode import get_best_cmap_or_raise
|
|
13
14
|
|
|
14
15
|
|
|
@@ -51,9 +52,9 @@ def get_svg(
|
|
|
51
52
|
Gets an SVG representation of the given font rendering some text.
|
|
52
53
|
"""
|
|
53
54
|
# get font metrics
|
|
54
|
-
units_per_em = ttfont
|
|
55
|
+
units_per_em = get_table_or_raise(ttfont, "head").unitsPerEm
|
|
55
56
|
scale = size / units_per_em
|
|
56
|
-
hhea = ttfont
|
|
57
|
+
hhea = get_table_or_raise(ttfont, "hhea")
|
|
57
58
|
ascent = hhea.ascent * scale
|
|
58
59
|
descent = hhea.descent * scale
|
|
59
60
|
width = 0
|
|
@@ -4,6 +4,8 @@ from typing import Any
|
|
|
4
4
|
|
|
5
5
|
from fontTools.ttLib import TTFont
|
|
6
6
|
|
|
7
|
+
from fontbro.exceptions import MissingTableError
|
|
8
|
+
|
|
7
9
|
# https://learn.microsoft.com/en-us/typography/opentype/spec/otff#font-tables
|
|
8
10
|
_TABLE_NAMES_BY_TAG: dict[str, str] = {
|
|
9
11
|
# required tables
|
|
@@ -95,6 +97,19 @@ _TABLE_NAMES_BY_TAG: dict[str, str] = {
|
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
|
|
100
|
+
def get_table_or_raise(
|
|
101
|
+
ttfont: TTFont,
|
|
102
|
+
tag: str,
|
|
103
|
+
) -> Any:
|
|
104
|
+
"""
|
|
105
|
+
Gets the table with the given tag of the given font,
|
|
106
|
+
MissingTableError is raised if the font has no table with the given tag.
|
|
107
|
+
"""
|
|
108
|
+
if tag not in ttfont:
|
|
109
|
+
raise MissingTableError(tag)
|
|
110
|
+
return ttfont[tag]
|
|
111
|
+
|
|
112
|
+
|
|
98
113
|
def get_tables_tags(
|
|
99
114
|
ttfont: TTFont,
|
|
100
115
|
*,
|
|
@@ -9,8 +9,9 @@ from fontTools.varLib.instancer import OverlapMode
|
|
|
9
9
|
|
|
10
10
|
from fontbro import names as _names
|
|
11
11
|
from fontbro import style_flags as _style_flags
|
|
12
|
-
from fontbro.exceptions import ArgumentError,
|
|
12
|
+
from fontbro.exceptions import ArgumentError, VariableFontRequiredError
|
|
13
13
|
from fontbro.math import get_euclidean_distance
|
|
14
|
+
from fontbro.tables import get_table_or_raise
|
|
14
15
|
from fontbro.utils import slugify
|
|
15
16
|
|
|
16
17
|
# Variable Axes:
|
|
@@ -159,7 +160,7 @@ def get_variable_instances(
|
|
|
159
160
|
"""
|
|
160
161
|
if not is_variable(ttfont):
|
|
161
162
|
return None
|
|
162
|
-
name_table = ttfont
|
|
163
|
+
name_table = get_table_or_raise(ttfont, "name")
|
|
163
164
|
return [
|
|
164
165
|
{
|
|
165
166
|
"coordinates": instance.coordinates,
|
|
@@ -174,11 +175,15 @@ def get_variable_instance_by_style_name(
|
|
|
174
175
|
style_name: str,
|
|
175
176
|
) -> dict[str, Any] | None:
|
|
176
177
|
"""
|
|
177
|
-
Gets the variable instance of the given font by style name
|
|
178
|
+
Gets the variable instance of the given font by style name,
|
|
179
|
+
the instances without a name record (style name None) are skipped.
|
|
178
180
|
"""
|
|
181
|
+
if not style_name:
|
|
182
|
+
return None
|
|
179
183
|
instances = get_variable_instances(ttfont) or []
|
|
180
184
|
for instance in instances:
|
|
181
|
-
|
|
185
|
+
instance_style_name = instance["style_name"]
|
|
186
|
+
if instance_style_name and slugify(instance_style_name) == slugify(style_name):
|
|
182
187
|
return instance
|
|
183
188
|
return None
|
|
184
189
|
|
|
@@ -320,7 +325,7 @@ def to_sliced_variable(
|
|
|
320
325
|
the variable axes at the given coordinates.
|
|
321
326
|
"""
|
|
322
327
|
if not is_variable(ttfont):
|
|
323
|
-
raise
|
|
328
|
+
raise VariableFontRequiredError("Only a variable font can be sliced.")
|
|
324
329
|
|
|
325
330
|
coordinates = get_sliced_coordinates(ttfont, coordinates)
|
|
326
331
|
|
|
@@ -364,7 +369,7 @@ def to_static(
|
|
|
364
369
|
the variable axes at the given coordinates.
|
|
365
370
|
"""
|
|
366
371
|
if not is_variable(ttfont):
|
|
367
|
-
raise
|
|
372
|
+
raise VariableFontRequiredError("Only a variable font can be made static.")
|
|
368
373
|
|
|
369
374
|
coordinates = get_static_coordinates(
|
|
370
375
|
ttfont,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools"]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
3
|
build-backend = "setuptools.build_meta"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
@@ -40,11 +40,11 @@ classifiers = [
|
|
|
40
40
|
"Natural Language :: English",
|
|
41
41
|
"Operating System :: OS Independent",
|
|
42
42
|
"Programming Language :: Python :: 3",
|
|
43
|
-
"Programming Language :: Python :: 3.10",
|
|
44
43
|
"Programming Language :: Python :: 3.11",
|
|
45
44
|
"Programming Language :: Python :: 3.12",
|
|
46
45
|
"Programming Language :: Python :: 3.13",
|
|
47
46
|
"Programming Language :: Python :: 3.14",
|
|
47
|
+
"Programming Language :: Python :: 3.15",
|
|
48
48
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
49
49
|
"Topic :: Text Processing :: Fonts",
|
|
50
50
|
"Topic :: Multimedia :: Graphics",
|
|
@@ -59,6 +59,7 @@ dependencies = [
|
|
|
59
59
|
"python-fsutil >= 0.16.0, < 1.0.0",
|
|
60
60
|
]
|
|
61
61
|
dynamic = ["version"]
|
|
62
|
+
requires-python = ">=3.11"
|
|
62
63
|
maintainers = [
|
|
63
64
|
{ name = "Fabio Caccamo", email = "fabio.caccamo@gmail.com" },
|
|
64
65
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-fontbro
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.32.1
|
|
4
4
|
Summary: friendly font operations on top of fontTools.
|
|
5
5
|
Author-email: Fabio Caccamo <fabio.caccamo@gmail.com>
|
|
6
6
|
Maintainer-email: Fabio Caccamo <fabio.caccamo@gmail.com>
|
|
@@ -43,15 +43,16 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
43
43
|
Classifier: Natural Language :: English
|
|
44
44
|
Classifier: Operating System :: OS Independent
|
|
45
45
|
Classifier: Programming Language :: Python :: 3
|
|
46
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
47
46
|
Classifier: Programming Language :: Python :: 3.11
|
|
48
47
|
Classifier: Programming Language :: Python :: 3.12
|
|
49
48
|
Classifier: Programming Language :: Python :: 3.13
|
|
50
49
|
Classifier: Programming Language :: Python :: 3.14
|
|
50
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
51
51
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
52
52
|
Classifier: Topic :: Text Processing :: Fonts
|
|
53
53
|
Classifier: Topic :: Multimedia :: Graphics
|
|
54
54
|
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
|
|
55
|
+
Requires-Python: >=3.11
|
|
55
56
|
Description-Content-Type: text/markdown
|
|
56
57
|
License-File: LICENSE.txt
|
|
57
58
|
Requires-Dist: fonttools[lxml,pathops,unicode,woff]<5.0,>=4.43.0
|
|
@@ -184,7 +185,7 @@ font_clone = font.clone()
|
|
|
184
185
|
```python
|
|
185
186
|
"""
|
|
186
187
|
Close the wrapped TTFont instance.
|
|
187
|
-
After closing, any operation on the font raises
|
|
188
|
+
After closing, any operation on the font raises ClosedFontError,
|
|
188
189
|
closing an already closed font does nothing.
|
|
189
190
|
"""
|
|
190
191
|
|
|
@@ -631,7 +632,7 @@ Gets the wrapped TTFont instance.
|
|
|
631
632
|
:returns: The TTFont instance.
|
|
632
633
|
:rtype: TTFont
|
|
633
634
|
|
|
634
|
-
:raises
|
|
635
|
+
:raises ClosedFontError: If the font has been closed.
|
|
635
636
|
"""
|
|
636
637
|
|
|
637
638
|
ttfont = font.get_ttfont()
|
|
@@ -1011,7 +1012,7 @@ If family_name is not defined it will be auto-detected.
|
|
|
1011
1012
|
(only if the default instance style name is renamed)
|
|
1012
1013
|
:type update_style_flags: bool
|
|
1013
1014
|
|
|
1014
|
-
:raises
|
|
1015
|
+
:raises VariableFontRequiredError: if the font is not a variable font.
|
|
1015
1016
|
"""
|
|
1016
1017
|
|
|
1017
1018
|
font.rename_variable_instances(
|
|
@@ -1131,7 +1132,7 @@ Save all instances of a variable font to specified directory in one or more form
|
|
|
1131
1132
|
includes 'instance' (containing instance metadata) and 'files' (a dictionary
|
|
1132
1133
|
with file formats as keys and file-paths as values).
|
|
1133
1134
|
|
|
1134
|
-
:raises
|
|
1135
|
+
:raises VariableFontRequiredError: If the font is not a variable font.
|
|
1135
1136
|
"""
|
|
1136
1137
|
|
|
1137
1138
|
saved_fonts = font.save_variable_instances(
|
|
@@ -1167,7 +1168,7 @@ The fsType field is left untouched if any argument is invalid.
|
|
|
1167
1168
|
:raises ArgumentError: If a value is not a bool or None, if more than one
|
|
1168
1169
|
of the mutually exclusive usage permissions is set to True, or if
|
|
1169
1170
|
installable is set to False while no other usage permission is in effect.
|
|
1170
|
-
:raises
|
|
1171
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1171
1172
|
"""
|
|
1172
1173
|
|
|
1173
1174
|
font.set_embedding_permissions(
|
|
@@ -1187,7 +1188,7 @@ based on provided class_id and subclass_id.
|
|
|
1187
1188
|
|
|
1188
1189
|
:param class_id: Numeric identifier of the font family class.
|
|
1189
1190
|
:param subclass_id: Optional numeric identifier of the font family subclass (default is 0).
|
|
1190
|
-
:raises
|
|
1191
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1191
1192
|
:raises ArgumentError: If class_id is invalid or subclass_id is specified but invalid.
|
|
1192
1193
|
"""
|
|
1193
1194
|
|
|
@@ -1405,7 +1406,7 @@ If an axis min and max values are equal, the axis will be pinned.
|
|
|
1405
1406
|
:param options: The options for the fontTools.varLib.instancer
|
|
1406
1407
|
:type options: dictionary
|
|
1407
1408
|
|
|
1408
|
-
:raises
|
|
1409
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1409
1410
|
:raises ValueError: If the coordinates are not defined (empty)
|
|
1410
1411
|
:raises ValueError: If the coordinates axes are all pinned
|
|
1411
1412
|
"""
|
|
@@ -1438,7 +1439,7 @@ If coordinates are not specified each axis will be pinned at its default value.
|
|
|
1438
1439
|
:param options: The options for the fontTools.varLib.instancer
|
|
1439
1440
|
:type options: dictionary
|
|
1440
1441
|
|
|
1441
|
-
:raises
|
|
1442
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1442
1443
|
:raises ValueError: If the coordinates axes are not all pinned
|
|
1443
1444
|
"""
|
|
1444
1445
|
|