Beispiel #1
0
 def _startElementHandler(self, name, attrs):
     stackSize = self.stackSize
     self.stackSize = stackSize + 1
     if not stackSize:
         if name != "ttFont":
             raise TTXParseError("illegal root tag: %s" % name)
         sfntVersion = attrs.get("sfntVersion")
         if sfntVersion is not None:
             if len(sfntVersion) != 4:
                 sfntVersion = safeEval('"' + sfntVersion + '"')
             self.ttFont.sfntVersion = sfntVersion
         self.contentStack.append([])
     elif stackSize == 1:
         subFile = attrs.get("src")
         if subFile is not None:
             if hasattr(self.file, 'name'):
                 # if file has a name, get its parent directory
                 dirname = os.path.dirname(self.file.name)
             else:
                 # else fall back to using the current working directory
                 dirname = os.getcwd()
             subFile = os.path.join(dirname, subFile)
             subReader = XMLReader(subFile, self.ttFont, self.progress,
                                   self.quiet)
             subReader.read()
             self.contentStack.append([])
             return
         tag = ttLib.xmlToTag(name)
         msg = "Parsing '%s' table..." % tag
         if self.progress:
             self.progress.setLabel(msg)
         elif self.ttFont.verbose:
             ttLib.debugmsg(msg)
         else:
             if not self.quiet:
                 print(msg)
         if tag == "GlyphOrder":
             tableClass = ttLib.GlyphOrder
         elif "ERROR" in attrs or ('raw' in attrs
                                   and safeEval(attrs['raw'])):
             tableClass = DefaultTable
         else:
             tableClass = ttLib.getTableClass(tag)
             if tableClass is None:
                 tableClass = DefaultTable
         if tag == 'loca' and tag in self.ttFont:
             # Special-case the 'loca' table as we need the
             #    original if the 'glyf' table isn't recompiled.
             self.currentTable = self.ttFont[tag]
         else:
             self.currentTable = tableClass(tag)
             self.ttFont[tag] = self.currentTable
         self.contentStack.append([])
     elif stackSize == 2:
         self.contentStack.append([])
         self.root = (name, attrs, self.contentStack[-1])
     else:
         l = []
         self.contentStack[-1].append((name, attrs, l))
         self.contentStack.append(l)
Beispiel #2
0
 def _writeTableDirectory(self):
     if self.verbose:
         debugmsg("writing table directory")
     self.file.seek(woffHeaderSize)
     for tag, (index, entry, data) in sorted(self.tables.items()):
         entry = sstruct.pack(woffDirectoryEntryFormat, entry)
         self.file.write(entry)
Beispiel #3
0
 def _writeTableDirectory(self):
     if self.verbose:
         debugmsg("writing table directory")
     self.file.seek(woffHeaderSize)
     for tag, (index, entry, data) in sorted(self.tables.items()):
         entry = sstruct.pack(woffDirectoryEntryFormat, entry)
         self.file.write(entry)
Beispiel #4
0
 def _checkTableConformance(self, entry, data):
     """
     Check the conformance of the table directory entries.
     These must be checked because the origChecksum, origLength
     and compLength can be set by an outside caller.
     """
     if self.verbose:
         debugmsg("checking conformance of '%s' table" % entry.tag)
     # origLength must be less than or equal to compLength
     if entry.origLength < entry.compLength:
         raise WOFFLibError(
             "origLength and compLength are not correct in the '%s' table entry."
             % entry.tag)
     # unpack the data as needed
     if entry.origLength > entry.compLength:
         origData = zlib.decompress(data)
         compData = data
     else:
         origData = data
         compData = data
     # the origLength entry must match the actual length
     if entry.origLength != len(origData):
         raise WOFFLibError(
             "origLength is not correct in the '%s' table entry." %
             entry.tag)
     # the checksum must be correct
     if entry.origChecksum != calcTableChecksum(entry.tag, origData):
         raise WOFFLibError(
             "origChecksum is not correct in the '%s' table entry." %
             entry.tag)
     # the compLength must be correct
     if entry.compLength != len(compData):
         raise WOFFLibError(
             "compLength is not correct in the '%s' table entry." %
             entry.tag)
