def decompileCoordinates(self, data): endPtsOfContours = array.array("h") endPtsOfContours.fromstring(data[:2 * self.numberOfContours]) if sys.byteorder <> "big": endPtsOfContours.byteswap() self.endPtsOfContours = endPtsOfContours.tolist() data = data[2 * self.numberOfContours:] instructionLength, = struct.unpack(">h", data[:2]) data = data[2:] self.program = ttProgram.Program() self.program.fromBytecode(data[:instructionLength]) data = data[instructionLength:] nCoordinates = self.endPtsOfContours[-1] + 1 flags, xCoordinates, yCoordinates = \ self.decompileCoordinatesRaw(nCoordinates, data) # fill in repetitions and apply signs coordinates = numpy.zeros((nCoordinates, 2), numpy.int16) xIndex = 0 yIndex = 0 for i in range(nCoordinates): flag = flags[i] # x coordinate if flag & flagXShort: if flag & flagXsame: x = xCoordinates[xIndex] else: x = -xCoordinates[xIndex] xIndex = xIndex + 1 elif flag & flagXsame: x = 0 else: x = xCoordinates[xIndex] xIndex = xIndex + 1 # y coordinate if flag & flagYShort: if flag & flagYsame: y = yCoordinates[yIndex] else: y = -yCoordinates[yIndex] yIndex = yIndex + 1 elif flag & flagYsame: y = 0 else: y = yCoordinates[yIndex] yIndex = yIndex + 1 coordinates[i] = (x, y) assert xIndex == len(xCoordinates) assert yIndex == len(yCoordinates) # convert relative to absolute coordinates self.coordinates = numpy.add.accumulate(coordinates) # discard all flags but for "flagOnCurve" self.flags = numpy.bitwise_and(flags, flagOnCurve).astype(numpy.int8)
def decompileComponents(self, data, glyfTable): self.components = [] more = 1 haveInstructions = 0 while more: component = GlyphComponent() more, haveInstr, data = component.decompile(data, glyfTable) haveInstructions = haveInstructions | haveInstr self.components.append(component) if haveInstructions: numInstructions, = struct.unpack(">h", data[:2]) data = data[2:] self.program = ttProgram.Program() self.program.fromBytecode(data[:numInstructions]) data = data[numInstructions:] assert len(data) < 4, "bad composite data"
class table__f_p_g_m(DefaultTable.DefaultTable): def decompile(self, data, ttFont): program = ttProgram.Program() program.fromBytecode(data) self.program = program def compile(self, ttFont): return self.program.getBytecode() def toXML(self, writer, ttFont): self.program.toXML(writer, ttFont) writer.newline() def fromXML(self, (name, attrs, content), ttFont): program = ttProgram.Program() program.fromXML((name, attrs, content), ttFont) self.program = program
def decompile(self, data, ttFont): program = ttProgram.Program() program.fromBytecode(data) self.program = program
class Glyph: def __init__(self, data=""): if not data: # empty char self.numberOfContours = 0 return self.data = data def compact(self, glyfTable, recalcBBoxes=1): data = self.compile(glyfTable, recalcBBoxes) self.__dict__.clear() self.data = data def expand(self, glyfTable): if not hasattr(self, "data"): # already unpacked return if not self.data: # empty char self.numberOfContours = 0 return dummy, data = sstruct.unpack2(glyphHeaderFormat, self.data, self) del self.data if self.isComposite(): self.decompileComponents(data, glyfTable) else: self.decompileCoordinates(data) def compile(self, glyfTable, recalcBBoxes=1): if hasattr(self, "data"): return self.data if self.numberOfContours == 0: return "" if recalcBBoxes: self.recalcBounds(glyfTable) data = sstruct.pack(glyphHeaderFormat, self) if self.isComposite(): data = data + self.compileComponents(glyfTable) else: data = data + self.compileCoordinates() # From the spec: "Note that the local offsets should be word-aligned" # From a later MS spec: "Note that the local offsets should be long-aligned" # Let's be modern and align on 4-byte boundaries. if len(data) % 4: # add pad bytes nPadBytes = 4 - (len(data) % 4) data = data + "\0" * nPadBytes return data def toXML(self, writer, ttFont): if self.isComposite(): for compo in self.components: compo.toXML(writer, ttFont) if hasattr(self, "program"): writer.begintag("instructions") self.program.toXML(writer, ttFont) writer.endtag("instructions") writer.newline() else: last = 0 for i in range(self.numberOfContours): writer.begintag("contour") writer.newline() for j in range(last, self.endPtsOfContours[i] + 1): writer.simpletag("pt", [("x", self.coordinates[j][0]), ("y", self.coordinates[j][1]), ("on", self.flags[j] & flagOnCurve)]) writer.newline() last = self.endPtsOfContours[i] + 1 writer.endtag("contour") writer.newline() if self.numberOfContours: writer.begintag("instructions") self.program.toXML(writer, ttFont) writer.endtag("instructions") writer.newline() def fromXML(self, (name, attrs, content), ttFont): if name == "contour": self.numberOfContours = self.numberOfContours + 1 if self.numberOfContours < 0: raise ttLib.TTLibError, "can't mix composites and contours in glyph" coordinates = [] flags = [] for element in content: if type(element) <> TupleType: continue name, attrs, content = element if name <> "pt": continue # ignore anything but "pt" coordinates.append( [safeEval(attrs["x"]), safeEval(attrs["y"])]) flags.append(not not safeEval(attrs["on"])) coordinates = numpy.array(coordinates, numpy.int16) flags = numpy.array(flags, numpy.int8) if not hasattr(self, "coordinates"): self.coordinates = coordinates self.flags = flags self.endPtsOfContours = [len(coordinates) - 1] else: self.coordinates = numpy.concatenate( (self.coordinates, coordinates)) self.flags = numpy.concatenate((self.flags, flags)) self.endPtsOfContours.append(len(self.coordinates) - 1) elif name == "component": if self.numberOfContours > 0: raise ttLib.TTLibError, "can't mix composites and contours in glyph" self.numberOfContours = -1 if not hasattr(self, "components"): self.components = [] component = GlyphComponent() self.components.append(component) component.fromXML((name, attrs, content), ttFont) elif name == "instructions": self.program = ttProgram.Program() for element in content: if type(element) <> TupleType: continue self.program.fromXML(element, ttFont)