1import fontTools.ttLib as ttLib 2from fontTools.ttLib.ttVisitor import TTVisitor 3from fontTools.misc.textTools import Tag 4from array import array 5 6 7class JsonVisitor(TTVisitor): 8 def _open(self, s): 9 print(s, file=self.file) 10 self._indent += self.indent 11 self.comma = False 12 13 def _close(self, s): 14 self._indent = self._indent[: -len(self.indent)] 15 print("\n%s%s" % (self._indent, s), end="", file=self.file) 16 self.comma = True 17 18 def __init__(self, file, indent=" "): 19 self.file = file 20 self.indent = indent 21 self._indent = "" 22 23 def visitObject(self, obj): 24 self._open("{") 25 super().visitObject(obj) 26 if self.comma: 27 print(",", end="", file=self.file) 28 print( 29 '\n%s"type": "%s"' % (self._indent, obj.__class__.__name__), 30 end="", 31 file=self.file, 32 ) 33 self._close("}") 34 35 def visitAttr(self, obj, attr, value): 36 if self.comma: 37 print(",", file=self.file) 38 print('%s"%s": ' % (self._indent, attr), end="", file=self.file) 39 self.visit(value) 40 self.comma = True 41 42 def visitList(self, obj, *args, **kwargs): 43 self._open("[") 44 comma = False 45 for value in obj: 46 if comma: 47 print(",", end="", file=self.file) 48 print(file=self.file) 49 print(self._indent, end="", file=self.file) 50 self.visit(value, *args, **kwargs) 51 comma = True 52 self._close("]") 53 54 def visitDict(self, obj, *args, **kwargs): 55 self._open("{") 56 comma = False 57 for key, value in obj.items(): 58 if comma: 59 print(",", end="", file=self.file) 60 print(file=self.file) 61 print('%s"%s": ' % (self._indent, key), end="", file=self.file) 62 self.visit(value, *args, **kwargs) 63 comma = True 64 self._close("}") 65 66 def visitLeaf(self, obj): 67 if isinstance(obj, tuple): 68 obj = list(obj) 69 elif isinstance(obj, bytes): 70 obj = list(obj) 71 72 if obj is None: 73 s = "null" 74 elif obj is True: 75 s = "true" 76 elif obj is False: 77 s = "false" 78 else: 79 s = repr(obj) 80 81 if s[0] == "'": 82 s = '"' + s[1:-1] + '"' 83 84 print("%s" % s, end="", file=self.file) 85 86 87@JsonVisitor.register(ttLib.TTFont) 88def visit(self, font): 89 if hasattr(visitor, "font"): 90 print("{}", end="", file=self.file) 91 return False 92 visitor.font = font 93 94 self._open("{") 95 for tag in font.keys(): 96 if self.comma: 97 print(",", file=self.file) 98 print('\n%s"%s": ' % (self._indent, tag), end="", file=self.file) 99 visitor.visit(font[tag]) 100 self._close("}") 101 102 del visitor.font 103 return False 104 105 106@JsonVisitor.register(ttLib.GlyphOrder) 107def visit(self, obj): 108 self.visitList(self.font.getGlyphOrder()) 109 return False 110 111 112@JsonVisitor.register_attr(ttLib.getTableClass("glyf"), "glyphOrder") 113def visit(visitor, obj, attr, value): 114 return False 115 116 117@JsonVisitor.register(ttLib.getTableModule("glyf").GlyphCoordinates) 118def visit(self, obj): 119 self.visitList(obj) 120 return False 121 122 123@JsonVisitor.register(Tag) 124def visit(self, obj): 125 print('"%s"' % str(obj), end="", file=self.file) 126 return False 127 128 129@JsonVisitor.register(array) 130def visit(self, obj): 131 self.visitList(obj) 132 return False 133 134 135@JsonVisitor.register(bytearray) 136def visit(self, obj): 137 self.visitList(obj) 138 return False 139 140 141if __name__ == "__main__": 142 from fontTools.ttLib import TTFont 143 import sys 144 145 if len(sys.argv) != 2: 146 print("usage: print-json.py font") 147 sys.exit() 148 149 font = TTFont(sys.argv[1]) 150 151 visitor = JsonVisitor(sys.stdout) 152 visitor.visit(font) 153