home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pypil112.zip / Scripts / bdf2pil.py next >
Text File  |  2001-05-03  |  6KB  |  237 lines

  1. #! /usr/local/bin/python
  2. #
  3. # $Id: bdf2pil.py,v 1.1 1996/12/16 18:51:31 fl Exp $
  4. #
  5. # File:
  6. #       bdf2pil.py -- font compiler for X bitmap distribution files
  7. #
  8. # Description:
  9. #       This utility converts a BDF font to an image file with an
  10. #       associated font metrics file.
  11. #
  12. # History:
  13. #       96-05-16 fl:    Created (after an idea from David Ascher)
  14. #       96-08-07 fl:    Font metrics file uses network byte order
  15. #
  16. # Copyright (c) Fredrik Lundh 1996.  All rights reserved.
  17. #
  18.  
  19. VERSION = "1.0"
  20.  
  21.  
  22. # HACK
  23. try:
  24.     import Image
  25. except:
  26.     import sys
  27.     sys.path.insert(0, ".")
  28.     import Image
  29.  
  30.  
  31. # --------------------------------------------------------------------
  32. # Parse X Bitmap Distribution Format (BDF)
  33. # --------------------------------------------------------------------
  34.  
  35. import string
  36.  
  37. bdf_slant = {
  38.    "R": "Roman",
  39.    "I": "Italic",
  40.    "O": "Oblique",
  41.    "RI": "Reverse Italic",
  42.    "RO": "Reverse Oblique",
  43.    "OT": "Other"
  44. }
  45.  
  46. bdf_spacing = {
  47.     "P": "Proportional",
  48.     "M": "Monospaced",
  49.     "C": "Cell"
  50. }
  51.  
  52. def bdf_char(f):
  53.  
  54.     # skip to STARTCHAR
  55.     while 1:
  56.         s = f.readline()
  57.         if not s:
  58.             return None
  59.         if s[:9] == "STARTCHAR":
  60.             break
  61.     id = string.strip(s[9:])
  62.  
  63.     # load symbol properties
  64.     props = {}
  65.     while 1:
  66.         s = f.readline()
  67.         if not s or s[:6] == "BITMAP":
  68.             break
  69.         i = string.find(s, " ")
  70.         props[s[:i]] = s[i+1:-1]
  71.  
  72.     # load bitmap
  73.     bitmap = []
  74.     while 1:
  75.         s = f.readline()
  76.         if not s or s[:7] == "ENDCHAR":
  77.             break
  78.         bitmap.append(s[:-1])
  79.     bitmap = string.join(bitmap, "")
  80.  
  81.     [w, h, x, y] = map(string.atoi, string.split(props["BBX"]))
  82.     [dx, dy] = map(string.atoi, string.split(props["DWIDTH"]))
  83.  
  84.     bbox = (dx, dy, x, y, x+w, y+h)
  85.  
  86.     return id, string.atoi(props["ENCODING"]), bbox, bitmap
  87.  
  88.  
  89. def bdf2font(filename):
  90.  
  91.     f = open(filename)
  92.  
  93.     s = f.readline()
  94.     if s[:13] != "STARTFONT 2.1":
  95.         print filename, "is not a valid BDF file (ignoring)"
  96.         return None
  97.  
  98.     print filename
  99.  
  100.     props = {}
  101.     comments = []
  102.  
  103.     while 1:
  104.         s = f.readline()
  105.         if not s or s[:13] == "ENDPROPERTIES":
  106.             break
  107.         i = string.find(s, " ")
  108.         props[s[:i]] = s[i+1:-1]
  109.         if s[:i] in ["COMMENT", "COPYRIGHT"]:
  110.             if string.find(s, "LogicalFontDescription") < 0:
  111.                 comments.append(s[i+1:-1])
  112.  
  113.     font = string.split(props["FONT"], "-")
  114.  
  115.     font[4] = bdf_slant[font[4]]
  116.     font[11] = bdf_spacing[font[11]]
  117.  
  118.     ascent = string.atoi(props["FONT_ASCENT"])
  119.     descent = string.atoi(props["FONT_DESCENT"])
  120.  
  121.     fontname = string.join(font[1:], ";")
  122.  
  123.     print "#", fontname
  124.     #for i in comments:
  125.     #   print "#", i
  126.  
  127.     font = []
  128.     while 1:
  129.         c = bdf_char(f)
  130.         if not c:
  131.             break
  132.         id, code, bbox, bits = c
  133.         if code >= 0:
  134.             font.append((code, bbox, bits))
  135.  
  136.     return font, fontname, ascent, descent
  137.  
  138.  
  139. # --------------------------------------------------------------------
  140. # Translate font to image
  141. # --------------------------------------------------------------------
  142.  
  143. def font2image(font, ascent, descent):
  144.  
  145.     metrics = [None] * 256
  146.  
  147.     # create glyph images for all characters in this font
  148.     width = height = 0
  149.     glyph = [None]*256
  150.     for id, (dx, dy, b0, b1, b2, b3), bits in font:
  151.         w, h = b2-b0, b3-b1
  152.         if w > 0 and h > 0:
  153.             i = Image.core.new("L", (w, h))
  154.             height = max(height, h)
  155.             d = Image.core.hex_decoder("1")
  156.             d.setimage(i)
  157.             d.decode(bits)
  158.             glyph[id] = i
  159.             width = width + w
  160.  
  161.     # pack the glyphs into a large image
  162.     x = 0
  163.     bboxes = {}
  164.     i = Image.core.fill("L", (width, height), 0)
  165.     for id, (dx, dy, b0, b1, b2, b3), bits in font:
  166.         w, h = b2-b0, b3-b1
  167.         if w > 0 and h > 0:
  168.             bbox = (x, 0, x+w, h)
  169.             metrics[id] = (dx, dy), (b0, b1, b2, b3), bbox
  170.             i.paste(glyph[id], bbox)
  171.             x = x + w
  172.             bboxes[id] = bbox
  173.  
  174.     return i, bboxes
  175.  
  176. def puti16(fp, values):
  177.     # write network order (big-endian) 16-bit sequence
  178.     for v in values:
  179.         fp.write(chr(v>>8&255) + chr(v&255))
  180.  
  181. # --------------------------------------------------------------------
  182. # MAIN
  183. # --------------------------------------------------------------------
  184.  
  185. import glob, os, sys
  186.  
  187. print "BDF2PIL", VERSION, "-- Font compiler for X BDF fonts."
  188. print "Copyright (c) Fredrik Lundh 1996.  All rights reserved."
  189.  
  190. if len(sys.argv) <= 1:
  191.     print
  192.     print "Usage: bdf2pil files..."
  193.     print
  194.     print "BDF files are converted to a bitmap file (currently"
  195.     print "using PBM format) and a font metrics file (PIL)."
  196.     sys.exit(1)
  197.  
  198. files = []
  199. for f in sys.argv[1:]:
  200.     files = files + glob.glob(f)
  201.  
  202. for file in files:
  203.     font, fontname, ascent, descent = bdf2font(file)
  204.     if font:
  205.         image, srcbbox = font2image(font, ascent, descent)
  206.         # to be changed to PCX or something...
  207.         image.save_ppm(os.path.splitext(file)[0] + ".pbm")
  208.         # create font metrics file
  209.         metrics = {}
  210.         for id, xy_bbox, bits in font:
  211.             x, y, x0, y0, x1, y1 = xy_bbox
  212.             metrics[id] = (x, y, x0, ascent-y1, x1, ascent-y0) + srcbbox[id]
  213.         fp = open(os.path.splitext(file)[0] + ".pil", "wb")
  214.         fp.write("PILfont\n")
  215.         fp.write("%s\n" % fontname) 
  216.         fp.write("DATA\n")
  217.         for id in range(256):
  218.             try:
  219.                 puti16(fp, metrics[id])
  220.             except KeyError:
  221.                 puti16(fp, (0,) * 10)
  222.         fp.close()
  223.  
  224. # --------------------------------------------------------------------
  225. # Font metrics format:
  226. #       "PILfont" LF
  227. #       fontdescriptor LF
  228. #       (optional) key=value... LF
  229. #       "DATA" LF
  230. #       binary data: 256*10*2 bytes (dx, dy, dstbox, srcbox)
  231. #
  232. # To place a character, cut out srcbox and paste at dstbox,
  233. # relative to the character position.  Then move the character
  234. # position according to dx, dy.
  235. # --------------------------------------------------------------------
  236.  
  237.