Beispiel #5
0
 def _checkTableConformance(self, entry, data):
     """
     Check the conformance of the table directory entries.
     These must be checked because the origChecksum, origLength
     and compLength can be set by an outside caller.
     """
     if self.verbose:
         debugmsg("checking conformance of '%s' table" % entry.tag)
     # origLength must be less than or equal to compLength
     if entry.origLength < entry.compLength:
         raise WOFFLibError("origLength and compLength are not correct in the '%s' table entry." % entry.tag)
     # unpack the data as needed
     if entry.origLength > entry.compLength:
         origData = zlib.decompress(data)
         compData = data
     else:
         origData = data
         compData = data
     # the origLength entry must match the actual length
     if entry.origLength != len(origData):
         raise WOFFLibError("origLength is not correct in the '%s' table entry." % entry.tag)
     # the checksum must be correct
     if entry.origChecksum != calcTableChecksum(entry.tag, origData):
         raise WOFFLibError("origChecksum is not correct in the '%s' table entry." % entry.tag)
     # the compLength must be correct
     if entry.compLength != len(compData):
         raise WOFFLibError("compLength is not correct in the '%s' table entry." % entry.tag)
Beispiel #6
0
 def _prepTable(self, tag, data, origLength=None, origChecksum=None, compLength=None, entryOnly=False):
     # skip data prep
     if entryOnly:
         origLength = origLength
         origChecksum = calcTableChecksum(tag, data)
         compLength = 0
     # prep the data
     else:
         # compress
         if compLength is None:
             origData = data
             origLength = len(origData)
             origChecksum = calcTableChecksum(tag, data)
             if self.verbose:
                 debugmsg("compressing '%s' table" % tag)
             compData = zlib.compress(origData, self.compressionLevel)
             compLength = len(compData)
             if origLength <= compLength:
                 data = origData
                 compLength = origLength
             else:
                 data = compData
     # make the directory entry
     entry = WOFFDirectoryEntry()
     entry.tag = tag
     entry.offset = 0
     entry.origLength = origLength
     entry.origChecksum = origChecksum
     entry.compLength = compLength
     # return
     if entryOnly:
         return entry
     return entry, data
Beispiel #7
0
	def _startElementHandler(self, name, attrs):
		stackSize = self.stackSize
		self.stackSize = stackSize + 1
		if not stackSize:
			if name != "ttFont":
				raise TTXParseError("illegal root tag: %s" % name)
			sfntVersion = attrs.get("sfntVersion")
			if sfntVersion is not None:
				if len(sfntVersion) != 4:
					sfntVersion = safeEval('"' + sfntVersion + '"')
				self.ttFont.sfntVersion = sfntVersion
			self.contentStack.append([])
		elif stackSize == 1:
			subFile = attrs.get("src")
			if subFile is not None:
				if hasattr(self.file, 'name'):
					# if file has a name, get its parent directory
					dirname = os.path.dirname(self.file.name)
				else:
					# else fall back to using the current working directory
					dirname = os.getcwd()
				subFile = os.path.join(dirname, subFile)
				subReader = XMLReader(subFile, self.ttFont, self.progress, self.quiet)
				subReader.read()
				self.contentStack.append([])
				return
			tag = ttLib.xmlToTag(name)
			msg = "Parsing '%s' table..." % tag
			if self.progress:
				self.progress.setLabel(msg)
			elif self.ttFont.verbose:
				ttLib.debugmsg(msg)
			else:
				if not self.quiet:
					print(msg)
			if tag == "GlyphOrder":
				tableClass = ttLib.GlyphOrder
			elif "ERROR" in attrs or ('raw' in attrs and safeEval(attrs['raw'])):
				tableClass = DefaultTable
			else:
				tableClass = ttLib.getTableClass(tag)
				if tableClass is None:
					tableClass = DefaultTable
			if tag == 'loca' and tag in self.ttFont:
				# Special-case the 'loca' table as we need the
				#    original if the 'glyf' table isn't recompiled.
				self.currentTable = self.ttFont[tag]
			else:
				self.currentTable = tableClass(tag)
				self.ttFont[tag] = self.currentTable
			self.contentStack.append([])
		elif stackSize == 2:
			self.contentStack.append([])
			self.root = (name, attrs, self.contentStack[-1])
		else:
			l = []
			self.contentStack[-1].append((name, attrs, l))
			self.contentStack.append(l)
