Aluode/PerceptionLabPortable
0
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 