codekingpro/portable-devtools
115k
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"""
23
24from __future__ import annotations
25
26from typing import BinaryIO
27
28from . import FontFile, Image
29
30
31def bdf_char(
32 f: BinaryIO,
33) -> (
34 tuple[
35 str,
36 int,
37 tuple[tuple[int, int], tuple[int, int, int, int], tuple[int, int, int, int]],
38 Image.Image,
39 ]
40 | None
41):
42 # skip to STARTCHAR
43 while True:
44 s = f.readline()
45 if not s:
46 return None
47 if s.startswith(b"STARTCHAR"):
48 break
49 id = s[9:].strip().decode("ascii")
50
51 # load symbol properties
52 props = {}
53 while True:
54 s = f.readline()
55 if not s or s.startswith(b"BITMAP"):
56 break
57 i = s.find(b" ")
58 props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
59
60 # load bitmap
61 bitmap = bytearray()
62 while True:
63 s = f.readline()
64 if not s or s.startswith(b"ENDCHAR"):
65 break
66 bitmap += s[:-1]
67
68 # The word BBX
69 # followed by the width in x (BBw), height in y (BBh),
70 # and x and y displacement (BBxoff0, BByoff0)
71 # of the lower left corner from the origin of the character.
72 width, height, x_disp, y_disp = (int(p) for p in props["BBX"].split())
73
74 # The word DWIDTH
75 # followed by the width in x and y of the character in device pixels.
76 dwx, dwy = (int(p) for p in props["DWIDTH"].split())
77
78 bbox = (
79 (dwx, dwy),
80 (x_disp, -y_disp - height, width + x_disp, -y_disp),
81 (0, 0, width, height),
82 )
83
84 try:
85 im = Image.frombytes("1", (width, height), bitmap, "hex", "1")
86 except ValueError:
87 # deal with zero-width characters
88 im = Image.new("1", (width, height))
89
90 return id, int(props["ENCODING"]), bbox, im
91
92
93class BdfFontFile(FontFile.FontFile):
94 """Font file plugin for the X11 BDF format."""
95
96 def __init__(self, fp: BinaryIO) -> None:
97 super().__init__()
98
99 s = fp.readline()
100 if not s.startswith(b"STARTFONT 2.1"):
101 msg = "not a valid BDF file"
102 raise SyntaxError(msg)
103
104 props = {}
105 comments = []
106
107 while True:
108 s = fp.readline()
109 if not s or s.startswith(b"ENDPROPERTIES"):
110 break
111 i = s.find(b" ")
112 props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii")
113 if s[:i] in [b"COMMENT", b"COPYRIGHT"]:
114 if s.find(b"LogicalFontDescription") < 0:
115 comments.append(s[i + 1 : -1].decode("ascii"))
116
117 while True:
118 c = bdf_char(fp)
119 if not c:
120 break
121 id, ch, (xy, dst, src), im = c
122 if 0 <= ch < len(self.glyph):
123 self.glyph[ch] = xy, dst, src, im
124 