Beispiel #8
0
 def _writePrivateData(self):
     if self.privateData is None:
         return
     if self.verbose:
         debugmsg("writing private data")
     if self.metadata is not None:
         self.privOffset = self.metadataEnd
     else:
         self.privOffset = self.tableDataEnd
     self.length += self.privLength
     self.file.seek(self.privOffset)
     self.file.write(self.privateData)
Beispiel #9
0
 def _writePrivateData(self):
     if self.privateData is None:
         return
     if self.verbose:
         debugmsg("writing private data")
     if self.metadata is not None:
         self.privOffset = self.metadataEnd
     else:
         self.privOffset = self.tableDataEnd
     self.length += self.privLength
     self.file.seek(self.privOffset)
     self.file.write(self.privateData)
Beispiel #10
0
	def startElementHandler(self, name, attrs):
		stackSize = self.stackSize
		self.stackSize = stackSize + 1
		if not stackSize:
			if name <> "ttFont":
				raise TTXParseError, "illegal root tag: %s" % name
			sfntVersion = attrs.get("sfntVersion")
			if sfntVersion is not None:
				if len(sfntVersion) <> 4:
					sfntVersion = safeEval('"' + sfntVersion + '"')
				self.ttFont.sfntVersion = sfntVersion
			self.contentStack.append([])
		elif stackSize == 1:
			subFile = attrs.get("src")
			if subFile is not None:
				subFile = os.path.join(os.path.dirname(self.fileName), subFile)
				importXML(self.ttFont, subFile, self.progress)
				self.contentStack.append([])
				return
			tag = ttLib.xmlToTag(name)
			msg = "Parsing '%s' table..." % tag
			if self.progress:
				self.progress.setlabel(msg)
			elif self.ttFont.verbose:
				ttLib.debugmsg(msg)
			else:
				if not self.quiet:
					print msg
			if tag == "GlyphOrder":
				tableClass = ttLib.GlyphOrder
			elif attrs.has_key("ERROR"):
				tableClass = DefaultTable
			else:
				tableClass = ttLib.getTableClass(tag)
				if tableClass is None:
					tableClass = DefaultTable
			if tag == 'loca' and self.ttFont.has_key(tag):
				# Special-case the 'loca' table as we need the
				#    original if the 'glyf' table isn't recompiled.
				self.currentTable = self.ttFont[tag]
			else:
				self.currentTable = tableClass(tag)
				self.ttFont[tag] = self.currentTable
			self.contentStack.append([])
		elif stackSize == 2:
			self.contentStack.append([])
			self.root = (name, attrs, self.contentStack[-1])
		else:
			list = []
			self.contentStack[-1].append((name, attrs, list))
			self.contentStack.append(list)
Beispiel #11
0
 def setMetadata(self, data, metaOrigLength=None, metaLength=None):
     if not data:
         return
     if metaLength is None:
         if self.verbose:
             debugmsg("compressing metadata")
         metaOrigLength = len(data)
         data = zlib.compress(data, self.compressionLevel)
         metaLength = len(data)
     # set the header values
     self.metaOrigLength = metaOrigLength
     self.metaLength = metaLength
     # store
     self.metadata = data
Beispiel #12
0
 def _writeTableData(self):
     d = woffHeaderSize + (woffDirectoryEntrySize * self.numTables)
     offset = woffHeaderSize + (woffDirectoryEntrySize * self.numTables)
     self.file.seek(offset)
     for tag in self._tableOrder():
         if self.verbose:
             debugmsg("writing '%s' table" % tag)
         index, entry, data = self.tables[tag]
         data += "\0" * (calc4BytePaddedLength(entry.compLength) - entry.compLength ) # ensure byte alignment
         self.file.write(data)
         self.length += calc4BytePaddedLength(entry.compLength) # ensure byte alignment
         self.totalSFNTSize += calc4BytePaddedLength(entry.origLength) # ensure byte alignment
     # store the end for use by metadata or private data
     self.tableDataEnd = self.length
