python-fontbro 0.30.0__tar.gz → 0.32.0__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.30.0/python_fontbro.egg-info → python_fontbro-0.32.0}/PKG-INFO +57 -10
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/README.md +55 -8
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/embedding_permissions.py +3 -4
- python_fontbro-0.32.0/fontbro/exceptions.py +53 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/family_classification.py +3 -4
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/font.py +70 -11
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/metadata.py +1 -1
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/monospace.py +3 -1
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/names.py +257 -18
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/pixel.py +2 -1
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/render.py +3 -2
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/tables.py +15 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/variable.py +37 -4
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/pyproject.toml +1 -1
- {python_fontbro-0.30.0 → python_fontbro-0.32.0/python_fontbro.egg-info}/PKG-INFO +57 -10
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/python_fontbro.egg-info/SOURCES.txt +1 -0
- python_fontbro-0.32.0/tests/test_exceptions.py +134 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_instantiation.py +55 -0
- python_fontbro-0.32.0/tests/test_rename.py +484 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_save.py +7 -5
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_unicode_blocks_and_scripts.py +16 -16
- python_fontbro-0.32.0/tests/test_update_unicode_data.py +20 -0
- python_fontbro-0.30.0/fontbro/exceptions.py +0 -14
- python_fontbro-0.30.0/tests/test_rename.py +0 -163
- python_fontbro-0.30.0/tests/test_update_unicode_data.py +0 -11
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/LICENSE.txt +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/MANIFEST.in +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/__init__.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/bitmap.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/color.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/data/family-classifications.json +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/data/features.json +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/data/unicode-blocks.json +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/data/unicode-scripts.json +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/features.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/files.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/fingerprint.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/flags.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/glyphs.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/math.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/metrics.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/py.typed +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/sanitize.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/style_flags.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/subset.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/support.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/unicode.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/utils.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/fontbro/version.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/python_fontbro.egg-info/dependency_links.txt +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/python_fontbro.egg-info/requires.txt +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/python_fontbro.egg-info/top_level.txt +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/setup.cfg +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/setup.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_bitmap.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_characters.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_clone.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_close.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_collection.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_color.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_context_manager.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_embedding_permissions.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_family_classification.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_family_name.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_features.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_filename.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_fingerprint.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_format.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_glyphs.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_image.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_init.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_issues.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_italic_angle.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_monospace.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_names.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_pixel.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_sanitize.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_str.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_style_flags.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_style_name.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_subset.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_support.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_svg.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_tables.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_unicode.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_variable.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_version.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_vertical_metrics.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/tests/test_weight.py +0 -0
- {python_fontbro-0.30.0 → python_fontbro-0.32.0}/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.0
|
|
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,7 +43,6 @@ 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
|
|
@@ -52,6 +51,7 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
|
52
51
|
Classifier: Topic :: Text Processing :: Fonts
|
|
53
52
|
Classifier: Topic :: Multimedia :: Graphics
|
|
54
53
|
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
|
|
54
|
+
Requires-Python: >=3.11
|
|
55
55
|
Description-Content-Type: text/markdown
|
|
56
56
|
License-File: LICENSE.txt
|
|
57
57
|
Requires-Dist: fonttools[lxml,pathops,unicode,woff]<5.0,>=4.43.0
|
|
@@ -149,6 +149,7 @@ with open("fonts/MyFont.ttf") as fh:
|
|
|
149
149
|
- [`is_static`](#is_static)
|
|
150
150
|
- [`is_variable`](#is_variable)
|
|
151
151
|
- [`rename`](#rename)
|
|
152
|
+
- [`rename_variable_instances`](#rename_variable_instances)
|
|
152
153
|
- [`sanitize`](#sanitize)
|
|
153
154
|
- [`save`](#save)
|
|
154
155
|
- [`save_as_woff`](#save_as_woff)
|
|
@@ -183,7 +184,7 @@ font_clone = font.clone()
|
|
|
183
184
|
```python
|
|
184
185
|
"""
|
|
185
186
|
Close the wrapped TTFont instance.
|
|
186
|
-
After closing, any operation on the font raises
|
|
187
|
+
After closing, any operation on the font raises ClosedFontError,
|
|
187
188
|
closing an already closed font does nothing.
|
|
188
189
|
"""
|
|
189
190
|
|
|
@@ -630,7 +631,7 @@ Gets the wrapped TTFont instance.
|
|
|
630
631
|
:returns: The TTFont instance.
|
|
631
632
|
:rtype: TTFont
|
|
632
633
|
|
|
633
|
-
:raises
|
|
634
|
+
:raises ClosedFontError: If the font has been closed.
|
|
634
635
|
"""
|
|
635
636
|
|
|
636
637
|
ttfont = font.get_ttfont()
|
|
@@ -966,6 +967,8 @@ variable = font.is_variable()
|
|
|
966
967
|
"""
|
|
967
968
|
Renames the font names records (1, 2, 4, 6, 16, 17) according to
|
|
968
969
|
the given family_name and style_name (subfamily_name).
|
|
970
|
+
The names records (18, 25), the fvar named instances PostScript names
|
|
971
|
+
and the CFF table names are updated too, only if already defined.
|
|
969
972
|
|
|
970
973
|
If family_name is not defined it will be auto-detected.
|
|
971
974
|
If style_name is not defined it will be auto-detected.
|
|
@@ -985,6 +988,39 @@ font.rename(
|
|
|
985
988
|
)
|
|
986
989
|
```
|
|
987
990
|
|
|
991
|
+
#### `rename_variable_instances`
|
|
992
|
+
```python
|
|
993
|
+
"""
|
|
994
|
+
Renames the named instances of the variable font.
|
|
995
|
+
|
|
996
|
+
The family_name replaces the family part of the instances PostScript names
|
|
997
|
+
(and of the variations PostScript name prefix, if defined).
|
|
998
|
+
The style_names replace the instances style names and the style part
|
|
999
|
+
of their PostScript names. The axes names are unchanged.
|
|
1000
|
+
The default instance style name must match the font style name,
|
|
1001
|
+
so renaming it renames the font style too.
|
|
1002
|
+
|
|
1003
|
+
If family_name is not defined it will be auto-detected.
|
|
1004
|
+
|
|
1005
|
+
:param family_name: The family name
|
|
1006
|
+
:type family_name: str
|
|
1007
|
+
:param style_names: The new style names mapped by the old ones (case-insensitive),
|
|
1008
|
+
eg. {"Thin": "Hairline"}
|
|
1009
|
+
:type style_names: dict or None
|
|
1010
|
+
:param update_style_flags: if True the style flags will be updated by subfamily name
|
|
1011
|
+
(only if the default instance style name is renamed)
|
|
1012
|
+
:type update_style_flags: bool
|
|
1013
|
+
|
|
1014
|
+
:raises VariableFontRequiredError: if the font is not a variable font.
|
|
1015
|
+
"""
|
|
1016
|
+
|
|
1017
|
+
font.rename_variable_instances(
|
|
1018
|
+
family_name="My Font New",
|
|
1019
|
+
style_names={"Thin": "Hairline"},
|
|
1020
|
+
update_style_flags=True,
|
|
1021
|
+
)
|
|
1022
|
+
```
|
|
1023
|
+
|
|
988
1024
|
#### `sanitize`
|
|
989
1025
|
```python
|
|
990
1026
|
"""
|
|
@@ -1095,7 +1131,7 @@ Save all instances of a variable font to specified directory in one or more form
|
|
|
1095
1131
|
includes 'instance' (containing instance metadata) and 'files' (a dictionary
|
|
1096
1132
|
with file formats as keys and file-paths as values).
|
|
1097
1133
|
|
|
1098
|
-
:raises
|
|
1134
|
+
:raises VariableFontRequiredError: If the font is not a variable font.
|
|
1099
1135
|
"""
|
|
1100
1136
|
|
|
1101
1137
|
saved_fonts = font.save_variable_instances(
|
|
@@ -1131,7 +1167,7 @@ The fsType field is left untouched if any argument is invalid.
|
|
|
1131
1167
|
:raises ArgumentError: If a value is not a bool or None, if more than one
|
|
1132
1168
|
of the mutually exclusive usage permissions is set to True, or if
|
|
1133
1169
|
installable is set to False while no other usage permission is in effect.
|
|
1134
|
-
:raises
|
|
1170
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1135
1171
|
"""
|
|
1136
1172
|
|
|
1137
1173
|
font.set_embedding_permissions(
|
|
@@ -1151,7 +1187,7 @@ based on provided class_id and subclass_id.
|
|
|
1151
1187
|
|
|
1152
1188
|
:param class_id: Numeric identifier of the font family class.
|
|
1153
1189
|
:param subclass_id: Optional numeric identifier of the font family subclass (default is 0).
|
|
1154
|
-
:raises
|
|
1190
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1155
1191
|
:raises ArgumentError: If class_id is invalid or subclass_id is specified but invalid.
|
|
1156
1192
|
"""
|
|
1157
1193
|
|
|
@@ -1360,15 +1396,26 @@ If an axis min and max values are equal, the axis will be pinned.
|
|
|
1360
1396
|
{'wdth':100, 'wght':[100,600], 'ital':[30,65,70]} or
|
|
1361
1397
|
{'wdth':100, 'wght':{'min':100,'max':600}, 'ital':{'min':30,'default':65,'max':70}}
|
|
1362
1398
|
:type coordinates: dict
|
|
1399
|
+
:param update_names: if True the name records will be updated based on
|
|
1400
|
+
the closest instance to the new default coordinates (only if changed)
|
|
1401
|
+
:type update_names: bool
|
|
1402
|
+
:param update_style_flags: if True the style flags will be updated based on
|
|
1403
|
+
the closest instance to the new default coordinates (only if changed)
|
|
1404
|
+
:type update_style_flags: bool
|
|
1363
1405
|
:param options: The options for the fontTools.varLib.instancer
|
|
1364
1406
|
:type options: dictionary
|
|
1365
1407
|
|
|
1366
|
-
:raises
|
|
1408
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1367
1409
|
:raises ValueError: If the coordinates are not defined (empty)
|
|
1368
1410
|
:raises ValueError: If the coordinates axes are all pinned
|
|
1369
1411
|
"""
|
|
1370
1412
|
|
|
1371
|
-
font.to_sliced_variable(
|
|
1413
|
+
font.to_sliced_variable(
|
|
1414
|
+
coordinates,
|
|
1415
|
+
update_names=True,
|
|
1416
|
+
update_style_flags=True,
|
|
1417
|
+
**options,
|
|
1418
|
+
)
|
|
1372
1419
|
```
|
|
1373
1420
|
|
|
1374
1421
|
#### `to_static`
|
|
@@ -1391,7 +1438,7 @@ If coordinates are not specified each axis will be pinned at its default value.
|
|
|
1391
1438
|
:param options: The options for the fontTools.varLib.instancer
|
|
1392
1439
|
:type options: dictionary
|
|
1393
1440
|
|
|
1394
|
-
:raises
|
|
1441
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1395
1442
|
:raises ValueError: If the coordinates axes are not all pinned
|
|
1396
1443
|
"""
|
|
1397
1444
|
|
|
@@ -85,6 +85,7 @@ with open("fonts/MyFont.ttf") as fh:
|
|
|
85
85
|
- [`is_static`](#is_static)
|
|
86
86
|
- [`is_variable`](#is_variable)
|
|
87
87
|
- [`rename`](#rename)
|
|
88
|
+
- [`rename_variable_instances`](#rename_variable_instances)
|
|
88
89
|
- [`sanitize`](#sanitize)
|
|
89
90
|
- [`save`](#save)
|
|
90
91
|
- [`save_as_woff`](#save_as_woff)
|
|
@@ -119,7 +120,7 @@ font_clone = font.clone()
|
|
|
119
120
|
```python
|
|
120
121
|
"""
|
|
121
122
|
Close the wrapped TTFont instance.
|
|
122
|
-
After closing, any operation on the font raises
|
|
123
|
+
After closing, any operation on the font raises ClosedFontError,
|
|
123
124
|
closing an already closed font does nothing.
|
|
124
125
|
"""
|
|
125
126
|
|
|
@@ -566,7 +567,7 @@ Gets the wrapped TTFont instance.
|
|
|
566
567
|
:returns: The TTFont instance.
|
|
567
568
|
:rtype: TTFont
|
|
568
569
|
|
|
569
|
-
:raises
|
|
570
|
+
:raises ClosedFontError: If the font has been closed.
|
|
570
571
|
"""
|
|
571
572
|
|
|
572
573
|
ttfont = font.get_ttfont()
|
|
@@ -902,6 +903,8 @@ variable = font.is_variable()
|
|
|
902
903
|
"""
|
|
903
904
|
Renames the font names records (1, 2, 4, 6, 16, 17) according to
|
|
904
905
|
the given family_name and style_name (subfamily_name).
|
|
906
|
+
The names records (18, 25), the fvar named instances PostScript names
|
|
907
|
+
and the CFF table names are updated too, only if already defined.
|
|
905
908
|
|
|
906
909
|
If family_name is not defined it will be auto-detected.
|
|
907
910
|
If style_name is not defined it will be auto-detected.
|
|
@@ -921,6 +924,39 @@ font.rename(
|
|
|
921
924
|
)
|
|
922
925
|
```
|
|
923
926
|
|
|
927
|
+
#### `rename_variable_instances`
|
|
928
|
+
```python
|
|
929
|
+
"""
|
|
930
|
+
Renames the named instances of the variable font.
|
|
931
|
+
|
|
932
|
+
The family_name replaces the family part of the instances PostScript names
|
|
933
|
+
(and of the variations PostScript name prefix, if defined).
|
|
934
|
+
The style_names replace the instances style names and the style part
|
|
935
|
+
of their PostScript names. The axes names are unchanged.
|
|
936
|
+
The default instance style name must match the font style name,
|
|
937
|
+
so renaming it renames the font style too.
|
|
938
|
+
|
|
939
|
+
If family_name is not defined it will be auto-detected.
|
|
940
|
+
|
|
941
|
+
:param family_name: The family name
|
|
942
|
+
:type family_name: str
|
|
943
|
+
:param style_names: The new style names mapped by the old ones (case-insensitive),
|
|
944
|
+
eg. {"Thin": "Hairline"}
|
|
945
|
+
:type style_names: dict or None
|
|
946
|
+
:param update_style_flags: if True the style flags will be updated by subfamily name
|
|
947
|
+
(only if the default instance style name is renamed)
|
|
948
|
+
:type update_style_flags: bool
|
|
949
|
+
|
|
950
|
+
:raises VariableFontRequiredError: if the font is not a variable font.
|
|
951
|
+
"""
|
|
952
|
+
|
|
953
|
+
font.rename_variable_instances(
|
|
954
|
+
family_name="My Font New",
|
|
955
|
+
style_names={"Thin": "Hairline"},
|
|
956
|
+
update_style_flags=True,
|
|
957
|
+
)
|
|
958
|
+
```
|
|
959
|
+
|
|
924
960
|
#### `sanitize`
|
|
925
961
|
```python
|
|
926
962
|
"""
|
|
@@ -1031,7 +1067,7 @@ Save all instances of a variable font to specified directory in one or more form
|
|
|
1031
1067
|
includes 'instance' (containing instance metadata) and 'files' (a dictionary
|
|
1032
1068
|
with file formats as keys and file-paths as values).
|
|
1033
1069
|
|
|
1034
|
-
:raises
|
|
1070
|
+
:raises VariableFontRequiredError: If the font is not a variable font.
|
|
1035
1071
|
"""
|
|
1036
1072
|
|
|
1037
1073
|
saved_fonts = font.save_variable_instances(
|
|
@@ -1067,7 +1103,7 @@ The fsType field is left untouched if any argument is invalid.
|
|
|
1067
1103
|
:raises ArgumentError: If a value is not a bool or None, if more than one
|
|
1068
1104
|
of the mutually exclusive usage permissions is set to True, or if
|
|
1069
1105
|
installable is set to False while no other usage permission is in effect.
|
|
1070
|
-
:raises
|
|
1106
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1071
1107
|
"""
|
|
1072
1108
|
|
|
1073
1109
|
font.set_embedding_permissions(
|
|
@@ -1087,7 +1123,7 @@ based on provided class_id and subclass_id.
|
|
|
1087
1123
|
|
|
1088
1124
|
:param class_id: Numeric identifier of the font family class.
|
|
1089
1125
|
:param subclass_id: Optional numeric identifier of the font family subclass (default is 0).
|
|
1090
|
-
:raises
|
|
1126
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1091
1127
|
:raises ArgumentError: If class_id is invalid or subclass_id is specified but invalid.
|
|
1092
1128
|
"""
|
|
1093
1129
|
|
|
@@ -1296,15 +1332,26 @@ If an axis min and max values are equal, the axis will be pinned.
|
|
|
1296
1332
|
{'wdth':100, 'wght':[100,600], 'ital':[30,65,70]} or
|
|
1297
1333
|
{'wdth':100, 'wght':{'min':100,'max':600}, 'ital':{'min':30,'default':65,'max':70}}
|
|
1298
1334
|
:type coordinates: dict
|
|
1335
|
+
:param update_names: if True the name records will be updated based on
|
|
1336
|
+
the closest instance to the new default coordinates (only if changed)
|
|
1337
|
+
:type update_names: bool
|
|
1338
|
+
:param update_style_flags: if True the style flags will be updated based on
|
|
1339
|
+
the closest instance to the new default coordinates (only if changed)
|
|
1340
|
+
:type update_style_flags: bool
|
|
1299
1341
|
:param options: The options for the fontTools.varLib.instancer
|
|
1300
1342
|
:type options: dictionary
|
|
1301
1343
|
|
|
1302
|
-
:raises
|
|
1344
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1303
1345
|
:raises ValueError: If the coordinates are not defined (empty)
|
|
1304
1346
|
:raises ValueError: If the coordinates axes are all pinned
|
|
1305
1347
|
"""
|
|
1306
1348
|
|
|
1307
|
-
font.to_sliced_variable(
|
|
1349
|
+
font.to_sliced_variable(
|
|
1350
|
+
coordinates,
|
|
1351
|
+
update_names=True,
|
|
1352
|
+
update_style_flags=True,
|
|
1353
|
+
**options,
|
|
1354
|
+
)
|
|
1308
1355
|
```
|
|
1309
1356
|
|
|
1310
1357
|
#### `to_static`
|
|
@@ -1327,7 +1374,7 @@ If coordinates are not specified each axis will be pinned at its default value.
|
|
|
1327
1374
|
:param options: The options for the fontTools.varLib.instancer
|
|
1328
1375
|
:type options: dictionary
|
|
1329
1376
|
|
|
1330
|
-
:raises
|
|
1377
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1331
1378
|
:raises ValueError: If the coordinates axes are not all pinned
|
|
1332
1379
|
"""
|
|
1333
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(
|
|
@@ -1227,6 +1228,8 @@ class Font:
|
|
|
1227
1228
|
"""
|
|
1228
1229
|
Renames the font names records (1, 2, 4, 6, 16, 17) according to
|
|
1229
1230
|
the given family_name and style_name (subfamily_name).
|
|
1231
|
+
The names records (18, 25), the fvar named instances PostScript names
|
|
1232
|
+
and the CFF table names are updated too, only if already defined.
|
|
1230
1233
|
|
|
1231
1234
|
If family_name is not defined it will be auto-detected.
|
|
1232
1235
|
If style_name is not defined it will be auto-detected.
|
|
@@ -1247,6 +1250,48 @@ class Font:
|
|
|
1247
1250
|
if update_style_flags:
|
|
1248
1251
|
self.set_style_flags_by_subfamily_name()
|
|
1249
1252
|
|
|
1253
|
+
def rename_variable_instances(
|
|
1254
|
+
self,
|
|
1255
|
+
*,
|
|
1256
|
+
family_name: str = "",
|
|
1257
|
+
style_names: dict[str, str] | None = None,
|
|
1258
|
+
update_style_flags: bool = True,
|
|
1259
|
+
) -> None:
|
|
1260
|
+
"""
|
|
1261
|
+
Renames the named instances of the variable font.
|
|
1262
|
+
|
|
1263
|
+
The family_name replaces the family part of the instances PostScript names
|
|
1264
|
+
(and of the variations PostScript name prefix, if defined).
|
|
1265
|
+
The style_names replace the instances style names and the style part
|
|
1266
|
+
of their PostScript names. The axes names are unchanged.
|
|
1267
|
+
The default instance style name must match the font style name,
|
|
1268
|
+
so renaming it renames the font style too.
|
|
1269
|
+
|
|
1270
|
+
If family_name is not defined it will be auto-detected.
|
|
1271
|
+
|
|
1272
|
+
:param family_name: The family name
|
|
1273
|
+
:type family_name: str
|
|
1274
|
+
:param style_names: The new style names mapped by the old ones (case-insensitive),
|
|
1275
|
+
eg. {"Thin": "Hairline"}
|
|
1276
|
+
:type style_names: dict or None
|
|
1277
|
+
:param update_style_flags: if True the style flags will be updated by subfamily name
|
|
1278
|
+
(only if the default instance style name is renamed)
|
|
1279
|
+
:type update_style_flags: bool
|
|
1280
|
+
|
|
1281
|
+
:raises VariableFontRequiredError: if the font is not a variable font.
|
|
1282
|
+
:return: None
|
|
1283
|
+
"""
|
|
1284
|
+
ttfont = self.get_ttfont()
|
|
1285
|
+
style_name = self.get_style_name()
|
|
1286
|
+
_names.rename_variable_instances(
|
|
1287
|
+
ttfont,
|
|
1288
|
+
family_name=family_name,
|
|
1289
|
+
style_names=style_names,
|
|
1290
|
+
)
|
|
1291
|
+
|
|
1292
|
+
if update_style_flags and self.get_style_name() != style_name:
|
|
1293
|
+
self.set_style_flags_by_subfamily_name()
|
|
1294
|
+
|
|
1250
1295
|
def sanitize(
|
|
1251
1296
|
self,
|
|
1252
1297
|
*,
|
|
@@ -1468,10 +1513,10 @@ class Font:
|
|
|
1468
1513
|
includes 'instance' (containing instance metadata) and 'files' (a dictionary
|
|
1469
1514
|
with file formats as keys and file-paths as values).
|
|
1470
1515
|
|
|
1471
|
-
:raises
|
|
1516
|
+
:raises VariableFontRequiredError: If the font is not a variable font.
|
|
1472
1517
|
"""
|
|
1473
1518
|
if not self.is_variable():
|
|
1474
|
-
raise
|
|
1519
|
+
raise VariableFontRequiredError("Only a variable font can be instantiated.")
|
|
1475
1520
|
|
|
1476
1521
|
fsutil.assert_not_file(dirpath)
|
|
1477
1522
|
fsutil.make_dirs(dirpath)
|
|
@@ -1526,7 +1571,7 @@ class Font:
|
|
|
1526
1571
|
|
|
1527
1572
|
:param class_id: Numeric identifier of the font family class.
|
|
1528
1573
|
:param subclass_id: Optional numeric identifier of the font family subclass (default is 0).
|
|
1529
|
-
:raises
|
|
1574
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1530
1575
|
:raises ArgumentError: If class_id is invalid or subclass_id is specified but invalid.
|
|
1531
1576
|
"""
|
|
1532
1577
|
ttfont = self.get_ttfont()
|
|
@@ -1679,7 +1724,7 @@ class Font:
|
|
|
1679
1724
|
:raises ArgumentError: If a value is not a bool or None, if more than one
|
|
1680
1725
|
of the mutually exclusive usage permissions is set to True, or if
|
|
1681
1726
|
installable is set to False while no other usage permission is in effect.
|
|
1682
|
-
:raises
|
|
1727
|
+
:raises MissingTableError: If the OS/2 table is not available in the font.
|
|
1683
1728
|
"""
|
|
1684
1729
|
ttfont = self.get_ttfont()
|
|
1685
1730
|
_embedding_permissions.set_embedding_permissions(
|
|
@@ -1791,6 +1836,8 @@ class Font:
|
|
|
1791
1836
|
self,
|
|
1792
1837
|
*,
|
|
1793
1838
|
coordinates: dict[str, Any],
|
|
1839
|
+
update_names: bool = True,
|
|
1840
|
+
update_style_flags: bool = True,
|
|
1794
1841
|
**options: Any,
|
|
1795
1842
|
) -> None:
|
|
1796
1843
|
"""
|
|
@@ -1805,15 +1852,27 @@ class Font:
|
|
|
1805
1852
|
{'wdth':100, 'wght':[100,600], 'ital':[30,65,70]} or
|
|
1806
1853
|
{'wdth':100, 'wght':{'min':100,'max':600}, 'ital':{'min':30,'default':65,'max':70}}
|
|
1807
1854
|
:type coordinates: dict
|
|
1855
|
+
:param update_names: if True the name records will be updated based on
|
|
1856
|
+
the closest instance to the new default coordinates (only if changed)
|
|
1857
|
+
:type update_names: bool
|
|
1858
|
+
:param update_style_flags: if True the style flags will be updated based on
|
|
1859
|
+
the closest instance to the new default coordinates (only if changed)
|
|
1860
|
+
:type update_style_flags: bool
|
|
1808
1861
|
:param options: The options for the fontTools.varLib.instancer
|
|
1809
1862
|
:type options: dictionary
|
|
1810
1863
|
|
|
1811
|
-
:raises
|
|
1864
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1812
1865
|
:raises ValueError: If the coordinates are not defined (blank)
|
|
1813
1866
|
:raises ValueError: If the coordinates axes are all pinned
|
|
1814
1867
|
"""
|
|
1815
1868
|
ttfont = self.get_ttfont()
|
|
1816
|
-
_variable.to_sliced_variable(
|
|
1869
|
+
_variable.to_sliced_variable(
|
|
1870
|
+
ttfont,
|
|
1871
|
+
coordinates=coordinates,
|
|
1872
|
+
update_names=update_names,
|
|
1873
|
+
update_style_flags=update_style_flags,
|
|
1874
|
+
**options,
|
|
1875
|
+
)
|
|
1817
1876
|
|
|
1818
1877
|
def to_static(
|
|
1819
1878
|
self,
|
|
@@ -1842,7 +1901,7 @@ class Font:
|
|
|
1842
1901
|
:param options: The options for the fontTools.varLib.instancer
|
|
1843
1902
|
:type options: dictionary
|
|
1844
1903
|
|
|
1845
|
-
:raises
|
|
1904
|
+
:raises VariableFontRequiredError: If the font is not a variable font
|
|
1846
1905
|
:raises ValueError: If the coordinates axes are not all pinned
|
|
1847
1906
|
"""
|
|
1848
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
|
|