O_S_2f_2.py revision 170fc9d40fb1abf5bf5582f603ba4e9a0a441a0c
1import DefaultTable 2from fontTools.misc import sstruct 3from fontTools.misc.textTools import safeEval, num2binary, binary2num 4from types import TupleType 5 6 7# panose classification 8 9panoseFormat = """ 10 bFamilyType: B 11 bSerifStyle: B 12 bWeight: B 13 bProportion: B 14 bContrast: B 15 bStrokeVariation: B 16 bArmStyle: B 17 bLetterForm: B 18 bMidline: B 19 bXHeight: B 20""" 21 22class Panose: 23 24 def toXML(self, writer, ttFont): 25 formatstring, names, fixes = sstruct.getformat(panoseFormat) 26 for name in names: 27 writer.simpletag(name, value=getattr(self, name)) 28 writer.newline() 29 30 def fromXML(self, (name, attrs, content), ttFont): 31 setattr(self, name, safeEval(attrs["value"])) 32 33 34# 'sfnt' OS/2 and Windows Metrics table - 'OS/2' 35 36OS2_format_0 = """ 37 > # big endian 38 version: H # version 39 xAvgCharWidth: h # average character width 40 usWeightClass: H # degree of thickness of strokes 41 usWidthClass: H # aspect ratio 42 fsType: h # type flags 43 ySubscriptXSize: h # subscript horizontal font size 44 ySubscriptYSize: h # subscript vertical font size 45 ySubscriptXOffset: h # subscript x offset 46 ySubscriptYOffset: h # subscript y offset 47 ySuperscriptXSize: h # superscript horizontal font size 48 ySuperscriptYSize: h # superscript vertical font size 49 ySuperscriptXOffset: h # superscript x offset 50 ySuperscriptYOffset: h # superscript y offset 51 yStrikeoutSize: h # strikeout size 52 yStrikeoutPosition: h # strikeout position 53 sFamilyClass: h # font family class and subclass 54 panose: 10s # panose classification number 55 ulUnicodeRange1: L # character range 56 ulUnicodeRange2: L # character range 57 ulUnicodeRange3: L # character range 58 ulUnicodeRange4: L # character range 59 achVendID: 4s # font vendor identification 60 fsSelection: H # font selection flags 61 fsFirstCharIndex: H # first unicode character index 62 fsLastCharIndex: H # last unicode character index 63 sTypoAscender: h # typographic ascender 64 sTypoDescender: h # typographic descender 65 sTypoLineGap: h # typographic line gap 66 usWinAscent: H # Windows ascender 67 usWinDescent: H # Windows descender 68""" 69 70OS2_format_1_addition = """ 71 ulCodePageRange1: L 72 ulCodePageRange2: L 73""" 74 75OS2_format_2_addition = OS2_format_1_addition + """ 76 sxHeight: h 77 sCapHeight: h 78 usDefaultChar: H 79 usBreakChar: H 80 usMaxContex: H 81""" 82 83OS2_format_5_addition = OS2_format_2_addition + """ 84 usLowerOpticalPointSize: H 85 usUpperOpticalPointSize: H 86""" 87 88bigendian = " > # big endian\n" 89 90OS2_format_1 = OS2_format_0 + OS2_format_1_addition 91OS2_format_2 = OS2_format_0 + OS2_format_2_addition 92OS2_format_5 = OS2_format_0 + OS2_format_5_addition 93OS2_format_1_addition = bigendian + OS2_format_1_addition 94OS2_format_2_addition = bigendian + OS2_format_2_addition 95OS2_format_5_addition = bigendian + OS2_format_5_addition 96 97 98class table_O_S_2f_2(DefaultTable.DefaultTable): 99 100 """the OS/2 table""" 101 102 def decompile(self, data, ttFont): 103 dummy, data = sstruct.unpack2(OS2_format_0, data, self) 104 # workarounds for buggy fonts (Apple, mona) 105 if not data: 106 self.version = 0 107 elif len(data) == sstruct.calcsize(OS2_format_1_addition): 108 self.version = 1 109 elif len(data) == sstruct.calcsize(OS2_format_2_addition): 110 if self.version not in (2, 3, 4): 111 self.version = 1 112 elif len(data) == sstruct.calcsize(OS2_format_5_addition): 113 self.version = 5 114 else: 115 from fontTools import ttLib 116 raise ttLib.TTLibError, "unknown format for OS/2 table (incorrect length): version %s" % (self.version, len(data)) 117 if self.version == 1: 118 sstruct.unpack2(OS2_format_1_addition, data, self) 119 elif self.version in (2, 3, 4): 120 sstruct.unpack2(OS2_format_2_addition, data, self) 121 elif self.version == 5: 122 sstruct.unpack2(OS2_format_5_addition, data, self) 123 self.usLowerOpticalPointSize /= 20. 124 self.usUpperOpticalPointSize /= 20. 125 elif self.version <> 0: 126 from fontTools import ttLib 127 raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version 128 self.panose = sstruct.unpack(panoseFormat, self.panose, Panose()) 129 130 def compile(self, ttFont): 131 panose = self.panose 132 self.panose = sstruct.pack(panoseFormat, self.panose) 133 if self.version == 0: 134 data = sstruct.pack(OS2_format_0, self) 135 elif self.version == 1: 136 data = sstruct.pack(OS2_format_1, self) 137 elif self.version in (2, 3, 4): 138 data = sstruct.pack(OS2_format_2, self) 139 elif self.version == 5: 140 lower = self.usLowerOpticalPointSize 141 upper = self.usUpperOpticalPointSize 142 self.usLowerOpticalPointSize = int(round(self.usLowerOpticalPointSize * 20)) 143 self.usUpperOpticalPointSize = int(round(self.usUpperOpticalPointSize * 20)) 144 data = sstruct.pack(OS2_format_5, self) 145 self.usLowerOpticalPointSize = lower 146 self.usUpperOpticalPointSize = upper 147 else: 148 from fontTools import ttLib 149 raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version 150 self.panose = panose 151 return data 152 153 def toXML(self, writer, ttFont): 154 if self.version == 1: 155 format = OS2_format_1 156 elif self.version in (2, 3, 4): 157 format = OS2_format_2 158 elif self.version == 5: 159 format = OS2_format_5 160 else: 161 format = OS2_format_0 162 formatstring, names, fixes = sstruct.getformat(format) 163 for name in names: 164 value = getattr(self, name) 165 if type(value) == type(0L): 166 value = int(value) 167 if name=="panose": 168 writer.begintag("panose") 169 writer.newline() 170 value.toXML(writer, ttFont) 171 writer.endtag("panose") 172 elif name in ("ulUnicodeRange1", "ulUnicodeRange2", 173 "ulUnicodeRange3", "ulUnicodeRange4", 174 "ulCodePageRange1", "ulCodePageRange2"): 175 writer.simpletag(name, value=num2binary(value)) 176 elif name in ("fsType", "fsSelection"): 177 writer.simpletag(name, value=num2binary(value, 16)) 178 elif name == "achVendID": 179 writer.simpletag(name, value=repr(value)[1:-1]) 180 else: 181 writer.simpletag(name, value=value) 182 writer.newline() 183 184 def fromXML(self, (name, attrs, content), ttFont): 185 if name == "panose": 186 self.panose = panose = Panose() 187 for element in content: 188 if type(element) == TupleType: 189 panose.fromXML(element, ttFont) 190 elif name in ("ulUnicodeRange1", "ulUnicodeRange2", 191 "ulUnicodeRange3", "ulUnicodeRange4", 192 "ulCodePageRange1", "ulCodePageRange2", 193 "fsType", "fsSelection"): 194 setattr(self, name, binary2num(attrs["value"])) 195 elif name == "achVendID": 196 setattr(self, name, safeEval("'''" + attrs["value"] + "'''")) 197 else: 198 setattr(self, name, safeEval(attrs["value"])) 199 200 201