Our footprint in the Python module namespace is all under fontTools now. User code importing sstruct should be updated to say "from fontTools.misc import sstruct".
178 lines
5.9 KiB
Python
178 lines
5.9 KiB
Python
import DefaultTable
|
|
from fontTools.misc import sstruct
|
|
from fontTools.misc.textTools import safeEval, num2binary, binary2num
|
|
from types import TupleType
|
|
|
|
|
|
# panose classification
|
|
|
|
panoseFormat = """
|
|
bFamilyType: B
|
|
bSerifStyle: B
|
|
bWeight: B
|
|
bProportion: B
|
|
bContrast: B
|
|
bStrokeVariation: B
|
|
bArmStyle: B
|
|
bLetterForm: B
|
|
bMidline: B
|
|
bXHeight: B
|
|
"""
|
|
|
|
class Panose:
|
|
|
|
def toXML(self, writer, ttFont):
|
|
formatstring, names, fixes = sstruct.getformat(panoseFormat)
|
|
for name in names:
|
|
writer.simpletag(name, value=getattr(self, name))
|
|
writer.newline()
|
|
|
|
def fromXML(self, (name, attrs, content), ttFont):
|
|
setattr(self, name, safeEval(attrs["value"]))
|
|
|
|
|
|
# 'sfnt' OS/2 and Windows Metrics table - 'OS/2'
|
|
|
|
OS2_format_0 = """
|
|
> # big endian
|
|
version: H # version
|
|
xAvgCharWidth: h # average character width
|
|
usWeightClass: H # degree of thickness of strokes
|
|
usWidthClass: H # aspect ratio
|
|
fsType: h # type flags
|
|
ySubscriptXSize: h # subscript horizontal font size
|
|
ySubscriptYSize: h # subscript vertical font size
|
|
ySubscriptXOffset: h # subscript x offset
|
|
ySubscriptYOffset: h # subscript y offset
|
|
ySuperscriptXSize: h # superscript horizontal font size
|
|
ySuperscriptYSize: h # superscript vertical font size
|
|
ySuperscriptXOffset: h # superscript x offset
|
|
ySuperscriptYOffset: h # superscript y offset
|
|
yStrikeoutSize: h # strikeout size
|
|
yStrikeoutPosition: h # strikeout position
|
|
sFamilyClass: h # font family class and subclass
|
|
panose: 10s # panose classification number
|
|
ulUnicodeRange1: L # character range
|
|
ulUnicodeRange2: L # character range
|
|
ulUnicodeRange3: L # character range
|
|
ulUnicodeRange4: L # character range
|
|
achVendID: 4s # font vendor identification
|
|
fsSelection: H # font selection flags
|
|
fsFirstCharIndex: H # first unicode character index
|
|
fsLastCharIndex: H # last unicode character index
|
|
sTypoAscender: h # typographic ascender
|
|
sTypoDescender: h # typographic descender
|
|
sTypoLineGap: h # typographic line gap
|
|
usWinAscent: H # Windows ascender
|
|
usWinDescent: H # Windows descender
|
|
"""
|
|
|
|
OS2_format_1_addition = """
|
|
ulCodePageRange1: L
|
|
ulCodePageRange2: L
|
|
"""
|
|
|
|
OS2_format_2_addition = OS2_format_1_addition + """
|
|
sxHeight: h
|
|
sCapHeight: h
|
|
usDefaultChar: H
|
|
usBreakChar: H
|
|
usMaxContex: H
|
|
"""
|
|
|
|
bigendian = " > # big endian\n"
|
|
|
|
OS2_format_1 = OS2_format_0 + OS2_format_1_addition
|
|
OS2_format_2 = OS2_format_0 + OS2_format_2_addition
|
|
OS2_format_1_addition = bigendian + OS2_format_1_addition
|
|
OS2_format_2_addition = bigendian + OS2_format_2_addition
|
|
|
|
|
|
class table_O_S_2f_2(DefaultTable.DefaultTable):
|
|
|
|
"""the OS/2 table"""
|
|
|
|
def decompile(self, data, ttFont):
|
|
dummy, data = sstruct.unpack2(OS2_format_0, data, self)
|
|
# workarounds for buggy fonts (Apple, mona)
|
|
if not data:
|
|
self.version = 0
|
|
elif len(data) == sstruct.calcsize(OS2_format_1_addition):
|
|
self.version = 1
|
|
elif len(data) == sstruct.calcsize(OS2_format_2_addition):
|
|
if self.version not in (2, 3, 4):
|
|
self.version = 1
|
|
else:
|
|
from fontTools import ttLib
|
|
raise ttLib.TTLibError, "unknown format for OS/2 table (incorrect length): version %s" % (self.version, len(data))
|
|
if self.version == 1:
|
|
sstruct.unpack2(OS2_format_1_addition, data, self)
|
|
elif self.version in (2, 3, 4):
|
|
sstruct.unpack2(OS2_format_2_addition, data, self)
|
|
elif self.version <> 0:
|
|
from fontTools import ttLib
|
|
raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version
|
|
self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
|
|
|
|
def compile(self, ttFont):
|
|
panose = self.panose
|
|
self.panose = sstruct.pack(panoseFormat, self.panose)
|
|
if self.version == 0:
|
|
data = sstruct.pack(OS2_format_0, self)
|
|
elif self.version == 1:
|
|
data = sstruct.pack(OS2_format_1, self)
|
|
elif self.version in (2, 3, 4):
|
|
data = sstruct.pack(OS2_format_2, self)
|
|
else:
|
|
from fontTools import ttLib
|
|
raise ttLib.TTLibError, "unknown format for OS/2 table: version %s" % self.version
|
|
self.panose = panose
|
|
return data
|
|
|
|
def toXML(self, writer, ttFont):
|
|
if self.version == 1:
|
|
format = OS2_format_1
|
|
elif self.version in (2, 3, 4):
|
|
format = OS2_format_2
|
|
else:
|
|
format = OS2_format_0
|
|
formatstring, names, fixes = sstruct.getformat(format)
|
|
for name in names:
|
|
value = getattr(self, name)
|
|
if type(value) == type(0L):
|
|
value = int(value)
|
|
if name=="panose":
|
|
writer.begintag("panose")
|
|
writer.newline()
|
|
value.toXML(writer, ttFont)
|
|
writer.endtag("panose")
|
|
elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
|
|
"ulUnicodeRange3", "ulUnicodeRange4",
|
|
"ulCodePageRange1", "ulCodePageRange2"):
|
|
writer.simpletag(name, value=num2binary(value))
|
|
elif name in ("fsType", "fsSelection"):
|
|
writer.simpletag(name, value=num2binary(value, 16))
|
|
elif name == "achVendID":
|
|
writer.simpletag(name, value=repr(value)[1:-1])
|
|
else:
|
|
writer.simpletag(name, value=value)
|
|
writer.newline()
|
|
|
|
def fromXML(self, (name, attrs, content), ttFont):
|
|
if name == "panose":
|
|
self.panose = panose = Panose()
|
|
for element in content:
|
|
if type(element) == TupleType:
|
|
panose.fromXML(element, ttFont)
|
|
elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
|
|
"ulUnicodeRange3", "ulUnicodeRange4",
|
|
"ulCodePageRange1", "ulCodePageRange2",
|
|
"fsType", "fsSelection"):
|
|
setattr(self, name, binary2num(attrs["value"]))
|
|
elif name == "achVendID":
|
|
setattr(self, name, safeEval("'''" + attrs["value"] + "'''"))
|
|
else:
|
|
setattr(self, name, safeEval(attrs["value"]))
|
|
|
|
|