Beispiel #13
0
 def startElementHandler(self, name, attrs):
     stackSize = self.stackSize
     self.stackSize = stackSize + 1
     if not stackSize:
         if name <> "ttFont":
             raise TTXParseError, "illegal root tag: %s" % name
         sfntVersion = attrs.get("sfntVersion")
         if sfntVersion is not None:
             if len(sfntVersion) <> 4:
                 sfntVersion = safeEval('"' + sfntVersion + '"')
             self.ttFont.sfntVersion = sfntVersion
         self.contentStack.append([])
     elif stackSize == 1:
         subFile = attrs.get("src")
         if subFile is not None:
             subFile = os.path.join(os.path.dirname(self.fileName), subFile)
             importXML(self.ttFont, subFile, self.progress)
             self.contentStack.append([])
             return
         tag = ttLib.xmlToTag(name)
         msg = "Parsing '%s' table..." % tag
         if self.progress:
             self.progress.setlabel(msg)
         elif self.ttFont.verbose:
             ttLib.debugmsg(msg)
         else:
             print msg
         if tag == "GlyphOrder":
             tableClass = ttLib.GlyphOrder
         elif attrs.has_key("ERROR"):
             tableClass = DefaultTable
         else:
             tableClass = ttLib.getTableClass(tag)
             if tableClass is None:
                 tableClass = DefaultTable
         if tag == 'loca' and self.ttFont.has_key(tag):
             # Special-case the 'loca' table as we need the
             #    original if the 'glyf' table isn't recompiled.
             self.currentTable = self.ttFont[tag]
         else:
             self.currentTable = tableClass(tag)
             self.ttFont[tag] = self.currentTable
         self.contentStack.append([])
     elif stackSize == 2:
         self.contentStack.append([])
         self.root = (name, attrs, self.contentStack[-1])
     else:
         list = []
         self.contentStack[-1].append((name, attrs, list))
         self.contentStack.append(list)
Beispiel #14
0
 def setMetadata(self, data, metaOrigLength=None, metaLength=None):
     if not data:
         return
     if metaLength is None:
         if self.verbose:
             debugmsg("compressing metadata")
         metaOrigLength = len(data)
         data = zlib.compress(data, self.compressionLevel)
         metaLength = len(data)
     # set the header values
     self.metaOrigLength = metaOrigLength
     self.metaLength = metaLength
     # store
     self.metadata = data
Beispiel #15
0
 def _writeTableData(self):
     d = woffHeaderSize + (woffDirectoryEntrySize * self.numTables)
     offset = woffHeaderSize + (woffDirectoryEntrySize * self.numTables)
     self.file.seek(offset)
     for tag in self._tableOrder():
         if self.verbose:
             debugmsg("writing '%s' table" % tag)
         index, entry, data = self.tables[tag]
         data += "\0" * (calc4BytePaddedLength(entry.compLength) -
                         entry.compLength)  # ensure byte alignment
         self.file.write(data)
         self.length += calc4BytePaddedLength(
             entry.compLength)  # ensure byte alignment
         self.totalSFNTSize += calc4BytePaddedLength(
             entry.origLength)  # ensure byte alignment
     # store the end for use by metadata or private data
     self.tableDataEnd = self.length
Beispiel #16
0
 def _writeMetadata(self):
     if self.metadata is None:
         return
     if self.verbose:
         debugmsg("writing metadata")
     self.length += self.metaLength
     self.metaOffset = self.tableDataEnd
     self.file.seek(self.metaOffset)
     self.file.write(self.metadata)
     # store the end for use by private data
     self.metadataEnd = self.metaOffset + self.metaLength
     # if private data exists, pad to a four byte boundary
     if self.privateData is not None:
         padding = calc4BytePaddedLength(self.metaLength) - self.metaLength
         self.metadataEnd += padding
         self.length += padding
         padding = "\0" * padding
         if padding:
             self.file.write(padding)
Beispiel #17
0
 def _writeMetadata(self):
     if self.metadata is None:
         return
     if self.verbose:
         debugmsg("writing metadata")
     self.length += self.metaLength
     self.metaOffset = self.tableDataEnd
     self.file.seek(self.metaOffset)
     self.file.write(self.metadata)
     # store the end for use by private data
     self.metadataEnd = self.metaOffset + self.metaLength
     # if private data exists, pad to a four byte boundary
     if self.privateData is not None:
         padding = calc4BytePaddedLength(self.metaLength) - self.metaLength
         self.metadataEnd += padding
         self.length += padding
         padding = "\0" * padding
         if padding:
             self.file.write(padding)
