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

1from fontTools.misc import sstruct 

2from fontTools.misc.textTools import readHex, safeEval 

3import struct 

4 

5 

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""" 

18 

19sbixGlyphHeaderFormatSize = sstruct.calcsize(sbixGlyphHeaderFormat) 

20 

21 

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 

42 

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 

49 

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))] 

56 

57 def decompile(self, ttFont): 

58 self.glyphName = ttFont.getGlyphName(self.gid) 

59 if self.rawdata is None: 

60 from fontTools import ttLib 

61 

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 

66 

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.") 

69 

70 sstruct.unpack( 

71 sbixGlyphHeaderFormat, self.rawdata[:sbixGlyphHeaderFormatSize], self 

72 ) 

73 

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 

84 

85 def compile(self, ttFont): 

86 if self.glyphName is None: 

87 from fontTools import ttLib 

88 

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 

103 

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() 

131 

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 

144 

145 raise ttLib.TTLibError("can't handle '%s' element" % name)