Coverage for /usr/lib/python3/dist-packages/fontTools/ttLib/tables/sbixGlyph.py: 14%
78 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from fontTools.misc import sstruct
2from fontTools.misc.textTools import readHex, safeEval
3import struct
6sbixGlyphHeaderFormat = """
7 >
8 originOffsetX: h # The x-value of the point in the glyph relative to its
9 # lower-left corner which corresponds to the origin of
10 # the glyph on the screen, that is the point on the
11 # baseline at the left edge of the glyph.
12 originOffsetY: h # The y-value of the point in the glyph relative to its
13 # lower-left corner which corresponds to the origin of
14 # the glyph on the screen, that is the point on the
15 # baseline at the left edge of the glyph.
16 graphicType: 4s # e.g. "png "
17"""
19sbixGlyphHeaderFormatSize = sstruct.calcsize(sbixGlyphHeaderFormat)
22class Glyph(object):
23 def __init__(
24 self,
25 glyphName=None,
26 referenceGlyphName=None,
27 originOffsetX=0,
28 originOffsetY=0,
29 graphicType=None,
30 imageData=None,
31 rawdata=None,
32 gid=0,
33 ):
34 self.gid = gid
35 self.glyphName = glyphName
36 self.referenceGlyphName = referenceGlyphName
37 self.originOffsetX = originOffsetX
38 self.originOffsetY = originOffsetY
39 self.rawdata = rawdata
40 self.graphicType = graphicType
41 self.imageData = imageData
43 # fix self.graphicType if it is null terminated or too short
44 if self.graphicType is not None:
45 if self.graphicType[-1] == "\0":
46 self.graphicType = self.graphicType[:-1]
47 if len(self.graphicType) > 4:
48 from fontTools import ttLib
50 raise ttLib.TTLibError(
51 "Glyph.graphicType must not be longer than 4 characters."
52 )
53 elif len(self.graphicType) < 4:
54 # pad with spaces
55 self.graphicType += " "[: (4 - len(self.graphicType))]
57 def decompile(self, ttFont):
58 self.glyphName = ttFont.getGlyphName(self.gid)
59 if self.rawdata is None:
60 from fontTools import ttLib
62 raise ttLib.TTLibError("No table data to decompile")
63 if len(self.rawdata) > 0:
64 if len(self.rawdata) < sbixGlyphHeaderFormatSize:
65 from fontTools import ttLib
67 # print "Glyph %i header too short: Expected %x, got %x." % (self.gid, sbixGlyphHeaderFormatSize, len(self.rawdata))
68 raise ttLib.TTLibError("Glyph header too short.")
70 sstruct.unpack(
71 sbixGlyphHeaderFormat, self.rawdata[:sbixGlyphHeaderFormatSize], self
72 )
74 if self.graphicType == "dupe":
75 # this glyph is a reference to another glyph's image data
76 (gid,) = struct.unpack(">H", self.rawdata[sbixGlyphHeaderFormatSize:])
77 self.referenceGlyphName = ttFont.getGlyphName(gid)
78 else:
79 self.imageData = self.rawdata[sbixGlyphHeaderFormatSize:]
80 self.referenceGlyphName = None
81 # clean up
82 del self.rawdata
83 del self.gid
85 def compile(self, ttFont):
86 if self.glyphName is None:
87 from fontTools import ttLib
89 raise ttLib.TTLibError("Can't compile Glyph without glyph name")
90 # TODO: if ttFont has no maxp, cmap etc., ignore glyph names and compile by index?
91 # (needed if you just want to compile the sbix table on its own)
92 self.gid = struct.pack(">H", ttFont.getGlyphID(self.glyphName))
93 if self.graphicType is None:
94 rawdata = b""
95 else:
96 rawdata = sstruct.pack(sbixGlyphHeaderFormat, self)
97 if self.graphicType == "dupe":
98 rawdata += struct.pack(">H", ttFont.getGlyphID(self.referenceGlyphName))
99 else:
100 assert self.imageData is not None
101 rawdata += self.imageData
102 self.rawdata = rawdata
104 def toXML(self, xmlWriter, ttFont):
105 if self.graphicType is None:
106 # TODO: ignore empty glyphs?
107 # a glyph data entry is required for each glyph,
108 # but empty ones can be calculated at compile time
109 xmlWriter.simpletag("glyph", name=self.glyphName)
110 xmlWriter.newline()
111 return
112 xmlWriter.begintag(
113 "glyph",
114 graphicType=self.graphicType,
115 name=self.glyphName,
116 originOffsetX=self.originOffsetX,
117 originOffsetY=self.originOffsetY,
118 )
119 xmlWriter.newline()
120 if self.graphicType == "dupe":
121 # graphicType == "dupe" is a reference to another glyph id.
122 xmlWriter.simpletag("ref", glyphname=self.referenceGlyphName)
123 else:
124 xmlWriter.begintag("hexdata")
125 xmlWriter.newline()
126 xmlWriter.dumphex(self.imageData)
127 xmlWriter.endtag("hexdata")
128 xmlWriter.newline()
129 xmlWriter.endtag("glyph")
130 xmlWriter.newline()
132 def fromXML(self, name, attrs, content, ttFont):
133 if name == "ref":
134 # glyph is a "dupe", i.e. a reference to another glyph's image data.
135 # in this case imageData contains the glyph id of the reference glyph
136 # get glyph id from glyphname
137 glyphname = safeEval("'''" + attrs["glyphname"] + "'''")
138 self.imageData = struct.pack(">H", ttFont.getGlyphID(glyphname))
139 self.referenceGlyphName = glyphname
140 elif name == "hexdata":
141 self.imageData = readHex(content)
142 else:
143 from fontTools import ttLib
145 raise ttLib.TTLibError("can't handle '%s' element" % name)