BdfFontFile.py 2.9 KB

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