Beispiel #18
0
	def fromXML(self, name, attrs, content, ttFont):
		if name != "TTGlyph":
			return
		if not hasattr(self, "glyphs"):
			self.glyphs = {}
		if not hasattr(self, "glyphOrder"):
			self.glyphOrder = ttFont.getGlyphOrder()
		glyphName = attrs["name"]
		if ttFont.verbose:
			ttLib.debugmsg("unpacking glyph '%s'" % glyphName)
		glyph = Glyph()
		for attr in ['xMin', 'yMin', 'xMax', 'yMax']:
			setattr(glyph, attr, safeEval(attrs.get(attr, '0')))
		self.glyphs[glyphName] = glyph
		for element in content:
			if not isinstance(element, tuple):
				continue
			name, attrs, content = element
			glyph.fromXML(name, attrs, content, ttFont)
		if not ttFont.recalcBBoxes:
			glyph.compact(self, 0)
Beispiel #19
0
 def _handleHeadChecksum(self):
     if self.verbose:
         debugmsg("updating head checkSumAdjustment")
     # get the value
     tables = {}
     offset = sfntDirectorySize + (sfntDirectoryEntrySize * self.numTables)
     for (index, entry, data) in sorted(self.tables.values()):
         tables[entry.tag] = dict(offset=offset, length=entry.origLength, checkSum=entry.origChecksum)
         offset += calc4BytePaddedLength(entry.origLength)
     checkSumAdjustment = calcHeadCheckSumAdjustment(self.flavor, tables)
     # set the value in the head table
     index, entry, data = self.tables["head"]
     data = data[:8] + struct.pack(">L", checkSumAdjustment) + data[12:]
     # compress the data
     newEntry, data = self._prepTable("head", data)
     # update the entry data
     assert entry.origChecksum == newEntry.origChecksum
     entry.origLength = newEntry.origLength
     entry.compLength = newEntry.compLength
     # store
     self.tables["head"] = (index, entry, data)
Beispiel #20
0
 def fromXML(self, name, attrs, content, ttFont):
     if name != "TTGlyph":
         return
     if not hasattr(self, "glyphs"):
         self.glyphs = {}
     if not hasattr(self, "glyphOrder"):
         self.glyphOrder = ttFont.getGlyphOrder()
     glyphName = attrs["name"]
     if ttFont.verbose:
         ttLib.debugmsg("unpacking glyph '%s'" % glyphName)
     glyph = Glyph()
     for attr in ['xMin', 'yMin', 'xMax', 'yMax']:
         setattr(glyph, attr, safeEval(attrs.get(attr, '0')))
     self.glyphs[glyphName] = glyph
     for element in content:
         if not isinstance(element, tuple):
             continue
         name, attrs, content = element
         glyph.fromXML(name, attrs, content, ttFont)
     if not ttFont.recalcBBoxes:
         glyph.compact(self, 0)
Beispiel #21
0
 def _prepTable(self,
                tag,
                data,
                origLength=None,
                origChecksum=None,
                compLength=None,
                entryOnly=False):
     # skip data prep
     if entryOnly:
         origLength = origLength
         origChecksum = calcTableChecksum(tag, data)
         compLength = 0
     # prep the data
     else:
         # compress
         if compLength is None:
             origData = data
             origLength = len(origData)
             origChecksum = calcTableChecksum(tag, data)
             if self.verbose:
                 debugmsg("compressing '%s' table" % tag)
             compData = zlib.compress(origData, self.compressionLevel)
             compLength = len(compData)
             if origLength <= compLength:
                 data = origData
                 compLength = origLength
             else:
                 data = compData
     # make the directory entry
     entry = WOFFDirectoryEntry()
     entry.tag = tag
     entry.offset = 0
     entry.origLength = origLength
     entry.origChecksum = origChecksum
     entry.compLength = compLength
     # return
     if entryOnly:
         return entry
     return entry, data
