python-fontbro 0.27.0__tar.gz → 0.28.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.
Files changed (92) hide show
  1. {python_fontbro-0.27.0/python_fontbro.egg-info → python_fontbro-0.28.1}/PKG-INFO +342 -24
  2. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/README.md +340 -23
  3. python_fontbro-0.28.1/fontbro/bitmap.py +59 -0
  4. python_fontbro-0.28.1/fontbro/color.py +16 -0
  5. python_fontbro-0.28.1/fontbro/embedding_permissions.py +123 -0
  6. python_fontbro-0.28.1/fontbro/family_classification.py +175 -0
  7. python_fontbro-0.28.1/fontbro/features.py +48 -0
  8. python_fontbro-0.28.1/fontbro/files.py +106 -0
  9. python_fontbro-0.28.1/fontbro/fingerprint.py +54 -0
  10. python_fontbro-0.28.1/fontbro/font.py +1796 -0
  11. python_fontbro-0.28.1/fontbro/glyphs.py +82 -0
  12. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/metadata.py +1 -1
  13. python_fontbro-0.28.1/fontbro/metrics.py +178 -0
  14. python_fontbro-0.28.1/fontbro/monospace.py +86 -0
  15. python_fontbro-0.28.1/fontbro/names.py +295 -0
  16. python_fontbro-0.28.1/fontbro/pixel.py +237 -0
  17. python_fontbro-0.28.1/fontbro/render.py +86 -0
  18. python_fontbro-0.28.1/fontbro/sanitize.py +42 -0
  19. python_fontbro-0.28.1/fontbro/style_flags.py +140 -0
  20. python_fontbro-0.28.1/fontbro/subset.py +71 -0
  21. python_fontbro-0.28.1/fontbro/support.py +284 -0
  22. python_fontbro-0.28.1/fontbro/tables.py +138 -0
  23. python_fontbro-0.28.1/fontbro/unicode.py +210 -0
  24. python_fontbro-0.28.1/fontbro/variable.py +377 -0
  25. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/pyproject.toml +1 -0
  26. {python_fontbro-0.27.0 → python_fontbro-0.28.1/python_fontbro.egg-info}/PKG-INFO +342 -24
  27. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/python_fontbro.egg-info/SOURCES.txt +25 -0
  28. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/python_fontbro.egg-info/requires.txt +1 -0
  29. python_fontbro-0.28.1/tests/test_bitmap.py +85 -0
  30. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_characters.py +24 -0
  31. python_fontbro-0.28.1/tests/test_close.py +61 -0
  32. python_fontbro-0.28.1/tests/test_context_manager.py +24 -0
  33. python_fontbro-0.28.1/tests/test_embedding_permissions.py +227 -0
  34. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_fingerprint.py +6 -6
  35. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_glyphs.py +8 -0
  36. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_instantiation.py +18 -0
  37. python_fontbro-0.28.1/tests/test_monospace.py +52 -0
  38. python_fontbro-0.28.1/tests/test_names.py +206 -0
  39. python_fontbro-0.28.1/tests/test_pixel.py +191 -0
  40. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_sanitize.py +25 -4
  41. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_style_flags.py +37 -0
  42. python_fontbro-0.28.1/tests/test_support.py +178 -0
  43. python_fontbro-0.28.1/tests/test_svg.py +35 -0
  44. python_fontbro-0.28.1/tests/test_tables.py +149 -0
  45. python_fontbro-0.28.1/tests/test_unicode.py +43 -0
  46. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_width.py +22 -0
  47. python_fontbro-0.27.0/fontbro/font.py +0 -2404
  48. python_fontbro-0.27.0/fontbro/subset.py +0 -28
  49. python_fontbro-0.27.0/tests/test_close.py +0 -15
  50. python_fontbro-0.27.0/tests/test_context_manager.py +0 -15
  51. python_fontbro-0.27.0/tests/test_monospace.py +0 -17
  52. python_fontbro-0.27.0/tests/test_names.py +0 -82
  53. python_fontbro-0.27.0/tests/test_svg.py +0 -20
  54. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/LICENSE.txt +0 -0
  55. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/MANIFEST.in +0 -0
  56. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/__init__.py +0 -0
  57. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/data/family-classifications.json +0 -0
  58. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/data/features.json +0 -0
  59. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/data/unicode-blocks.json +0 -0
  60. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/data/unicode-scripts.json +0 -0
  61. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/exceptions.py +0 -0
  62. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/flags.py +0 -0
  63. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/math.py +0 -0
  64. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/py.typed +0 -0
  65. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/fontbro/utils.py +0 -0
  66. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/python_fontbro.egg-info/dependency_links.txt +0 -0
  67. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/python_fontbro.egg-info/top_level.txt +0 -0
  68. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/setup.cfg +0 -0
  69. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/setup.py +0 -0
  70. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_clone.py +0 -0
  71. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_collection.py +0 -0
  72. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_color.py +0 -0
  73. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_family_classification.py +0 -0
  74. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_family_name.py +0 -0
  75. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_features.py +0 -0
  76. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_filename.py +0 -0
  77. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_format.py +0 -0
  78. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_image.py +0 -0
  79. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_init.py +0 -0
  80. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_issues.py +0 -0
  81. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_italic_angle.py +0 -0
  82. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_rename.py +0 -0
  83. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_save.py +0 -0
  84. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_str.py +0 -0
  85. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_style_name.py +0 -0
  86. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_subset.py +0 -0
  87. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_unicode_blocks_and_scripts.py +0 -0
  88. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_update_unicode_data.py +0 -0
  89. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_variable.py +0 -0
  90. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_version.py +0 -0
  91. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_vertical_metrics.py +0 -0
  92. {python_fontbro-0.27.0 → python_fontbro-0.28.1}/tests/test_weight.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-fontbro
