home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / EVE_1424_100181.exe / PcfFontFile.py < prev    next >
Encoding:
Python Source  |  2004-04-20  |  6.2 KB  |  253 lines

  1. #
  2. # THIS IS WORK IN PROGRESS
  3. #
  4. # The Python Imaging Library
  5. # $Id: //modules/pil/PIL/PcfFontFile.py#3 $
  6. #
  7. # portable compiled font file parser
  8. #
  9. # history:
  10. # 97-08-19 fl   created
  11. #
  12. # Copyright (c) Secret Labs AB 1997-98.
  13. # Copyright (c) Fredrik Lundh 1997.
  14. #
  15. # See the README file for information on usage and redistribution.
  16. #
  17.  
  18. import Image
  19. import FontFile
  20.  
  21. import string
  22.  
  23. # --------------------------------------------------------------------
  24. # declarations
  25.  
  26. PCF_MAGIC = 0x70636601
  27.  
  28. PCF_PROPERTIES = (1<<0)
  29. PCF_ACCELERATORS = (1<<1)
  30. PCF_METRICS = (1<<2)
  31. PCF_BITMAPS = (1<<3)
  32. PCF_INK_METRICS = (1<<4)
  33. PCF_BDF_ENCODINGS = (1<<5)
  34. PCF_SWIDTHS = (1<<6)
  35. PCF_GLYPH_NAMES = (1<<7)
  36. PCF_BDF_ACCELERATORS = (1<<8)
  37.  
  38. BYTES_PER_ROW = [
  39.     lambda bits: ((bits+7)  >> 3),
  40.     lambda bits: ((bits+15) >> 3) & ~1,
  41.     lambda bits: ((bits+31) >> 3) & ~3,
  42.     lambda bits: ((bits+63) >> 3) & ~7,
  43. ]
  44.  
  45.  
  46. def l16(c):
  47.     return ord(c[0]) + (ord(c[1])<<8)
  48. def l32(c):
  49.     return ord(c[0]) + (ord(c[1])<<8) + (ord(c[2])<<16) + (ord(c[3])<<24)
  50.  
  51. def b16(c):
  52.     return ord(c[1]) + (ord(c[0])<<8)
  53. def b32(c):
  54.     return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
  55.  
  56. def sz(s, o):
  57.     return s[o:string.index(s, "\0", o)]
  58.  
  59.  
  60. # --------------------------------------------------------------------
  61. # parser
  62.  
  63. class PcfFontFile(FontFile.FontFile):
  64.  
  65.     name = "name"
  66.  
  67.     def __init__(self, fp):
  68.  
  69.         magic = l32(fp.read(4))
  70.         if magic != PCF_MAGIC:
  71.             raise SyntaxError, "not a PCF file"
  72.  
  73.         FontFile.FontFile.__init__(self)
  74.  
  75.         count = l32(fp.read(4))
  76.         self.toc = {}
  77.         for i in range(count):
  78.             type = l32(fp.read(4))
  79.             self.toc[type] = l32(fp.read(4)), l32(fp.read(4)), l32(fp.read(4))
  80.  
  81.         self.fp = fp
  82.  
  83.         self.info = self._load_properties()
  84.  
  85.         metrics = self._load_metrics()
  86.         bitmaps = self._load_bitmaps(metrics)
  87.         encoding = self._load_encoding()
  88.  
  89.         #
  90.         # create glyph structure
  91.  
  92.         for ch in range(256):
  93.             ix = encoding[ch]
  94.             if ix is not None:
  95.                 x, y, l, r, w, a, d, f = metrics[ix]
  96.                 self.glyph[ch] = (w, 0), (l, d-y, x+l, d), (0, 0, x, y), bitmaps[ix]
  97.  
  98.  
  99.     def _getformat(self, tag):
  100.  
  101.         format, size, offset = self.toc[tag]
  102.  
  103.         fp = self.fp
  104.         fp.seek(offset)
  105.  
  106.         format = l32(fp.read(4))
  107.  
  108.         if format & 4:
  109.             i16, i32 = b16, b32
  110.         else:
  111.             i16, i32 = l16, l32
  112.  
  113.         return fp, format, i16, i32
  114.  
  115.     def _load_properties(self):
  116.  
  117.         #
  118.         # font properties
  119.  
  120.         properties = {}
  121.  
  122.         fp, format, i16, i32 = self._getformat(PCF_PROPERTIES)
  123.  
  124.         nprops = i32(fp.read(4))
  125.  
  126.         # read property description
  127.         p = []
  128.         for i in range(nprops):
  129.             p.append((i32(fp.read(4)), ord(fp.read(1)), i32(fp.read(4))))
  130.         if nprops & 3:
  131.             fp.seek(4 - (nprops & 3), 1) # pad
  132.  
  133.         data = fp.read(i32(fp.read(4)))
  134.  
  135.         for k, s, v in p:
  136.             k = sz(data, k)
  137.             if s:
  138.                 v = sz(data, v)
  139.             properties[k] = v
  140.  
  141.         return properties
  142.  
  143.     def _load_metrics(self):
  144.  
  145.         #
  146.         # font metrics
  147.  
  148.         metrics = []
  149.  
  150.         fp, format, i16, i32 = self._getformat(PCF_METRICS)
  151.  
  152.         append = metrics.append
  153.  
  154.         if (format & 0xff00) == 0x100:
  155.  
  156.             # "compressed" metrics
  157.             for i in range(i16(fp.read(2))):
  158.                 left = ord(fp.read(1)) - 128
  159.                 right = ord(fp.read(1)) - 128
  160.                 width = ord(fp.read(1)) - 128
  161.                 ascent = ord(fp.read(1)) - 128
  162.                 descent = ord(fp.read(1)) - 128
  163.                 xsize = right - left
  164.                 ysize = ascent + descent
  165.                 append(
  166.                     (xsize, ysize, left, right, width,
  167.                      ascent, descent, 0)
  168.                     )
  169.  
  170.         else:
  171.  
  172.             # "jumbo" metrics
  173.             for i in range(i32(fp.read(4))):
  174.                 left = i16(fp.read(2))
  175.                 right = i16(fp.read(2))
  176.                 width = i16(fp.read(2))
  177.                 ascent = i16(fp.read(2))
  178.                 descent = i16(fp.read(2))
  179.                 attributes = i16(fp.read(2))
  180.                 append(
  181.                     (xsize, ysize, left, right, width,
  182.                      ascent, descent, attributes)
  183.                     )
  184.  
  185.         return metrics
  186.  
  187.     def _load_bitmaps(self, metrics):
  188.  
  189.         #
  190.         # bitmap data
  191.  
  192.         bitmaps = []
  193.  
  194.         fp, format, i16, i32 = self._getformat(PCF_BITMAPS)
  195.  
  196.         nbitmaps = i32(fp.read(4))
  197.  
  198.         if nbitmaps != len(metrics):
  199.             raise IOError, "Wrong number of bitmaps"
  200.  
  201.         offsets = []
  202.         for i in range(nbitmaps):
  203.             offsets.append(i32(fp.read(4)))
  204.  
  205.         bitmapSizes = []
  206.         for i in range(4):
  207.             bitmapSizes.append(i32(fp.read(4)))
  208.  
  209.         byteorder = format & 4 # non-zero => MSB
  210.         bitorder  = format & 8 # non-zero => MSB
  211.         padindex  = format & 3
  212.  
  213.         bitmapsize = bitmapSizes[padindex]
  214.         offsets.append(bitmapsize)
  215.  
  216.         data = fp.read(bitmapsize)
  217.  
  218.         pad  = BYTES_PER_ROW[padindex]
  219.         mode = "1;R"
  220.         if bitorder:
  221.             mode = "1"
  222.  
  223.         for i in range(nbitmaps):
  224.  
  225.             x, y, l, r, w, a, d, f = metrics[i]
  226.             b, e = offsets[i], offsets[i+1]
  227.  
  228.             im = Image.fromstring("1", (x, y), data[b:e], "raw", mode, pad(x))
  229.  
  230.             bitmaps.append(im)
  231.  
  232.         return bitmaps
  233.  
  234.     def _load_encoding(self):
  235.  
  236.         encoding = [None] * 256
  237.  
  238.         fp, format, i16, i32 = self._getformat(PCF_BDF_ENCODINGS)
  239.  
  240.         firstCol, lastCol = i16(fp.read(2)), i16(fp.read(2))
  241.         firstRow, lastRow = i16(fp.read(2)), i16(fp.read(2))
  242.  
  243.         default = i16(fp.read(2))
  244.  
  245.         nencoding = (lastCol - firstCol + 1) * (lastRow - firstRow + 1)
  246.  
  247.         for i in range(nencoding):
  248.             encodingOffset = i16(fp.read(2))
  249.             if encodingOffset != 0xFFFF:
  250.                 encoding[i+firstCol] = encodingOffset
  251.  
  252.         return encoding
  253.