Beispiel #22
0
 def _handleHeadChecksum(self):
     if self.verbose:
         debugmsg("updating head checkSumAdjustment")
     # get the value
     tables = {}
     offset = sfntDirectorySize + (sfntDirectoryEntrySize * self.numTables)
     for (index, entry, data) in sorted(self.tables.values()):
         tables[entry.tag] = dict(offset=offset,
                                  length=entry.origLength,
                                  checkSum=entry.origChecksum)
         offset += calc4BytePaddedLength(entry.origLength)
     checkSumAdjustment = calcHeadCheckSumAdjustment(self.flavor, tables)
     # set the value in the head table
     index, entry, data = self.tables["head"]
     data = data[:8] + struct.pack(">L", checkSumAdjustment) + data[12:]
     # compress the data
     newEntry, data = self._prepTable("head", data)
     # update the entry data
     assert entry.origChecksum == newEntry.origChecksum
     entry.origLength = newEntry.origLength
     entry.compLength = newEntry.compLength
     # store
     self.tables["head"] = (index, entry, data)
Beispiel #23
0
    def save(self,
             file,
             compressionLevel=9,
             recompressTables=False,
             reorderTables=True,
             recalculateHeadChecksum=True):
        """
        Save a WOFF into file a file object specifified by the
        file argument.. Optionally, file can be a path and a
        new file will be created at that location.

        compressionLevel is the compression level to be
        used with zlib. This must be an int between 1 and 9.
        The default is 9, the highest compression, but slowest
        compression time.

        Set recompressTables to True if you want any already
        compressed tables to be decompressed and then recompressed
        using the level specified by compressionLevel.

        If you want the tables in the WOFF reordered following
        the suggested optimal table orderings described in the
        OTF/OFF sepecification, set reorderTables to True.
        Tables cannot be reordered if a DSIG table is in the font.

        If you change any of the SFNT data or reorder the tables,
        the head table checkSumAdjustment must be recalculated.
        If you are not changing any of the SFNT data, you can set
        recalculateHeadChecksum to False to prevent the recalculation.
        This must be set to False if the font contains a DSIG table.
        """
        # if DSIG is to be written, the table order
        # must be completely specified. otherwise the
        # DSIG may not be valid after decoding the WOFF.
        tags = self.keys()
        if "GlyphOrder" in tags:
            tags.remove("GlyphOrder")
        if "DSIG" in tags:
            if self._tableOrder is None or (set(self._tableOrder) !=
                                            set(tags)):
                raise WOFFLibError(
                    "A complete table order must be supplied when saving a font with a 'DSIG' table."
                )
            elif reorderTables:
                raise WOFFLibError(
                    "Tables can not be reordered when a 'DSIG' table is in the font. Set reorderTables to False."
                )
            elif recalculateHeadChecksum:
                raise WOFFLibError(
                    "The 'head' table checkSumAdjustment can not be recalculated when a 'DSIG' table is in the font."
                )
        # sort the tags if necessary
        if reorderTables:
            tags = sortedTagList(tags)
        # open a file if necessary
        closeStream = False
        if not hasattr(file, "write"):
            closeStream = True
            file = open(file, "wb")
        # write the table data
        if "GlyphOrder" in tags:
            tags.remove("GlyphOrder")
        numTables = len(tags)
        writer = WOFFWriter(file,
                            numTables,
                            flavor=self.flavor,
                            majorVersion=self.majorVersion,
                            minorVersion=self.minorVersion,
                            compressionLevel=compressionLevel,
                            recalculateHeadChecksum=recalculateHeadChecksum,
                            verbose=self.verbose)
        for tag in tags:
            origData = None
            origLength = None
            origChecksum = None
            compLength = None
            # table is loaded
            if self.isLoaded(tag):
                origData = self.getTableData(tag)
            # table is in reader
            elif self.reader is not None:
                if recompressTables:
                    origData = self.getTableData(tag)
                else:
                    if self.verbose:
                        debugmsg("Reading '%s' table from disk" % tag)
                    origData, origLength, origChecksum, compLength = self.reader.getCompressedTableData(
                        tag)
            # add to writer
            writer.setTable(tag,
                            origData,
                            origLength=origLength,
                            origChecksum=origChecksum,
                            compLength=compLength)
        # write the metadata
        metadata = None
        metaOrigLength = None
        metaLength = None
        if hasattr(self, "metadata"):
            declaration = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            tree = ElementTree.ElementTree(self.metadata)
            f = StringIO()
            tree.write(f, encoding="utf-8")
            metadata = f.getvalue()
            # make sure the metadata starts with the declaration
            if not metadata.startswith(declaration):
                metadata = declaration + metadata
            del f
        elif self.reader is not None:
            if recompressTables:
                metadata = self.reader.metadata
            else:
                metadata, metaOrigLength, metaLength = self.reader.getCompressedMetadata(
                )
        if metadata:
            writer.setMetadata(metadata,
                               metaOrigLength=metaOrigLength,
                               metaLength=metaLength)
        # write the private data
        privData = self.privateData
        if privData:
            writer.setPrivateData(privData)
        # close the writer
        writer.close()
        # close the file
        if closeStream:
            file.close()
