_s_b_i_x.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. from fontTools.misc import sstruct
  2. from fontTools.misc.textTools import safeEval, num2binary, binary2num
  3. from . import DefaultTable
  4. from .sbixStrike import Strike
  5. sbixHeaderFormat = """
  6. >
  7. version: H # Version number (set to 1)
  8. flags: H # The only two bits used in the flags field are bits 0
  9. # and 1. For historical reasons, bit 0 must always be 1.
  10. # Bit 1 is a sbixDrawOutlines flag and is interpreted as
  11. # follows:
  12. # 0: Draw only 'sbix' bitmaps
  13. # 1: Draw both 'sbix' bitmaps and outlines, in that
  14. # order
  15. numStrikes: L # Number of bitmap strikes to follow
  16. """
  17. sbixHeaderFormatSize = sstruct.calcsize(sbixHeaderFormat)
  18. sbixStrikeOffsetFormat = """
  19. >
  20. strikeOffset: L # Offset from begining of table to data for the
  21. # individual strike
  22. """
  23. sbixStrikeOffsetFormatSize = sstruct.calcsize(sbixStrikeOffsetFormat)
  24. class table__s_b_i_x(DefaultTable.DefaultTable):
  25. def __init__(self, tag=None):
  26. DefaultTable.DefaultTable.__init__(self, tag)
  27. self.version = 1
  28. self.flags = 1
  29. self.numStrikes = 0
  30. self.strikes = {}
  31. self.strikeOffsets = []
  32. def decompile(self, data, ttFont):
  33. # read table header
  34. sstruct.unpack(sbixHeaderFormat, data[:sbixHeaderFormatSize], self)
  35. # collect offsets to individual strikes in self.strikeOffsets
  36. for i in range(self.numStrikes):
  37. current_offset = sbixHeaderFormatSize + i * sbixStrikeOffsetFormatSize
  38. offset_entry = sbixStrikeOffset()
  39. sstruct.unpack(
  40. sbixStrikeOffsetFormat,
  41. data[current_offset : current_offset + sbixStrikeOffsetFormatSize],
  42. offset_entry,
  43. )
  44. self.strikeOffsets.append(offset_entry.strikeOffset)
  45. # decompile Strikes
  46. for i in range(self.numStrikes - 1, -1, -1):
  47. current_strike = Strike(rawdata=data[self.strikeOffsets[i] :])
  48. data = data[: self.strikeOffsets[i]]
  49. current_strike.decompile(ttFont)
  50. # print " Strike length: %xh" % len(bitmapSetData)
  51. # print "Number of Glyph entries:", len(current_strike.glyphs)
  52. if current_strike.ppem in self.strikes:
  53. from fontTools import ttLib
  54. raise ttLib.TTLibError("Pixel 'ppem' must be unique for each Strike")
  55. self.strikes[current_strike.ppem] = current_strike
  56. # after the glyph data records have been extracted, we don't need the offsets anymore
  57. del self.strikeOffsets
  58. del self.numStrikes
  59. def compile(self, ttFont):
  60. sbixData = b""
  61. self.numStrikes = len(self.strikes)
  62. sbixHeader = sstruct.pack(sbixHeaderFormat, self)
  63. # calculate offset to start of first strike
  64. setOffset = sbixHeaderFormatSize + sbixStrikeOffsetFormatSize * self.numStrikes
  65. for si in sorted(self.strikes.keys()):
  66. current_strike = self.strikes[si]
  67. current_strike.compile(ttFont)
  68. # append offset to this strike to table header
  69. current_strike.strikeOffset = setOffset
  70. sbixHeader += sstruct.pack(sbixStrikeOffsetFormat, current_strike)
  71. setOffset += len(current_strike.data)
  72. sbixData += current_strike.data
  73. return sbixHeader + sbixData
  74. def toXML(self, xmlWriter, ttFont):
  75. xmlWriter.simpletag("version", value=self.version)
  76. xmlWriter.newline()
  77. xmlWriter.simpletag("flags", value=num2binary(self.flags, 16))
  78. xmlWriter.newline()
  79. for i in sorted(self.strikes.keys()):
  80. self.strikes[i].toXML(xmlWriter, ttFont)
  81. def fromXML(self, name, attrs, content, ttFont):
  82. if name == "version":
  83. setattr(self, name, safeEval(attrs["value"]))
  84. elif name == "flags":
  85. setattr(self, name, binary2num(attrs["value"]))
  86. elif name == "strike":
  87. current_strike = Strike()
  88. for element in content:
  89. if isinstance(element, tuple):
  90. name, attrs, content = element
  91. current_strike.fromXML(name, attrs, content, ttFont)
  92. self.strikes[current_strike.ppem] = current_strike
  93. else:
  94. from fontTools import ttLib
  95. raise ttLib.TTLibError("can't handle '%s' element" % name)
  96. # Helper classes
  97. class sbixStrikeOffset(object):
  98. pass