xref: /aosp_15_r20/external/fonttools/Snippets/print-json.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
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