| 375 | |
| 376 | |
| 377 | class AFM: |
| 378 | |
| 379 | def __init__(self, fh: BinaryIO): |
| 380 | """Parse the AFM file in file object *fh*.""" |
| 381 | self._header = _parse_header(fh) |
| 382 | self._metrics, self._metrics_by_name = _parse_char_metrics(fh) |
| 383 | self._kern, self._composite = _parse_optional(fh) |
| 384 | |
| 385 | def get_str_bbox_and_descent(self, s: str) -> tuple[int, int, float, int, int]: |
| 386 | """Return the string bounding box and the maximal descent.""" |
| 387 | if not len(s): |
| 388 | return 0, 0, 0, 0, 0 |
| 389 | total_width = 0.0 |
| 390 | namelast = '' |
| 391 | miny = 1_000_000_000 |
| 392 | maxy = 0 |
| 393 | left = 0 |
| 394 | for c in s: |
| 395 | if c == '\n': |
| 396 | continue |
| 397 | name = uni2type1.get(ord(c), f"uni{ord(c):04X}") |
| 398 | try: |
| 399 | wx, _, bbox = self._metrics_by_name[name] |
| 400 | except KeyError: |
| 401 | name = 'question' |
| 402 | wx, _, bbox = self._metrics_by_name[name] |
| 403 | total_width += wx + self._kern.get((namelast, name), 0) |
| 404 | l, b, w, h = bbox |
| 405 | left = min(left, l) |
| 406 | miny = min(miny, b) |
| 407 | maxy = max(maxy, b + h) |
| 408 | |
| 409 | namelast = name |
| 410 | |
| 411 | return left, miny, total_width, maxy - miny, -miny |
| 412 | |
| 413 | def get_glyph_name(self, # For consistency with FT2Font. |
| 414 | glyph_ind: GlyphIndexType) -> str: |
| 415 | """Get the name of the glyph, i.e., ord(';') is 'semicolon'.""" |
| 416 | return self._metrics[cast(CharacterCodeType, glyph_ind)].name |
| 417 | |
| 418 | def get_char_index(self, # For consistency with FT2Font. |
| 419 | c: CharacterCodeType) -> GlyphIndexType: |
| 420 | """ |
| 421 | Return the glyph index corresponding to a character code point. |
| 422 | |
| 423 | Note, for AFM fonts, we treat the glyph index the same as the codepoint. |
| 424 | """ |
| 425 | return cast(GlyphIndexType, c) |
| 426 | |
| 427 | def get_width_char(self, c: CharacterCodeType) -> float: |
| 428 | """Get the width of the character code from the character metric WX field.""" |
| 429 | return self._metrics[c].width |
| 430 | |
| 431 | def get_width_from_char_name(self, name: str) -> float: |
| 432 | """Get the width of the character from a type1 character name.""" |
| 433 | return self._metrics_by_name[name].width |
| 434 |
no outgoing calls
no test coverage detected