Beispiel #24
0
class table__g_l_y_f(DefaultTable.DefaultTable):
    def decompile(self, data, ttFont):
        loca = ttFont['loca']
        last = int(loca[0])
        self.glyphs = {}
        self.glyphOrder = glyphOrder = ttFont.getGlyphOrder()
        for i in range(0, len(loca) - 1):
            glyphName = glyphOrder[i]
            next = int(loca[i + 1])
            glyphdata = data[last:next]
            if len(glyphdata) <> (next - last):
                raise ttLib.TTLibError, "not enough 'glyf' table data"
            glyph = Glyph(glyphdata)
            self.glyphs[glyphName] = glyph
            last = next
        # this should become a warning:
        #if len(data) > next:
        #	raise ttLib.TTLibError, "too much 'glyf' table data"

    def compile(self, ttFont):
        if not hasattr(self, "glyphOrder"):
            self.glyphOrder = ttFont.getGlyphOrder()
        import string
        locations = []
        currentLocation = 0
        dataList = []
        recalcBBoxes = ttFont.recalcBBoxes
        for glyphName in self.glyphOrder:
            glyph = self.glyphs[glyphName]
            glyphData = glyph.compile(self, recalcBBoxes)
            locations.append(currentLocation)
            currentLocation = currentLocation + len(glyphData)
            dataList.append(glyphData)
        locations.append(currentLocation)
        data = string.join(dataList, "")
        ttFont['loca'].set(locations)
        ttFont['maxp'].numGlyphs = len(self.glyphs)
        return data

    def toXML(self, writer, ttFont, progress=None):
        writer.newline()
        glyphNames = ttFont.getGlyphNames()
        writer.comment(
            "The xMin, yMin, xMax and yMax values\nwill be recalculated by the compiler."
        )
        writer.newline()
        writer.newline()
        counter = 0
        progressStep = 10
        numGlyphs = len(glyphNames)
        for glyphName in glyphNames:
            if not counter % progressStep and progress is not None:
                progress.setLabel("Dumping 'glyf' table... (%s)" % glyphName)
                progress.increment(progressStep / float(numGlyphs))
            counter = counter + 1
            glyph = self[glyphName]
            if glyph.numberOfContours:
                writer.begintag('TTGlyph', [
                    ("name", glyphName),
                    ("xMin", glyph.xMin),
                    ("yMin", glyph.yMin),
                    ("xMax", glyph.xMax),
                    ("yMax", glyph.yMax),
                ])
                writer.newline()
                glyph.toXML(writer, ttFont)
                writer.endtag('TTGlyph')
                writer.newline()
            else:
                writer.simpletag('TTGlyph', name=glyphName)
                writer.comment("contains no outline data")
                writer.newline()
            writer.newline()

    def fromXML(self, (name, attrs, content), ttFont):
        if name <> "TTGlyph":
            return
        if not hasattr(self, "glyphs"):
            self.glyphs = {}
        if not hasattr(self, "glyphOrder"):
            self.glyphOrder = ttFont.getGlyphOrder()
        glyphName = attrs["name"]
        if ttFont.verbose:
            ttLib.debugmsg("unpacking glyph '%s'" % glyphName)
        glyph = Glyph()
        for attr in ['xMin', 'yMin', 'xMax', 'yMax']:
            setattr(glyph, attr, safeEval(attrs.get(attr, '0')))
        self.glyphs[glyphName] = glyph
        for element in content:
            if type(element) <> TupleType:
                continue
            glyph.fromXML(element, ttFont)
        if not ttFont.recalcBBoxes:
            glyph.compact(self, 0)
