1 #!/usr/bin/python 2 3 import harfbuzz, optparse, sys 4 from fontconfig import fcPattern 5 6 usage = '''usage: %prog [options] codepoints 7 Generates output of glyphs and positions. Each entry is of the form: 8 glyphid>cluster@(offsetx,offsety)+(advancex,advancey) 9 10 codepoints is a space separated list of hex values of Unicode codepoints''' 11 p = optparse.OptionParser(usage=usage) 12 p.add_option('-s', '--size', default=32, type="int", help="point size") 13 p.add_option('-l', '--lang', help="language code") 14 p.add_option('-c', '--script', help="script code") 15 p.add_option('-F', '--feature', action='append', help="define a feature key=val") 16 p.add_option('-f', '--font', help='Font to use to render glyphs. My be a font file', default="verdana") 17 p.add_option('-b', '--bold', help='Choose bold fonts', action='store_true') 18 p.add_option('-i', '--italic', help='Choose italic fonts', action='store_true') 19 p.add_option('-d', '--debug', action='store_true', help="Output trace info") 20 p.add_option('--nogui', action='store_true', help="Don't display a gui") 21 (opts, args) = p.parse_args() 22 23 if opts.font.lower().endswith(".ttf") : 24 fpat = ":file=" 25 else : 26 fpat = "" 27 fpat += opts.font + ":weight=" 28 fpat += "bold" if opts.bold else "medium" 29 fpat += ":slant=" 30 fpat += "italic" if opts.italic else "roman" 31 pat = fcPattern(fpat) 32 fname = pat.getString("file", 0) 33 family = pat.getString("family", 0) 34 print "Processing: " + fname 35 if opts.font.lower().endswith(".ttf") and opts.font != fname : 36 print "Failed to find font in fontconfig. Exiting" 37 sys.exit(1) 38 39 ft = harfbuzz.ft(fname, opts.size) 40 text = "".join(unichr(int(c, 16)) for c in args) 41 bytes = text.encode('utf_8') 42 buffer = harfbuzz.buffer(bytes, len(text)) 43 if (opts.lang or opts.script) : buffer.set_scriptlang(opts.script if opts.script else "", opts.lang if opts.lang else "") 44 features = {} 45 if opts.feature : 46 for f in opts.feature : 47 k, v = f.split("=") 48 features[k] = v 49 ft.shape(buffer, features = features) 50 res = buffer.get_info(64) # scale for 26.6 51 print res 52 53 if not opts.nogui : 54 try: 55 import gtk 56 import gobject 57 import cairo 58 from gtk import gdk 59 except : 60 raise SystemExit 61 import pygtk 62 63 if gtk.pygtk_version < (2, 8) : 64 print "PyGtk 2.8 or later required" 65 raise SystemExit 66 67 class GlyphsWindow (gtk.Widget) : 68 def __init__(self, fontname, bold, italic, size, glyphs) : 69 gtk.Widget.__init__(self) 70 self.fontname = fontname 71 self.size = size 72 self.glyphs = glyphs 73 self.bold = bold 74 self.italic = italic 75 76 def do_realize(self) : 77 self.set_flags(gtk.REALIZED) 78 self.window = gdk.Window( 79 self.get_parent_window(), 80 width = self.allocation.width, 81 height = self.allocation.height, 82 window_type = gdk.WINDOW_CHILD, 83 wclass = gdk.INPUT_OUTPUT, 84 event_mask = self.get_events() | gdk.EXPOSURE_MASK) 85 self.window.set_user_data(self) 86 self.style.attach(self.window) 87 self.style.set_background(self.window, gtk.STATE_NORMAL) 88 self.window.move_resize(*self.allocation) 89 90 def do_unrealize(self) : 91 self.window.destroy() 92 93 def do_expose_event(self, event) : 94 cr = self.window.cairo_create() 95 cr.set_matrix(cairo.Matrix(1, 0, 0, 1, 0, 1.5 * self.size)) 96 cr.set_font_face(cairo.ToyFontFace(self.fontname, cairo.FONT_SLANT_ITALIC if self.italic else cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD if self.bold else cairo.FONT_WEIGHT_NORMAL)) 97 cr.set_font_size(self.size) 98 cr.show_glyphs(self.glyphs) # [(gid, originx, originy)] 99 100 glyphs = [] 101 org = [0, 0] 102 for g in res : 103 glyphs.append((g.gid, org[0] + g.offset[0], org[1] - g.offset[1])) 104 org[0] += g.advance[0] 105 org[1] -= g.advance[1] 106 107 gobject.type_register(GlyphsWindow) 108 win = gtk.Window() 109 win.resize(org[0] + 10, 2 * opts.size + 40) 110 win.connect('delete-event', gtk.main_quit) 111 frame = gtk.Frame("glyphs") 112 win.add(frame) 113 w = GlyphsWindow(family, opts.bold, opts.italic, opts.size, glyphs) 114 frame.add(w) 115 win.show_all() 116 gtk.main() 117