|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| """
|
| Parse X Bitmap Distribution Format (BDF)
|
| """
|
| from __future__ import annotations
|
|
|
| from typing import BinaryIO
|
|
|
| from . import FontFile, Image
|
|
|
|
|
| def bdf_char(
|
| f: BinaryIO,
|
| ) -> (
|
| tuple[
|
| str,
|
| int,
|
| tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]],
|
| Image.Image,
|
| ]
|
| | None
|
| ):
|
|
|
| while True:
|
| s = f.readline()
|
| if not s:
|
| return None
|
| if s.startswith(b"STARTCHAR"):
|
| break
|
| id = s[9:].strip().decode("ascii")
|
|
|
|
|
| props = {}
|
| while True:
|
| s = f.readline()
|
| if not s or s.startswith(b"BITMAP"):
|
| break
|
| i = s.find(b" ")
|
| props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
|
|
|
|
|
| bitmap = bytearray()
|
| while True:
|
| s = f.readline()
|
| if not s or s.startswith(b"ENDCHAR"):
|
| break
|
| bitmap += s[:-1]
|
|
|
|
|
|
|
|
|
|
|
| width, height, x_disp, y_disp = (int(p) for p in props["BBX"].split())
|
|
|
|
|
|
|
| dwx, dwy = (int(p) for p in props["DWIDTH"].split())
|
|
|
| bbox = (
|
| (dwx, dwy),
|
| (x_disp, -y_disp - height, width + x_disp, -y_disp),
|
| (0, 0, width, height),
|
| )
|
|
|
| try:
|
| im = Image.frombytes("1", (width, height), bitmap, "hex", "1")
|
| except ValueError:
|
|
|
| im = Image.new("1", (width, height))
|
|
|
| return id, int(props["ENCODING"]), bbox, im
|
|
|
|
|
| class BdfFontFile(FontFile.FontFile):
|
| """Font file plugin for the X11 BDF format."""
|
|
|
| def __init__(self, fp: BinaryIO) -> None:
|
| super().__init__()
|
|
|
| s = fp.readline()
|
| if not s.startswith(b"STARTFONT 2.1"):
|
| msg = "not a valid BDF file"
|
| raise SyntaxError(msg)
|
|
|
| props = {}
|
| comments = []
|
|
|
| while True:
|
| s = fp.readline()
|
| if not s or s.startswith(b"ENDPROPERTIES"):
|
| break
|
| i = s.find(b" ")
|
| props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
|
| if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
|
| if s.find(b"LogicalFontDescription") < 0:
|
| comments.append(s[i + 1 : -1].decode("ascii"))
|
|
|
| while True:
|
| c = bdf_char(fp)
|
| if not c:
|
| break
|
| id, ch, (xy, dst, src), im = c
|
| if 0 <= ch < len(self.glyph):
|
| self.glyph[ch] = xy, dst, src, im
|
|
|