Beispiel #25
0
    def save(self, file, compressionLevel=9, recompressTables=False, reorderTables=True, recalculateHeadChecksum=True):
        """
        Save a WOFF into file a file object specifified by the
        file argument.. Optionally, file can be a path and a
        new file will be created at that location.

        compressionLevel is the compression level to be
        used with zlib. This must be an int between 1 and 9.
        The default is 9, the highest compression, but slowest
        compression time.

        Set recompressTables to True if you want any already
        compressed tables to be decompressed and then recompressed
        using the level specified by compressionLevel.

        If you want the tables in the WOFF reordered following
        the suggested optimal table orderings described in the
        OTF/OFF sepecification, set reorderTables to True.
        Tables cannot be reordered if a DSIG table is in the font.

        If you change any of the SFNT data or reorder the tables,
        the head table checkSumAdjustment must be recalculated.
        If you are not changing any of the SFNT data, you can set
        recalculateHeadChecksum to False to prevent the recalculation.
        This must be set to False if the font contains a DSIG table.
        """
        # if DSIG is to be written, the table order
        # must be completely specified. otherwise the
        # DSIG may not be valid after decoding the WOFF.
        tags = self.keys()
        if "GlyphOrder" in tags:
            tags.remove("GlyphOrder")
        if "DSIG" in tags:
            if self._tableOrder is None or (set(self._tableOrder) != set(tags)):
                raise WOFFLibError("A complete table order must be supplied when saving a font with a 'DSIG' table.")
            elif reorderTables:
                raise WOFFLibError("Tables can not be reordered when a 'DSIG' table is in the font. Set reorderTables to False.")
            elif recalculateHeadChecksum:
                raise WOFFLibError("The 'head' table checkSumAdjustment can not be recalculated when a 'DSIG' table is in the font.")
        # sort the tags if necessary
        if reorderTables:
            tags = sortedTagList(tags)
        # open a file if necessary
        closeStream = False
        if not hasattr(file, "write"):
            closeStream = True
            file = open(file, "wb")
        # write the table data
        if "GlyphOrder" in tags:
            tags.remove("GlyphOrder")
        numTables = len(tags)
        writer = WOFFWriter(file, numTables, flavor=self.flavor,
            majorVersion=self.majorVersion, minorVersion=self.minorVersion,
            compressionLevel=compressionLevel, recalculateHeadChecksum=recalculateHeadChecksum,
            verbose=self.verbose)
        for tag in tags:
            origData = None
            origLength = None
            origChecksum = None
            compLength = None
            # table is loaded
            if self.isLoaded(tag):
                origData = self.getTableData(tag)
            # table is in reader
            elif self.reader is not None:
                if recompressTables:
                    origData = self.getTableData(tag)
                else:
                    if self.verbose:
                        debugmsg("Reading '%s' table from disk" % tag)
                    origData, origLength, origChecksum, compLength = self.reader.getCompressedTableData(tag)
            # add to writer
            writer.setTable(tag, origData, origLength=origLength, origChecksum=origChecksum, compLength=compLength)
        # write the metadata
        metadata = None
        metaOrigLength = None
        metaLength = None
        if hasattr(self, "metadata"):
            declaration = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            tree = ElementTree.ElementTree(self.metadata)
            f = StringIO()
            tree.write(f, encoding="utf-8")
            metadata = f.getvalue()
            # make sure the metadata starts with the declaration
            if not metadata.startswith(declaration):
                metadata = declaration + metadata
            del f
        elif self.reader is not None:
            if recompressTables:
                metadata = self.reader.metadata
            else:
                metadata, metaOrigLength, metaLength = self.reader.getCompressedMetadata()
        if metadata:
            writer.setMetadata(metadata, metaOrigLength=metaOrigLength, metaLength=metaLength)
        # write the private data
        privData = self.privateData
        if privData:
            writer.setPrivateData(privData)
        # close the writer
        writer.close()
        # close the file
        if closeStream:
            file.close()