CoolFace
Apppublic

Aluode/PerceptionLabPortable

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
BdfFontFile.py123 linesDownload Raw Back to PIL
1#
2# The Python Imaging Library
3# $Id$
4#
5# bitmap distribution font (bdf) file parser
6#
7# history:
8# 1996-05-16 fl   created (as bdf2pil)
9# 1997-08-25 fl   converted to FontFile driver
10# 2001-05-25 fl   removed bogus __init__ call
11# 2002-11-20 fl   robustification (from Kevin Cazabon, Dmitry Vasiliev)
12# 2003-04-22 fl   more robustification (from Graham Dumpleton)
13#
14# Copyright (c) 1997-2003 by Secret Labs AB.
15# Copyright (c) 1997-2003 by Fredrik Lundh.
16#
17# See the README file for information on usage and redistribution.
18#
19
20"""
21Parse X Bitmap Distribution Format (BDF)
22"""
23from __future__ import annotations
24
25from typing import BinaryIO
26
27from . import FontFile, Image
28
29
30def bdf_char(
31    f: BinaryIO,
32) -> (
33    tuple[
34        str,
35        int,
36        tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]],
37        Image.Image,
38    ]
39    | None
40):
41    # skip to STARTCHAR
42    while True:
43        s = f.readline()
44        if not s:
45            return None
46        if s.startswith(b"STARTCHAR"):
47            break
48    id = s[9:].strip().decode("ascii")
49
50    # load symbol properties
51    props = {}
52    while True:
53        s = f.readline()
54        if not s or s.startswith(b"BITMAP"):
55            break
56        i = s.find(b" ")
57        props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
58
59    # load bitmap
60    bitmap = bytearray()
61    while True:
62        s = f.readline()
63        if not s or s.startswith(b"ENDCHAR"):
64            break
65        bitmap += s[:-1]
66
67    # The word BBX
68    # followed by the width in x (BBw), height in y (BBh),
69    # and x and y displacement (BBxoff0, BByoff0)
70    # of the lower left corner from the origin of the character.
71    width, height, x_disp, y_disp = (int(p) for p in props["BBX"].split())
72
73    # The word DWIDTH
74    # followed by the width in x and y of the character in device pixels.
75    dwx, dwy = (int(p) for p in props["DWIDTH"].split())
76
77    bbox = (
78        (dwx, dwy),
79        (x_disp, -y_disp - height, width + x_disp, -y_disp),
80        (0, 0, width, height),
81    )
82
83    try:
84        im = Image.frombytes("1", (width, height), bitmap, "hex", "1")
85    except ValueError:
86        # deal with zero-width characters
87        im = Image.new("1", (width, height))
88
89    return id, int(props["ENCODING"]), bbox, im
90
91
92class BdfFontFile(FontFile.FontFile):
93    """Font file plugin for the X11 BDF format."""
94
95    def __init__(self, fp: BinaryIO) -> None:
96        super().__init__()
97
98        s = fp.readline()
99        if not s.startswith(b"STARTFONT 2.1"):
100            msg = "not a valid BDF file"
101            raise SyntaxError(msg)
102
103        props = {}
104        comments = []
105
106        while True:
107            s = fp.readline()
108            if not s or s.startswith(b"ENDPROPERTIES"):
109                break
110            i = s.find(b" ")
111            props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
112            if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
113                if s.find(b"LogicalFontDescription") < 0:
114                    comments.append(s[i + 1 : -1].decode("ascii"))
115
116        while True:
117            c = bdf_char(fp)
118            if not c:
119                break
120            id, ch, (xy, dst, src), im = c
121            if 0 <= ch < len(self.glyph):
122                self.glyph[ch] = xy, dst, src, im
123