123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- from fontTools.misc import sstruct
- from fontTools.misc.textTools import readHex, safeEval
- import struct
- sbixGlyphHeaderFormat = """
- >
- originOffsetX: h # The x-value of the point in the glyph relative to its
- # lower-left corner which corresponds to the origin of
- # the glyph on the screen, that is the point on the
- # baseline at the left edge of the glyph.
- originOffsetY: h # The y-value of the point in the glyph relative to its
- # lower-left corner which corresponds to the origin of
- # the glyph on the screen, that is the point on the
- # baseline at the left edge of the glyph.
- graphicType: 4s # e.g. "png "
- """
- sbixGlyphHeaderFormatSize = sstruct.calcsize(sbixGlyphHeaderFormat)
- class Glyph(object):
- def __init__(
- self,
- glyphName=None,
- referenceGlyphName=None,
- originOffsetX=0,
- originOffsetY=0,
- graphicType=None,
- imageData=None,
- rawdata=None,
- gid=0,
- ):
- self.gid = gid
- self.glyphName = glyphName
- self.referenceGlyphName = referenceGlyphName
- self.originOffsetX = originOffsetX
- self.originOffsetY = originOffsetY
- self.rawdata = rawdata
- self.graphicType = graphicType
- self.imageData = imageData
- # fix self.graphicType if it is null terminated or too short
- if self.graphicType is not None:
- if self.graphicType[-1] == "\0":
- self.graphicType = self.graphicType[:-1]
- if len(self.graphicType) > 4:
- from fontTools import ttLib
- raise ttLib.TTLibError(
- "Glyph.graphicType must not be longer than 4 characters."
- )
- elif len(self.graphicType) < 4:
- # pad with spaces
- self.graphicType += " "[: (4 - len(self.graphicType))]
- def decompile(self, ttFont):
- self.glyphName = ttFont.getGlyphName(self.gid)
- if self.rawdata is None:
- from fontTools import ttLib
- raise ttLib.TTLibError("No table data to decompile")
- if len(self.rawdata) > 0:
- if len(self.rawdata) < sbixGlyphHeaderFormatSize:
- from fontTools import ttLib
- # print "Glyph %i header too short: Expected %x, got %x." % (self.gid, sbixGlyphHeaderFormatSize, len(self.rawdata))
- raise ttLib.TTLibError("Glyph header too short.")
- sstruct.unpack(
- sbixGlyphHeaderFormat, self.rawdata[:sbixGlyphHeaderFormatSize], self
- )
- if self.graphicType == "dupe":
- # this glyph is a reference to another glyph's image data
- (gid,) = struct.unpack(">H", self.rawdata[sbixGlyphHeaderFormatSize:])
- self.referenceGlyphName = ttFont.getGlyphName(gid)
- else:
- self.imageData = self.rawdata[sbixGlyphHeaderFormatSize:]
- self.referenceGlyphName = None
- # clean up
- del self.rawdata
- del self.gid
- def compile(self, ttFont):
- if self.glyphName is None:
- from fontTools import ttLib
- raise ttLib.TTLibError("Can't compile Glyph without glyph name")
- # TODO: if ttFont has no maxp, cmap etc., ignore glyph names and compile by index?
- # (needed if you just want to compile the sbix table on its own)
- self.gid = struct.pack(">H", ttFont.getGlyphID(self.glyphName))
- if self.graphicType is None:
- rawdata = b""
- else:
- rawdata = sstruct.pack(sbixGlyphHeaderFormat, self)
- if self.graphicType == "dupe":
- rawdata += struct.pack(">H", ttFont.getGlyphID(self.referenceGlyphName))
- else:
- assert self.imageData is not None
- rawdata += self.imageData
- self.rawdata = rawdata
- def toXML(self, xmlWriter, ttFont):
- if self.graphicType is None:
- # TODO: ignore empty glyphs?
- # a glyph data entry is required for each glyph,
- # but empty ones can be calculated at compile time
- xmlWriter.simpletag("glyph", name=self.glyphName)
- xmlWriter.newline()
- return
- xmlWriter.begintag(
- "glyph",
- graphicType=self.graphicType,
- name=self.glyphName,
- originOffsetX=self.originOffsetX,
- originOffsetY=self.originOffsetY,
- )
- xmlWriter.newline()
- if self.graphicType == "dupe":
- # graphicType == "dupe" is a reference to another glyph id.
- xmlWriter.simpletag("ref", glyphname=self.referenceGlyphName)
- else:
- xmlWriter.begintag("hexdata")
- xmlWriter.newline()
- xmlWriter.dumphex(self.imageData)
- xmlWriter.endtag("hexdata")
- xmlWriter.newline()
- xmlWriter.endtag("glyph")
- xmlWriter.newline()
- def fromXML(self, name, attrs, content, ttFont):
- if name == "ref":
- # glyph is a "dupe", i.e. a reference to another glyph's image data.
- # in this case imageData contains the glyph id of the reference glyph
- # get glyph id from glyphname
- glyphname = safeEval("'''" + attrs["glyphname"] + "'''")
- self.imageData = struct.pack(">H", ttFont.getGlyphID(glyphname))
- self.referenceGlyphName = glyphname
- elif name == "hexdata":
- self.imageData = readHex(content)
- else:
- from fontTools import ttLib
- raise ttLib.TTLibError("can't handle '%s' element" % name)
|