3
- Version: 0.27.0
3
+ Version: 0.28.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>
@@ -55,6 +55,7 @@ Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
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
58
+ Requires-Dist: gflanguages<1.0.0,>=0.7.11
58
59
  Requires-Dist: imagehash<5.0.0,>=4.2.1
59
60
  Requires-Dist: opentype-sanitizer<10.0.0,>=9.1.0
60
61
  Requires-Dist: pillow<13.0.0,>=12.2.0
@@ -73,6 +74,7 @@ Dynamic: license-file
73
74
  [![](https://img.shields.io/codacy/grade/dd3a046db4b14b988a2f1fcfbfaa51eb?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/python-fontbro)
74
75
  [![](https://img.shields.io/badge/code%20style-black-000000.svg?logo=python&logoColor=black)](https://github.com/psf/black)
75
76
  [![](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
77
+ [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/fabiocaccamo/python-fontbro/badge)](https://securityscorecards.dev/viewer/?uri=github.com/fabiocaccamo/python-fontbro)
76
78
 
77
79
  # python-fontbro
78
80
  friendly font operations on top of `fontTools`. :billed_cap:
@@ -101,6 +103,7 @@ with open("fonts/MyFont.ttf") as fh:
101
103
  - [`from_collection`](#from_collection)
102
104
  - [`get_characters`](#get_characters)
103
105
  - [`get_characters_count`](#get_characters_count)
106
+ - [`get_embedding_permissions`](#get_embedding_permissions)
104
107
  - [`get_family_classification`](#get_family_classification)
105
108
  - [`get_family_name`](#get_family_name)
106
109
  - [`get_features`](#get_features)
@@ -118,7 +121,11 @@ with open("fonts/MyFont.ttf") as fh:
118
121
  - [`get_style_flag`](#get_style_flag)
119
122
  - [`get_style_flags`](#get_style_flags)
120
123
  - [`get_style_name`](#get_style_name)
124
+ - [`get_supported_languages`](#get_supported_languages)
125
+ - [`get_supported_writing_systems`](#get_supported_writing_systems)
121
126
  - [`get_svg`](#get_svg)
127
+ - [`get_tables`](#get_tables)
128
+ - [`get_tables_tags`](#get_tables_tags)
122
129
  - [`get_ttfont`](#get_ttfont)
123
130
  - [`get_unicode_block_by_name`](#get_unicode_block_by_name)
124
131
  - [`get_unicode_blocks`](#get_unicode_blocks)
@@ -134,8 +141,10 @@ with open("fonts/MyFont.ttf") as fh:
134
141
  - [`get_vertical_metrics`](#get_vertical_metrics)
135
142
  - [`get_weight`](#get_weight)
136
143
  - [`get_width`](#get_width)
144
+ - [`is_bitmap`](#is_bitmap)
137
145
  - [`is_color`](#is_color)
138
146
  - [`is_monospace`](#is_monospace)
147
+ - [`is_pixel`](#is_pixel)
139
148
  - [`is_static`](#is_static)
140
149
  - [`is_variable`](#is_variable)
141
150
  - [`rename`](#rename)
@@ -145,6 +154,7 @@ with open("fonts/MyFont.ttf") as fh:
145
154
  - [`save_as_woff2`](#save_as_woff2)
146
155
  - [`save_to_file_object`](#save_to_file_object)
147
156
  - [`save_variable_instances`](#save_variable_instances)
157
+ - [`set_embedding_permissions`](#set_embedding_permissions)
148
158
  - [`set_family_classification`](#set_family_classification)
149
159
  - [`set_family_name`](#set_family_name)
150
160
  - [`set_name`](#set_name)
@@ -163,6 +173,7 @@ with open("fonts/MyFont.ttf") as fh:
163
173
  """
164
174
  Creates a new Font instance reading the same binary file.
165
175
  """
176
+
166
177
  font_clone = font.clone()
167
178
  ```
168
179
 
@@ -170,7 +181,10 @@ font_clone = font.clone()
170
181
  ```python
171
182
  """
172
183
  Close the wrapped TTFont instance.
184
+ After closing, any operation on the font raises OperationError,
185
+ closing an already closed font does nothing.
173
186
  """
187
+
174
188
  font.close()
175
189
  ```
176
190
 
@@ -185,6 +199,7 @@ Gets a list of Font objects from a font collection file (.ttc / .otc)
185
199
  :returns: A list of Font objects.
186
200
  :rtype: list
187
201
  """
202
+
188
203
  fonts = Font.from_collection(filepath="my-font-collection.ttc")
189
204
  ```
190
205
 
@@ -199,8 +214,9 @@ Gets the font characters.
199
214
  :returns: The characters.
200
215
  :rtype: generator of dicts
201
216
 
202
- :raises TypeError: If it's not possible to find the 'best' unicode cmap dict in the font.
217
+ :raises DataError: If it's not possible to find the 'best' unicode cmap dict in the font.
203
218
  """
219
+
204
220
  chars = font.get_characters(ignore_blank=False)
205
221
  ```
206
222
 
@@ -215,9 +231,26 @@ Gets the font characters count.
215
231
  :returns: The characters count.
216
232
  :rtype: int
217
233
  """
234
+
218
235
  chars_count = font.get_characters_count(ignore_blank=False)
219
236
  ```
220
237
 
238
+ #### `get_embedding_permissions`
239
+ ```python
240
+ """
241
+ Gets the embedding permissions from the OS/2 fsType field.
242
+ "installable" is True only when none of "restricted", "preview_and_print"
243
+ and "editable" is set, since they are mutually exclusive usage permissions.
244
+
245
+ :returns: A dictionary representing the embedding permission flags.
246
+ :rtype: dict
247
+ """
248
+
249
+ permissions = font.get_embedding_permissions()
250
+ # {'installable': True, 'restricted': False, 'preview_and_print': False,
251
+ # 'editable': False, 'no_subsetting': False, 'bitmap_embedding_only': False}
252
+ ```
253
+
221
254
  #### `get_family_classification`
222
255
  ```python
223
256
  """
@@ -235,6 +268,7 @@ If the OS/2 table is not available None is returned.
235
268
  }
236
269
  :rtype: dict
237
270
  """
271
+
238
272
  family_classification = font.get_family_classification()
239
273
  ```
240
274
 
@@ -246,6 +280,7 @@ Gets the family name reading the name records with priority order (16, 21, 1).
246
280
  :returns: The font family name.
247
281
  :rtype: str
248
282
  """
283
+
249
284
  family_name = font.get_family_name()
250
285
  ```
251
286
 
@@ -257,6 +292,7 @@ Gets the font opentype features.
257
292
  :returns: The features.
258
293
  :rtype: list of dict
259
294
  """
295
+
260
296
  features = font.get_features()
261
297
  ```
262
298
 
@@ -268,6 +304,7 @@ Gets the font opentype features tags.
268
304
  :returns: The features tags list.
269
305
  :rtype: list of str
270
306
  """
307
+
271
308
  features_tags = font.get_features_tags()
272
309
  ```
273
310
 
@@ -288,7 +325,10 @@ Gets the filename to use for saving the font to file-system.
288
325
  :returns: The filename.
289
326
  :rtype: str
290
327
  """
291
- filename = font.get_filename(variable_suffix="Variable", variable_axes_tags=True, variable_axes_values=False)
328
+
329
+ filename = font.get_filename(
330
+ variable_suffix="Variable", variable_axes_tags=True, variable_axes_values=False
331
+ )
292
332
  ```
293
333
 
294
334
  #### `get_fingerprint`
@@ -302,6 +342,7 @@ Changing the text option affects the returned fingerprint.
302
342
  :returns: The fingerprint hash.
303
343
  :rtype: imagehash.ImageHash
304
344
  """
345
+
305
346
  hash = font.get_fingerprint()
306
347
  ```
307
348
 
@@ -320,7 +361,10 @@ by checking if their fingerprints are equal (difference <= tolerance).
320
361
  :returns: A tuple containing the match info (match, diff, hash, other_hash).
321
362
  :rtype: tuple
322
363
  """
323
- match, diff, hash, other_hash = font.get_fingerprint_match(other="other_font.ttf", tolerance=10)
364
+
365
+ match, diff, hash, other_hash = font.get_fingerprint_match(
366
+ other="other_font.ttf", tolerance=10
367
+ )
324
368
  ```
325
369
 
326
370
  #### `get_format`
@@ -334,6 +378,7 @@ Gets the font format: otf, ttf, woff, woff2.
334
378
  :returns: The format.
335
379
  :rtype: str or None
336
380
  """
381
+
337
382
  format = font.get_format(ignore_flavor=False)
338
383
  ```
339
384
 
@@ -345,6 +390,7 @@ Gets the font glyphs and their own composition.
345
390
  :returns: The glyphs.
346
391
  :rtype: generator of dicts
347
392
  """
393
+
348
394
  glyphs = font.get_glyphs()
349
395
  ```
350
396
 
@@ -356,6 +402,7 @@ Gets the font glyphs count.
356
402
  :returns: The glyphs count.
357
403
  :rtype: int
358
404
  """
405
+
359
406
  glyphs_count = font.get_glyphs_count()
360
407
  ```
361
408
 
@@ -374,7 +421,10 @@ some text using the given options.
374
421
  :param background_color: The background color
375
422
  :type background_color: tuple
376
423
  """
377
- img = font.get_image(text="Hello!", size=48, color=(0, 0, 0, 255), background_color=(255, 255, 255, 255))
424
+
425
+ img = font.get_image(
426
+ text="Hello!", size=48, color=(0, 0, 0, 255), background_color=(255, 255, 255, 255)
427
+ )
378
428
  ```
379
429
 
380
430
  #### `get_italic_angle`
@@ -385,6 +435,7 @@ Gets the font italic angle.
385
435
  :returns: The angle value including backslant, italic and roman flags.
386
436
  :rtype: dict or None
387
437
  """
438
+
388
439
  italic_angle = font.get_italic_angle()
389
440
  ```
390
441
 
@@ -401,6 +452,7 @@ Gets the name by its identifier from the font name table.
401
452
 
402
453
  :raises KeyError: if the key is not a valid name key/id
403
454
  """
455
+
404
456
  family_name = font.get_name(key=Font.NAME_FAMILY_NAME)
405
457
  ```
406
458
 
@@ -412,6 +464,7 @@ Gets the names records mapped by their property name.
412
464
  :returns: The names.
413
465
  :rtype: dict
414
466
  """
467
+
415
468
  names = font.get_names()
416
469
  ```
417
470
 
@@ -426,6 +479,7 @@ Gets the style flag reading OS/2 and macStyle tables.
426
479
  :returns: The style flag.
427
480
  :rtype: bool
428
481
  """
482
+
429
483
  flag = font.get_style_flag(Font.STYLE_FLAG_BOLD)
430
484
  ```
431
485
 
@@ -437,6 +491,7 @@ Gets the style flags reading OS/2 and macStyle tables.
437
491
  :returns: The dict representing the style flags.
438
492
  :rtype: dict
439
493
  """
494
+
440
495
  flags = font.get_style_flags()
441
496
  ```
442
497
 
@@ -448,9 +503,60 @@ Gets the style name reading the name records with priority order (17, 22, 2).
448
503
  :returns: The font style name.
449
504
  :rtype: str
450
505
  """
506
+
451
507
  style_name = font.get_style_name()
452
508
  ```
453
509
 
510
+ #### `get_supported_languages`
511
+ ```python
512
+ """
513
+ Gets the languages supported by the font and their coverage.
514
+ Only languages with coverage >= coverage_threshold (0.0 <= coverage_threshold <= 1.0) will be returned.
515
+ The coverage is the ratio of the base characters of the language
516
+ (as defined by the Google Fonts languages dataset) available in the font.
517
+
518
+ :param coverage_threshold: The minumum required coverage for a language to be returned.
519
+ :type coverage_threshold: float
520
+
521
+ :returns: The list of supported languages.
522
+ :rtype: list of dicts
523
+
524
+ :raises DataError: If it's not possible to find the 'best' unicode cmap dict.
525
+ """
526
+
527
+ languages = font.get_supported_languages(coverage_threshold=1.0)
528
+ # [{'code': 'en_Latn', 'name': 'English', 'writing_system_code': 'Latn',
529
+ # 'writing_system_name': 'Latin', 'coverage': 1.0, 'sample_texts': {...}}, ...]
530
+ ```
531
+
532
+ #### `get_supported_writing_systems`
533
+ ```python
534
+ """
535
+ Gets the writing systems supported by the font and their coverage.
536
+ A writing system is supported if at least one of its languages is supported,
537
+ the coverage is the ratio of the base characters of all its languages
538
+ (as defined by the Google Fonts languages dataset) available in the font.
539
+
540
+ :param coverage_threshold: The minumum required coverage for a language to be considered supported.
541
+ :type coverage_threshold: float
542
+ :param include_uncommon: If False, only the most common writing systems are returned.
543
+ :type include_uncommon: bool
544
+ :param prioritize_common: If True, the most common writing systems are returned first in a predefined order, otherwise all of them are sorted by name.
545
+ :type prioritize_common: bool
546
+
547
+ :returns: The list of supported writing systems.
548
+ :rtype: list of dicts
549
+
550
+ :raises DataError: If it's not possible to find the 'best' unicode cmap dict.
551
+ """
552
+
553
+ writing_systems = font.get_supported_writing_systems(
554
+ coverage_threshold=1.0, include_uncommon=True, prioritize_common=True
555
+ )
556
+ # [{'code': 'Latn', 'name': 'Latin', 'coverage': 0.55, 'languages_count': 894,
557
+ # 'languages_supported_count': 375, 'sample_texts': {...}}, ...]
558
+ ```
559
+
454
560
  #### `get_svg`
455
561
  ```python
456
562
  """
@@ -464,10 +570,56 @@ some text using the given options.
464
570
 
465
571
  :returns: An SVG string that represents the rendered text.
466
572
  :rtype: str
573
+
574
+ :raises DataError: If it's not possible to find the 'best' unicode cmap dict.
467
575
  """
576
+
468
577
  svg_str = font.get_svg(text="Hello!", size=48)
469
578
  ```
470
579
 
580
+ #### `get_tables`
581
+ ```python
582
+ """
583
+ Gets the table metadata present in the font.
584
+ Unknown tables are the ones not defined by the OpenType specification
585
+ or by the Apple TrueType Reference Manual, their name is their tag.
586
+ The length is the uncompressed table length (also for woff/woff2 fonts),
587
+ the offset is the position of the table data in the loaded font file,
588
+ it's None for woff2 fonts because tables are stored in a single
589
+ compressed stream and have no individual offset in the file.
590
+ Both length and offset are read from the originally loaded font file,
591
+ so they will be None for tables added in-memory that haven't been saved.
592
+
593
+ :param include_unknown: If False, unknown tables are excluded.
594
+ :type include_unknown: bool
595
+
596
+ :returns: The list of table metadata dictionaries.
597
+ :rtype: list[dict]
598
+ """
599
+
600
+ tables = font.get_tables(include_unknown=True)
601
+ # [{'tag': 'head', 'name': 'Header', 'length': 54, 'offset': 192}, ...]
602
+ ```
603
+
604
+ #### `get_tables_tags`
605
+ ```python
606
+ """
607
+ Gets the tags of the tables present in the font.
608
+ Unknown tables are the ones not defined by the OpenType specification
609
+ or by the Apple TrueType Reference Manual, eg. custom tables or tables
610
+ stored by font editors / tools (eg. VTT "TSI0"..."TSI5", FontForge "FFTM").
611
+
612
+ :param include_unknown: If False, unknown tables are excluded.
613
+ :type include_unknown: bool
614
+
615
+ :returns: The list of table tags.
616
+ :rtype: list[str]
617
+ """
618
+
619
+ tables = font.get_tables_tags(include_unknown=True)
620
+ # ['head', 'hhea', 'maxp', 'OS/2', ...]
621
+ ```
622
+
471
623
  #### `get_ttfont`
472
624
  ```python
473
625
  """
@@ -475,7 +627,10 @@ Gets the wrapped TTFont instance.
475
627
 
476
628
  :returns: The TTFont instance.
477
629
  :rtype: TTFont
630
+
631
+ :raises OperationError: If the font has been closed.
478
632
  """
633
+
479
634
  ttfont = font.get_ttfont()
480
635
  ```
481
636
 
@@ -490,6 +645,7 @@ Gets the unicode block by name (name is case-insensitive and ignores "-").
490
645
  :returns: The unicode block dict if the name is valid, None otherwise.
491
646
  :rtype: dict or None
492
647
  """
648
+
493
649
  block = font.get_unicode_block_by_name(name="Basic Latin")
494
650
  ```
495
651
 
@@ -505,6 +661,7 @@ Only blocks with coverage >= coverage_threshold (0.0 <= coverage_threshold <= 1.
505
661
  :returns: The list of unicode blocks.
506
662
  :rtype: list of dicts
507
663
  """
664
+
508
665
  blocks = font.get_unicode_blocks(coverage_threshold=0.00001)
509
666
  ```
510
667
 
@@ -519,6 +676,7 @@ Gets the unicode script by name/tag (name/tag is case-insensitive and ignores "-
519
676
  :returns: The unicode script dict if the name/tag is valid, None otherwise.
520
677
  :rtype: dict or None
521
678
  """
679
+
522
680
  script = font.get_unicode_script_by_name(name="Latn")
523
681
  ```
524
682
 
@@ -534,6 +692,7 @@ Only scripts with coverage >= coverage_threshold (0.0 <= coverage_threshold <= 1
534
692
  :returns: The list of unicode scripts.
535
693
  :rtype: list of dicts
536
694
  """
695
+
537
696
  scripts = font.get_unicode_scripts(coverage_threshold=0.00001)
538
697
  ```
539
698
 
@@ -545,6 +704,7 @@ Gets the font variable axes.
545
704
  :returns: The list of axes if the font is a variable font otherwise None.
546
705
  :rtype: list of dict or None
547
706
  """
707
+
548
708
  axes = font.get_variable_axes()
549
709
  ```
550
710
 
@@ -556,6 +716,7 @@ Gets the variable axes tags.
556
716
  :returns: The variable axis tags.
557
717
  :rtype: list or None
558
718
  """
719
+
559
720
  axes_tags = font.get_variable_axes_tags()
560
721
  ```
561
722
 
@@ -570,6 +731,7 @@ Gets a variable axis by tag.
570
731
  :returns: The variable axis by tag.
571
732
  :rtype: dict or None
572
733
  """
734
+
573
735
  axis = font.get_variable_axis_by_tag(tag="wght")
574
736
  ```
575
737
 
@@ -581,6 +743,7 @@ Gets the variable instances.
581
743
  :returns: The list of instances if the font is a variable font otherwise None.
582
744
  :rtype: list of dict or None
583
745
  """
746
+
584
747
  instances = font.get_variable_instances()
585
748
  ```
586
749
 
@@ -595,6 +758,7 @@ Gets the variable instance by style name, eg. style_name = 'Bold'
595
758
  :returns: The variable instance matching the given style name.
596
759
  :rtype: dict or None
597
760
  """
761
+
598
762
  instance = font.get_variable_instance_by_style_name(style_name="Bold")
599
763
  ```
600
764
 
@@ -611,7 +775,10 @@ If coordinates do not specify some axes, axes default value is used for lookup.
611
775
  :returns: The variable instance closest to coordinates.
612
776
  :rtype: dict or None
613
777
  """
614
- instance = font.get_variable_instance_closest_to_coordinates(coordinates={"wght": 1000, "slnt": 815, "wdth": 775})
778
+
779
+ instance = font.get_variable_instance_closest_to_coordinates(
780
+ coordinates={"wght": 1000, "slnt": 815, "wdth": 775}
781
+ )
615
782
  ```
616
783
 
617
784
  #### `get_version`
@@ -622,6 +789,7 @@ Gets the font version.
622
789
  :returns: The font version value.
623
790
  :rtype: float
624
791
  """
792
+
625
793
  version = font.get_version()
626
794
  ```
627
795
 
@@ -636,6 +804,7 @@ Gets the font vertical metrics.
636
804
  "win_ascent", "win_descent"
637
805
  :rtype: dict
638
806
  """
807
+
639
808
  metrics = font.get_vertical_metrics()
640
809
  ```
641
810
 
@@ -647,6 +816,7 @@ Gets the font weight value and name.
647
816
  :returns: The weight name and value.
648
817
  :rtype: dict or None
649
818
  """
819
+
650
820
  weight = font.get_weight()
651
821
  ```
652
822
 
@@ -658,9 +828,25 @@ Gets the font width value and name.
658
828
  :returns: The width name and value.
659
829
  :rtype: dict or None
660
830
  """
831
+
661
832
  width = font.get_width()
662
833
  ```
663
834
 
835
+ #### `is_bitmap`
836
+ ```python
837
+ """
838
+ Determines if the font is a bitmap font: glyphs are stored only as
839
+ monochrome bitmaps (EBDT/EBLC or Apple bdat/bloc tables), without outlines.
840
+ Color bitmap fonts (eg. emoji fonts with CBDT/CBLC or sbix tables)
841
+ are not considered bitmap fonts.
842
+
843
+ :returns: True if bitmap font, False otherwise.
844
+ :rtype: bool
845
+ """
846
+
847
+ bitmap = font.is_bitmap()
848
+ ```
849
+
664
850
  #### `is_color`
665
851
  ```python
666
852
  """
@@ -669,21 +855,49 @@ Determines if the font is a color font.
669
855
  :returns: True if color font, False otherwise.
670
856
  :rtype: bool
671
857
  """
858
+
672
859
  color = font.is_color()
673
860
  ```
674
861
 
675
862
  #### `is_monospace`
676
863
  ```python
677
864
  """
678
- Determines if the font is a monospace font.
865
+ Determines if the font is a monospace font (same criteria used by Fontbakery):
866
+ if the font covers at least 80% of the printable ascii characters, at least
867
+ threshold of their glyphs must have the same width, otherwise the glyphs of
868
+ the characters (excluding marks) must have at most 2 different widths
869
+ (eg. cjk monospace fonts with half-width and full-width characters).
870
+ Zero-width glyphs are ignored.
679
871
 
680
- :param threshold: The threshold (0.0 <= n <= 1.0) of glyphs with the same width to consider the font as monospace.
872
+ :param threshold: The threshold (0.0 <= n <= 1.0) of printable ascii characters glyphs with the same width to consider the font as monospace.
681
873
  :type threshold: float
682
874
 
683
875
  :returns: True if monospace font, False otherwise.
684
876
  :rtype: bool
685
877
  """
686
- mono = font.is_monospace(threshold=0.85)
878
+
879
+ mono = font.is_monospace(threshold=0.8)
880
+ ```
881
+
882
+ #### `is_pixel`
883
+ ```python
884
+ """
885
+ Determines if the font is a pixel font: glyphs outlines are drawn
886
+ with pixels (square or rectangular) aligned to a grid
887
+ (horizontal / vertical segments only).
888
+ The check is done on the A-Z, a-z and 0-9 glyphs, or if the font has none
889
+ of them, on the first 50 glyphs (by codepoint) that are not punctuation,
890
+ glyphs without outlines (eg. space) are ignored.
891
+ Bitmap fonts (without outlines) are not considered pixel fonts.
892
+
893
+ :param threshold: The threshold (0.0 <= n <= 1.0) of glyphs drawn with pixels to consider the font as pixel font.
894
+ :type threshold: float
895
+
896
+ :returns: True if pixel font, False otherwise.
897
+ :rtype: bool
898
+ """
899
+
900
+ pixel = font.is_pixel(threshold=0.9)
687
901
  ```
688
902
 
689
903
  #### `is_static`
@@ -694,6 +908,7 @@ Determines if the font is a static font.
694
908
  :returns: True if static font, False otherwise.
695
909
  :rtype: bool
696
910
  """
911
+
697
912
  static = font.is_static()
698
913
  ```
699
914
 
@@ -705,6 +920,7 @@ Determines if the font is a variable font.
705
920
  :returns: True if variable font, False otherwise.
706
921
  :rtype: bool
707
922
  """
923
+
708
924
  variable = font.is_variable()
709
925
  ```
710
926
 
@@ -726,7 +942,10 @@ If style_name is not defined it will be auto-detected.
726
942
 
727
943
  :raises ValueError: if the computed PostScript-name is longer than 63 characters.
728
944
  """
729
- font.rename(family_name="My Font New", style_name="Bold Italic", update_style_flags=True)
945
+
946
+ font.rename(
947
+ family_name="My Font New", style_name="Bold Italic", update_style_flags=True
948
+ )
730
949
  ```
731
950
 
732
951
  #### `sanitize`
@@ -747,6 +966,7 @@ https://github.com/googlefonts/ots-python
747
966
  If `strict` is True (default), treats sanitizer warnings as errors.
748
967
  If `strict` is False, only checks for sanitizer errors.
749
968
  """
969
+
750
970
  font.sanitize(strict=True)
751
971
  ```
752
972
 
@@ -765,6 +985,7 @@ Saves the font at filepath.
765
985
 
766
986
  :raises ValueError: If the filepath is the same of the source font and overwrite is not allowed.
767
987
  """
988
+
768
989
  saved_font_path = font.save(filepath=None, overwrite=False)
769
990
  ```
770
991
 
@@ -781,6 +1002,7 @@ Saves font as woff.
781
1002
  :returns: The filepath where the font has been saved to.
782
1003
  :rtype: str
783
1004
  """
1005
+
784
1006
  saved_font_path = font.save_as_woff(filepath=None, overwrite=True)
785
1007
  ```
786
1008
 
@@ -797,6 +1019,7 @@ Saves font as woff2.
797
1019
  :returns: The filepath where the font has been saved to.
798
1020
  :rtype: str
799
1021
  """
1022
+
800
1023
  saved_font_path = font.save_as_woff2(filepath=None, overwrite=True)
801
1024
  ```
802
1025
 
@@ -838,7 +1061,49 @@ Save all instances of a variable font to specified directory in one or more form
838
1061
  :raises TypeError: If the font is not a variable font.
839
1062
  """
840
1063
 
841
- saved_fonts = font.save_variable_instances(dirpath, woff2=True, woff=True, overwrite=True, **options)
1064
+ saved_fonts = font.save_variable_instances(
1065
+ dirpath, woff2=True, woff=True, overwrite=True, **options
1066
+ )
1067
+ ```
1068
+
1069
+ #### `set_embedding_permissions`
1070
+ ```python
1071
+ """
1072
+ Sets the embedding permissions in the OS/2 fsType field.
1073
+ Keys set to None will be ignored.
1074
+ "installable", "restricted", "preview_and_print" and "editable" are
1075
+ mutually exclusive usage permissions: exactly one of them is always
1076
+ in effect, so setting one of them to True replaces the current one,
1077
+ while setting the current one to False makes the font installable.
1078
+ The fsType field is left untouched if any argument is invalid.
1079
+
1080
+ :param installable: The installable embedding permission flag,
1081
+ it can be False only if another usage permission is in effect.
1082
+ :type installable: bool or None
1083
+ :param restricted: The restricted license embedding permission flag.
1084
+ :type restricted: bool or None
1085
+ :param preview_and_print: The preview and print embedding permission flag.
1086
+ :type preview_and_print: bool or None
1087
+ :param editable: The editable embedding permission flag.
1088
+ :type editable: bool or None
1089
+ :param no_subsetting: The no subsetting embedding permission flag.
1090
+ :type no_subsetting: bool or None
1091
+ :param bitmap_embedding_only: The bitmap-only embedding permission flag.
1092
+ :type bitmap_embedding_only: bool or None
1093
+
1094
+ :raises ArgumentError: If a value is not a bool or None, if more than one
1095
+ of the mutually exclusive usage permissions is set to True, or if
1096
+ installable is set to False while no other usage permission is in effect.
1097
+ :raises OperationError: If the OS/2 table is not available in the font.
1098
+ """
1099
+
1100
+ font.set_embedding_permissions(
1101
+ restricted=False,
1102
+ preview_and_print=True,
1103
+ editable=False,
1104
+ no_subsetting=False,
1105
+ bitmap_embedding_only=False,
1106
+ )
842
1107
  ```
843
1108
 
844
1109
  #### `set_family_classification`
@@ -852,6 +1117,7 @@ based on provided class_id and subclass_id.
852
1117
  :raises OperationError: If the OS/2 table is not available in the font.
853
1118
  :raises ArgumentError: If class_id is invalid or subclass_id is specified but invalid.
854
1119
  """
1120
+
855
1121
  font.set_family_classification(**font.FAMILY_CLASSIFICATION_SCRIPTS_CALLIGRAPHIC)
856
1122
  # alternatively:
857
1123
  font.set_family_classification(class_id=10, subclass_id=5)
@@ -865,6 +1131,7 @@ Sets the family name updating the related font names records.
865
1131
  :param name: The name
866
1132
  :type name: The new family name.
867
1133
  """
1134
+
868
1135
  font.set_family_name(name="My Font New")
869
1136
  ```
870
1137
 
@@ -878,6 +1145,7 @@ Sets the name by its identifier in the font name table.
878
1145
  :param value: The value
879
1146
  :type value: str
880
1147
  """
1148
+
881
1149
  font.set_name(Font.NAME_FAMILY_NAME, "Family Name Renamed")
882
1150
  ```
883
1151
 
@@ -889,10 +1157,13 @@ Sets the names by their identifier in the name table.
889
1157
  :param names: The names
890
1158
  :type names: dict
891
1159
  """
892
- font.set_names(names={
893
- Font.NAME_FAMILY_NAME: "Family Name Renamed",
894
- Font.NAME_SUBFAMILY_NAME: "Regular Renamed",
895
- })
1160
+
1161
+ font.set_names(
1162
+ names={
1163
+ Font.NAME_FAMILY_NAME: "Family Name Renamed",
1164
+ Font.NAME_SUBFAMILY_NAME: "Regular Renamed",
1165
+ }
1166
+ )
896
1167
  ```
897
1168
 
898
1169
  #### `set_style_flag`
@@ -905,24 +1176,45 @@ Sets the style flag.
905
1176
  :param value: The value
906
1177
  :type value: bool
907
1178
  """
1179
+
908
1180
  font.set_style_flag(Font.STYLE_FLAG_BOLD, True)
909
1181
  ```
910
1182
 
911
1183
  #### `set_style_flags`
912
1184
  ```python
913
1185
  """
914
- Sets the style flags, flags set to None will be ignored.
1186
+ Sets the style flags, keys set to None will be ignored.
915
1187
 
916
- :param bold: The bold flag value.
1188
+ :param regular: The regular style flag value
1189
+ :type regular: bool or None
1190
+ :param bold: The bold style flag value
917
1191
  :type bold: bool or None
918
- :param italic: The italic flag value.
1192
+ :param italic: The italic style flag value
919
1193
  :type italic: bool or None
920
- :param underline: The underline flag value.
1194
+ :param underline: The underline style flag value
921
1195
  :type underline: bool or None
922
- :param outline: The outline flag value.
1196
+ :param outline: The outline style flag value
923
1197
  :type outline: bool or None
1198
+ :param shadow: The shadow style flag value
1199
+ :type shadow: bool or None
1200
+ :param condensed: The condensed style flag value
1201
+ :type condensed: bool or None
1202
+ :param extended: The extended style flag value
1203
+ :type extended: bool or None
1204
+
1205
+ :raises ArgumentError: If a value is not a bool or None.
924
1206
  """
925
- font.set_style_flags(regular=None, bold=None, italic=None, outline=None, underline=None)
1207
+
1208
+ font.set_style_flags(
1209
+ regular=None,
1210
+ bold=None,
1211
+ italic=None,
1212
+ underline=None,
1213
+ outline=None,
1214
+ shadow=None,
1215
+ condensed=None,
1216
+ extended=None,
1217
+ )
926
1218
  ```
927
1219
 
928
1220
  #### `set_style_flags_by_subfamily_name`
@@ -932,6 +1224,7 @@ Sets the style flags by the subfamily name value.
932
1224
  The subfamily values should be "regular", "italic", "bold" or "bold italic"
933
1225
  to allow this method to work properly.
934
1226
  """
1227
+
935
1228
  font.set_style_flags_by_subfamily_name()
936
1229
  ```
937
1230
 
@@ -943,6 +1236,7 @@ Sets the style name updating the related font names records.
943
1236
  :param name: The name
944
1237
  :type name: The new style name.
945
1238
  """
1239
+
946
1240
  font.set_style_name(name="Bold Italic")
947
1241
  ```
948
1242
 
@@ -951,12 +1245,27 @@ font.set_style_name(name="Bold Italic")
951
1245
  """
952
1246
  Sets the vertical metrics.
953
1247
 
954
- :param metrics: Keyword arguments representing the vertical metrics that can be set:
1248
+ :param vertical_metrics: Keyword arguments representing the vertical metrics that can be set:
955
1249
  "units_per_em", "y_max", "y_min", "ascent", "descent", "line_gap",
956
1250
  "typo_ascender", "typo_descender", "typo_line_gap", "cap_height", "x_height",
957
1251
  "win_ascent", "win_descent"
958
1252
  """
959
- font.set_vertical_metrics(units_per_em=2000, y_max=2102, y_min=-533, ascent=1800, descent=-400, line_gap=0, typo_ascender=1800, typo_descender=-400, typo_line_gap=0, cap_height=1400, x_height=1080, win_ascent=2160, win_descent=540)
1253
+
1254
+ font.set_vertical_metrics(
1255
+ units_per_em=2000,
1256
+ y_max=2102,
1257
+ y_min=-533,
1258
+ ascent=1800,
1259
+ descent=-400,
1260
+ line_gap=0,
1261
+ typo_ascender=1800,
1262
+ typo_descender=-400,
1263
+ typo_line_gap=0,
1264
+ cap_height=1400,
1265
+ x_height=1080,
1266
+ win_ascent=2160,
1267
+ win_descent=540,
1268
+ )
960
1269
  ```
961
1270
 
962
1271
  #### `subset`
@@ -975,6 +1284,7 @@ https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/subset/__init__.p
975
1284
  :param options: The subsetter options
976
1285
  :type options: dict
977
1286
  """
1287
+
978
1288
  font.subset(unicodes="", glyphs=[], text="", **options)
979
1289
  ```
980
1290
 
@@ -998,6 +1308,7 @@ If an axis min and max values are equal, the axis will be pinned.
998
1308
  :raises ValueError: If the coordinates are not defined (empty)
999
1309
  :raises ValueError: If the coordinates axes are all pinned
1000
1310
  """
1311
+
1001
1312
  font.to_sliced_variable(coordinates, **options)
1002
1313
  ```
1003
1314
 
@@ -1024,7 +1335,14 @@ If coordinates are not specified each axis will be pinned at its default value.
1024
1335
  :raises TypeError: If the font is not a variable font
1025
1336
  :raises ValueError: If the coordinates axes are not all pinned
1026
1337
  """
1027
- font.to_static(coordinates=None, style_name=None, update_names=True, update_style_flags=True, **options)
1338
+
1339
+ font.to_static(
1340
+ coordinates=None,
1341
+ style_name=None,
1342
+ update_names=True,
1343
+ update_style_flags=True,
1344
+ **options,
1345
+ )
1028
1346
  ```
1029
1347
 
1030
1348
  ## Testing