# # The Python Imaging Library. # $Id: //modules/pil/PIL/ImageFont.py#4 $ # # PIL raster font management # # History: # 1996-08-07 fl created (experimental) # 1997-08-25 fl minor adjustments to handle fonts from pilfont 0.3 # 1999-02-06 fl rewrote most font management stuff in C # 1999-03-17 fl take pth files into account in load_path (from Richard Jones) # 2001-02-17 fl added freetype support # 2001-05-09 fl added TransposedFont wrapper class # 2002-03-04 fl make sure we have a "L" or "1" font # # Todo: # Adapt to PILFONT2 format (16-bit fonts, compressed, single file) # # Copyright (c) 1997-2002 by Secret Labs AB # Copyright (c) 1996-2001 by Fredrik Lundh # # See the README file for information on usage and redistribution. # import Image import os, string, sys # -------------------------------------------------------------------- # Font metrics format: # "PILfont" LF # fontdescriptor LF # (optional) key=value... LF # "DATA" LF # binary data: 256*10*2 bytes (dx, dy, dstbox, srcbox) # # To place a character, cut out srcbox and paste at dstbox, # relative to the character position. Then move the character # position according to dx, dy. # -------------------------------------------------------------------- # FIXME: add support for pilfont2 format (see FontFile.py) class ImageFont: "PIL font wrapper" def _load_pilfont(self, filename): fp = open(filename, "rb") # read PILfont header if fp.readline() != "PILfont\n": raise SyntaxError, "Not a PILfont file" d = string.split(fp.readline(), ";") self.info = [] # FIXME: should be a dictionary s = fp.readline() while s and s != "DATA\n": self.info.append(s) # read PILfont metrics data = fp.read(256*20) # read PILfont bitmap for ext in (".png", ".gif", ".pbm"): try: fullname = os.path.splitext(filename)[0] + ext image = Image.open(fullname) except: pass else: if image and image.mode in ("1", "L"): break else: raise IOError, "cannot find glyph data file" image.load() self.file = fullname self.font = Image.core.font(image.im, data) # delegate critical operations to internal type self.getsize = self.font.getsize self.getmask = self.font.getmask class FreeTypeFont: "FreeType font wrapper (requires _imagingft service)" def __init__(self, file, size, index=0): # FIXME: use service provider instead import _imagingft self.font = _imagingft.getfont(file, size, index) def getsize(self, text): return self.font.getsize(text) def getmask(self, text, fill=Image.core.fill): size = self.font.getsize(text) im = fill("L", size, 0) self.font.render(text, im.id) return im class TransposedFont: "Wrapper for writing rotated or mirrored text" def __init__(self, font, orientation=None): self.font = font self.orientation = orientation # any 'transpose' argument, or None def getsize(self, text): w, h = self.font.getsize(text) if self.orientation in (Image.ROTATE_90, Image.ROTATE_270): return h, w return w, h def getmask(self, text): im = self.font.getmask(text) if self.orientation is not None: return im.transpose(self.orientation) return im # # -------------------------------------------------------------------- def load(filename): "Load a font file." f = ImageFont() f._load_pilfont(filename) return f def truetype(filename, size, index=0): "Load a truetype font file." try: return FreeTypeFont(filename, size, index) except IOError: if sys.platform == "win32": # check the windows font repository # NOTE: must use uppercase WINDIR, to work around bugs in # 1.5.2's os.environ.get() windir = os.environ.get("WINDIR") if windir: filename = os.path.join(windir, "fonts", filename) return FreeTypeFont(filename, size, index) raise def load_path(filename): "Load a font file, searching along the Python path." for dir in sys.path: try: return load(os.path.join(dir, filename)) except IOError: pass # disabled: site.py already does this for us ## import glob ## for extra in glob.glob(os.path.join(dir, "*.pth")): ## try: ## dir = os.path.join(dir, string.strip(open(extra).read())) ## return load(os.path.join(dir, filename)) ## except IOError: ## pass raise IOError, "cannot find font file"