|
| 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 | +""" |
| 21 | +Parse X Bitmap Distribution Format (BDF) |
| 22 | +""" |
| 23 | + |
| 24 | + |
| 25 | +from . import FontFile, Image |
| 26 | + |
| 27 | +bdf_slant = { |
| 28 | + "R": "Roman", |
| 29 | + "I": "Italic", |
| 30 | + "O": "Oblique", |
| 31 | + "RI": "Reverse Italic", |
| 32 | + "RO": "Reverse Oblique", |
| 33 | + "OT": "Other", |
| 34 | +} |
| 35 | + |
| 36 | +bdf_spacing = {"P": "Proportional", "M": "Monospaced", "C": "Cell"} |
| 37 | + |
| 38 | + |
| 39 | +def bdf_char(f): |
| 40 | + # skip to STARTCHAR |
| 41 | + while True: |
| 42 | + s = f.readline() |
| 43 | + if not s: |
| 44 | + return None |
| 45 | + if s[:9] == b"STARTCHAR": |
| 46 | + break |
| 47 | + id = s[9:].strip().decode("ascii") |
| 48 | + |
| 49 | + # load symbol properties |
| 50 | + props = {} |
| 51 | + while True: |
| 52 | + s = f.readline() |
| 53 | + if not s or s[:6] == b"BITMAP": |
| 54 | + break |
| 55 | + i = s.find(b" ") |
| 56 | + props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii") |
| 57 | + |
| 58 | + # load bitmap |
| 59 | + bitmap = [] |
| 60 | + while True: |
| 61 | + s = f.readline() |
| 62 | + if not s or s[:7] == b"ENDCHAR": |
| 63 | + break |
| 64 | + bitmap.append(s[:-1]) |
| 65 | + bitmap = b"".join(bitmap) |
| 66 | + |
| 67 | + [x, y, l, d] = [int(p) for p in props["BBX"].split()] |
| 68 | + [dx, dy] = [int(p) for p in props["DWIDTH"].split()] |
| 69 | + |
| 70 | + bbox = (dx, dy), (l, -d - y, x + l, -d), (0, 0, x, y) |
| 71 | + |
| 72 | + try: |
| 73 | + im = Image.frombytes("1", (x, y), bitmap, "hex", "1") |
| 74 | + except ValueError: |
| 75 | + # deal with zero-width characters |
| 76 | + im = Image.new("1", (x, y)) |
| 77 | + |
| 78 | + return id, int(props["ENCODING"]), bbox, im |
| 79 | + |
| 80 | + |
| 81 | +class BdfFontFile(FontFile.FontFile): |
| 82 | + """Font file plugin for the X11 BDF format.""" |
| 83 | + |
| 84 | + def __init__(self, fp): |
| 85 | + super().__init__() |
| 86 | + |
| 87 | + s = fp.readline() |
| 88 | + if s[:13] != b"STARTFONT 2.1": |
| 89 | + msg = "not a valid BDF file" |
| 90 | + raise SyntaxError(msg) |
| 91 | + |
| 92 | + props = {} |
| 93 | + comments = [] |
| 94 | + |
| 95 | + while True: |
| 96 | + s = fp.readline() |
| 97 | + if not s or s[:13] == b"ENDPROPERTIES": |
| 98 | + break |
| 99 | + i = s.find(b" ") |
| 100 | + props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii") |
| 101 | + if s[:i] in [b"COMMENT", b"COPYRIGHT"]: |
| 102 | + if s.find(b"LogicalFontDescription") < 0: |
| 103 | + comments.append(s[i + 1 : -1].decode("ascii")) |
| 104 | + |
| 105 | + while True: |
| 106 | + c = bdf_char(fp) |
| 107 | + if not c: |
| 108 | + break |
| 109 | + id, ch, (xy, dst, src), im = c |
| 110 | + if 0 <= ch < len(self.glyph): |
| 111 | + self.glyph[ch] = xy, dst, src, im |
0 commit comments