Read the font metrics header (up to the char metrics). Returns ------- dict A dictionary mapping *key* to *val*. Dictionary keys are: StartFontMetrics, FontName, FullName, FamilyName, Weight, ItalicAngle, IsFixedPitch, FontBBox, UnderlinePosition, U
(fh: BinaryIO)
| 109 | |
| 110 | |
| 111 | def _parse_header(fh: BinaryIO) -> FontMetricsHeader: |
| 112 | """ |
| 113 | Read the font metrics header (up to the char metrics). |
| 114 | |
| 115 | Returns |
| 116 | ------- |
| 117 | dict |
| 118 | A dictionary mapping *key* to *val*. Dictionary keys are: |
| 119 | |
| 120 | StartFontMetrics, FontName, FullName, FamilyName, Weight, ItalicAngle, |
| 121 | IsFixedPitch, FontBBox, UnderlinePosition, UnderlineThickness, Version, |
| 122 | Notice, EncodingScheme, CapHeight, XHeight, Ascender, Descender, |
| 123 | StartCharMetrics |
| 124 | |
| 125 | *val* will be converted to the appropriate Python type as necessary, e.g.,: |
| 126 | |
| 127 | * 'False' -> False |
| 128 | * '0' -> 0 |
| 129 | * '-168 -218 1000 898' -> [-168, -218, 1000, 898] |
| 130 | """ |
| 131 | header_converters = { |
| 132 | bool: _to_bool, |
| 133 | bytes: lambda x: x, |
| 134 | float: _to_float, |
| 135 | int: _to_int, |
| 136 | list[int]: _to_list_of_ints, |
| 137 | str: _to_str, |
| 138 | } |
| 139 | header_value_types = inspect.get_annotations(FontMetricsHeader) |
| 140 | d: FontMetricsHeader = {} |
| 141 | first_line = True |
| 142 | for line in fh: |
| 143 | line = line.rstrip() |
| 144 | if line.startswith(b'Comment'): |
| 145 | continue |
| 146 | lst = line.split(b' ', 1) |
| 147 | key = lst[0] |
| 148 | if first_line: |
| 149 | # AFM spec, Section 4: The StartFontMetrics keyword |
| 150 | # [followed by a version number] must be the first line in |
| 151 | # the file, and the EndFontMetrics keyword must be the |
| 152 | # last non-empty line in the file. We just check the |
| 153 | # first header entry. |
| 154 | if key != b'StartFontMetrics': |
| 155 | raise RuntimeError('Not an AFM file') |
| 156 | first_line = False |
| 157 | if len(lst) == 2: |
| 158 | val = lst[1] |
| 159 | else: |
| 160 | val = b'' |
| 161 | try: |
| 162 | key_str = _to_str(key) |
| 163 | value_type = header_value_types[key_str] |
| 164 | except (KeyError, UnicodeDecodeError): |
| 165 | _log.error("Found an unknown keyword in AFM header (was %r)", key) |
| 166 | continue |
| 167 | try: |
| 168 | converter = header_converters[value_type] |