Beispiel #1
0
	def compile(self, offset):
		nTracks = len(self)
		sizes = self.sizes()
		nSizes = len(sizes)

		# offset to the start of the size subtable
		offset += TRACK_DATA_FORMAT_SIZE + TRACK_TABLE_ENTRY_FORMAT_SIZE*nTracks
		trackDataHeader = sstruct.pack(
			TRACK_DATA_FORMAT,
			{'nTracks': nTracks, 'nSizes': nSizes, 'sizeTableOffset': offset})

		entryDataList = []
		perSizeDataList = []
		# offset to per-size tracking values
		offset += SIZE_VALUE_FORMAT_SIZE*nSizes
		# sort track table entries by track value
		for track, entry in sorted(self.items()):
			assert entry.nameIndex is not None
			entry.track = track
			entry.offset = offset
			entryDataList += [sstruct.pack(TRACK_TABLE_ENTRY_FORMAT, entry)]
			# sort per-size values by size
			for size, value in sorted(entry.items()):
				perSizeDataList += [struct.pack(PER_SIZE_VALUE_FORMAT, value)]
			offset += PER_SIZE_VALUE_FORMAT_SIZE*nSizes
		# sort size values
		sizeDataList = [struct.pack(SIZE_VALUE_FORMAT, fl2fi(sv, 16)) for sv in sorted(sizes)]

		data = bytesjoin([trackDataHeader] + entryDataList + sizeDataList + perSizeDataList)
		return data
Beispiel #2
0
	def compile(self, ttFont):
		self.updateFirstAndLastCharIndex(ttFont)
		panose = self.panose
		head = ttFont["head"]
		if (self.fsSelection & 1) and not (head.macStyle & 1<<1):
			log.warning("fsSelection bit 0 (italic) and "
				"head table macStyle bit 1 (italic) should match")
		if (self.fsSelection & 1<<5) and not (head.macStyle & 1):
			log.warning("fsSelection bit 5 (bold) and "
				"head table macStyle bit 0 (bold) should match")
		if (self.fsSelection & 1<<6) and (self.fsSelection & 1 + (1<<5)):
			log.warning("fsSelection bit 6 (regular) is set, "
				"bits 0 (italic) and 5 (bold) must be clear")
		if self.version < 4 and self.fsSelection & 0b1110000000:
			log.warning("fsSelection bits 7, 8 and 9 are only defined in "
				"OS/2 table version 4 and up: version %s", self.version)
		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)
		elif self.version == 5:
			d = self.__dict__.copy()
			d['usLowerOpticalPointSize'] = round(self.usLowerOpticalPointSize * 20)
			d['usUpperOpticalPointSize'] = round(self.usUpperOpticalPointSize * 20)
			data = sstruct.pack(OS2_format_5, d)
		else:
			from fontTools import ttLib
			raise ttLib.TTLibError("unknown format for OS/2 table: version %s" % self.version)
		self.panose = panose
		return data
	def compile(self, ttFont):
		self.glyphDataOffsets = ""
		self.bitmapData = ""

		glyphOrder = ttFont.getGlyphOrder()

		# first glyph starts right after the header
		currentGlyphDataOffset = sbixStrikeHeaderFormatSize + sbixGlyphDataOffsetFormatSize * (len(glyphOrder) + 1)
		for glyphName in glyphOrder:
			if glyphName in self.glyphs:
				# we have glyph data for this glyph
				current_glyph = self.glyphs[glyphName]
			else:
				# must add empty glyph data record for this glyph
				current_glyph = Glyph(glyphName=glyphName)
			current_glyph.compile(ttFont)
			current_glyph.glyphDataOffset = currentGlyphDataOffset
			self.bitmapData += current_glyph.rawdata
			currentGlyphDataOffset += len(current_glyph.rawdata)
			self.glyphDataOffsets += sstruct.pack(sbixGlyphDataOffsetFormat, current_glyph)

		# add last "offset", really the end address of the last glyph data record
		dummy = Glyph()
		dummy.glyphDataOffset = currentGlyphDataOffset
		self.glyphDataOffsets += sstruct.pack(sbixGlyphDataOffsetFormat, dummy)

		# pack header
		self.data = sstruct.pack(sbixStrikeHeaderFormat, self)
		# add offsets and image data after header
		self.data += self.glyphDataOffsets + self.bitmapData
Beispiel #4
0
 def compile(self, ttFont):
     keys = sorted(self.data.keys())
     headerSize = sstruct.calcsize(META_HEADER_FORMAT)
     dataOffset = headerSize + len(keys) * sstruct.calcsize(DATA_MAP_FORMAT)
     header = sstruct.pack(META_HEADER_FORMAT, {
             "version": 1,
             "flags": 0,
             "dataOffset": dataOffset,
             "numDataMaps": len(keys)
     })
     dataMaps = []
     dataBlocks = []
     for tag in keys:
         if tag in ["dlng", "slng"]:
             data = self.data[tag].encode("utf-8")
         else:
             data = self.data[tag]
         dataMaps.append(sstruct.pack(DATA_MAP_FORMAT, {
             "tag": tag,
             "dataOffset": dataOffset,
             "dataLength": len(data)
         }))
         dataBlocks.append(data)
         dataOffset += len(data)
     return bytesjoin([header] + dataMaps + dataBlocks)
Beispiel #5
0
 def compile(self, ttFont):
     dataList = []
     dataList.append(sstruct.pack(bigGlyphMetricsFormat, self.metrics))
     dataList.append(struct.pack(">H", len(self.componentArray)))
     for curComponent in self.componentArray:
         curComponent.glyphCode = ttFont.getGlyphID(curComponent.name)
         dataList.append(sstruct.pack(ebdtComponentFormat, curComponent))
     return bytesjoin(dataList)
Beispiel #6
0
 def compileAttributes3(self, attrs):
     if self.hasOctaboxes:
         o = attrs.octabox
         data = sstruct.pack(Glat_format_3_octabox_metrics, o)
         numsub = bin(o.subboxBitmap).count("1")
         for b in range(numsub) :
             data += sstruct.pack(Glat_format_3_subbox_entry, o.subboxes[b])
     else:
         data = ""
     return data + self.compileAttributes12(attrs, Glat_format_23_entry)
Beispiel #7
0
	def compile(self, ttFont):
		if 'glyf' in ttFont:
			if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes:
				self.recalc(ttFont)
		else:
			pass  # CFF
		self.numGlyphs = len(ttFont.getGlyphOrder())
		if self.tableVersion != 0x00005000:
			self.tableVersion = 0x00010000
		data = sstruct.pack(maxpFormat_0_5, self)
		if self.tableVersion == 0x00010000:
			data = data + sstruct.pack(maxpFormat_1_0_add, self)
		return data
Beispiel #8
0
	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
Beispiel #9
0
	def transform(self, ttFont):
		""" Return transformed 'glyf' data """
		self.numGlyphs = len(self.glyphs)
		if not hasattr(self, "glyphOrder"):
			try:
				self.glyphOrder = ttFont.getGlyphOrder()
			except:
				self.glyphOrder = None
			if self.glyphOrder is None:
				self.glyphOrder = [".notdef"]
				self.glyphOrder.extend(["glyph%.5d" % i for i in range(1, self.numGlyphs)])
		if len(self.glyphOrder) != self.numGlyphs:
			raise TTLibError(
				"incorrect glyphOrder: expected %d glyphs, found %d" %
				(len(self.glyphOrder), self.numGlyphs))

		if 'maxp' in ttFont:
			ttFont['maxp'].numGlyphs = self.numGlyphs
		self.indexFormat = ttFont['head'].indexToLocFormat

		for stream in self.subStreams:
			setattr(self, stream, b"")
		bboxBitmapSize = ((self.numGlyphs + 31) >> 5) << 2
		self.bboxBitmap = array.array('B', [0]*bboxBitmapSize)

		for glyphID in range(self.numGlyphs):
			self._encodeGlyph(glyphID)

		self.bboxStream = self.bboxBitmap.tostring() + self.bboxStream
		for stream in self.subStreams:
			setattr(self, stream + 'Size', len(getattr(self, stream)))
		self.version = 0
		data = sstruct.pack(woff2GlyfTableFormat, self)
		data += bytesjoin([getattr(self, s) for s in self.subStreams])
		return data
Beispiel #10
0
	def _calcMasterChecksum(self, directory):
		# calculate checkSumAdjustment
		tags = list(self.tables.keys())
		checksums = []
		for i in range(len(tags)):
			checksums.append(self.tables[tags[i]].checkSum)

		if self.DirectoryEntry != SFNTDirectoryEntry:
			# Create a SFNT directory for checksum calculation purposes
			self.searchRange, self.entrySelector, self.rangeShift = getSearchRange(self.numTables, 16)
			directory = sstruct.pack(sfntDirectoryFormat, self)
			tables = sorted(self.tables.items())
			for tag, entry in tables:
				sfntEntry = SFNTDirectoryEntry()
				sfntEntry.tag = entry.tag
				sfntEntry.checkSum = entry.checkSum
				sfntEntry.offset = entry.origOffset
				sfntEntry.length = entry.origLength
				directory = directory + sfntEntry.toString()

		directory_end = sfntDirectorySize + len(self.tables) * sfntDirectoryEntrySize
		assert directory_end == len(directory)

		checksums.append(calcChecksum(directory))
		checksum = sum(checksums) & 0xffffffff
		# BiboAfba!
		checksumadjustment = (0xB1B0AFBA - checksum) & 0xffffffff
		return checksumadjustment
Beispiel #11
0
    def compile(self, ttFont):
        offsetOK = 0
        self.nMetaRecs = len(self.glyphRecords)
        count = 0
        while (offsetOK != 1):
            count = count + 1
            if count > 4:
                pdb_set_trace()
            metaData = sstruct.pack(METAHeaderFormat, self)
            stringRecsOffset = len(metaData) + self.nMetaRecs * (6 + 2 * (self.metaFlags & 1))
            stringRecSize = (6 + 2 * (self.metaFlags & 1))
            for glyphRec in self.glyphRecords:
                glyphRec.offset = stringRecsOffset
                if (glyphRec.offset > 65535) and ((self.metaFlags & 1) == 0):
                    self.metaFlags = self.metaFlags + 1
                    offsetOK = -1
                    break
                metaData = metaData + glyphRec.compile(self)
                stringRecsOffset = stringRecsOffset + (glyphRec.nMetaEntry * stringRecSize)
            # this will be the String Record offset for the next GlyphRecord.
            if offsetOK == -1:
                offsetOK = 0
                continue

            # metaData now contains the header and all of the GlyphRecords. Its length should bw
            # the offset to the first StringRecord.
            stringOffset = stringRecsOffset
            for glyphRec in self.glyphRecords:
                assert (
                glyphRec.offset == len(metaData)), "Glyph record offset did not compile correctly! for rec:" + str(
                    glyphRec)
                for stringRec in glyphRec.stringRecs:
                    stringRec.offset = stringOffset
                    if (stringRec.offset > 65535) and ((self.metaFlags & 1) == 0):
                        self.metaFlags = self.metaFlags + 1
                        offsetOK = -1
                        break
                    metaData = metaData + stringRec.compile(self)
                    stringOffset = stringOffset + stringRec.stringLen
            if offsetOK == -1:
                offsetOK = 0
                continue

            if ((self.metaFlags & 1) == 1) and (stringOffset < 65536):
                self.metaFlags = self.metaFlags - 1
                continue
            else:
                offsetOK = 1


            # metaData now contains the header and all of the GlyphRecords and all of the String Records.
            # Its length should be the offset to the first string datum.
            for glyphRec in self.glyphRecords:
                for stringRec in glyphRec.stringRecs:
                    assert (
                    stringRec.offset == len(metaData)), "String offset did not compile correctly! for string:" + str(
                        stringRec.string)
                    metaData = metaData + stringRec.string

        return metaData
Beispiel #12
0
def calcHeadCheckSumAdjustment(flavor, tables):
    numTables = len(tables)
    # build the sfnt header
    searchRange, entrySelector, rangeShift = getSearchRange(numTables)
    sfntDirectoryData = dict(
        sfntVersion=flavor,
        numTables=numTables,
        searchRange=searchRange,
        entrySelector=entrySelector,
        rangeShift=rangeShift
    )
    # build the sfnt directory
    directory = sstruct.pack(sfntDirectoryFormat, sfntDirectoryData)
    for tag, entry in sorted(tables.items()):
        entry = tables[tag]
        sfntEntry = SFNTDirectoryEntry()
        sfntEntry.tag = tag
        sfntEntry.checkSum = entry["checkSum"]
        sfntEntry.offset = entry["offset"]
        sfntEntry.length = entry["length"]
        directory += sfntEntry.toString()
    # calculate the checkSumAdjustment
    checkSums = [entry["checkSum"] for entry in tables.values()]
    checkSums.append(calcChecksum(directory))
    checkSumAdjustment = sum(checkSums)
    checkSumAdjustment = (0xB1B0AFBA - checkSumAdjustment) & 0xffffffff
    # done
    return checkSumAdjustment
Beispiel #13
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 #14
0
 def close(self):
     if self.numTables != len(self.tables):
         raise WOFFLibError("wrong number of tables; expected %d, found %d" % (self.numTables, len(self.tables)))
     # first, handle the checkSumAdjustment
     if self.recalculateHeadChecksum and "head" in self.tables:
         self._handleHeadChecksum()
     # check the table directory conformance
     for tag, (index, entry, data) in sorted(self.tables.items()):
         self._checkTableConformance(entry, data)
     # write the header
     header = sstruct.pack(woffHeaderFormat, self)
     self.file.seek(0)
     self.file.write(header)
     # update the directory offsets
     offset = woffHeaderSize + (woffDirectoryEntrySize * self.numTables)
     order = self._tableOrder()
     for tag in order:
         index, entry, data = self.tables[tag]
         entry.offset = offset
         offset += calc4BytePaddedLength(entry.compLength) # ensure byte alignment
     # write the directory
     self._writeTableDirectory()
     # write the table data
     self._writeTableData()
     # write the metadata
     self._writeMetadata()
     # write the private data
     self._writePrivateData()
     # write the header
     self._writeHeader()
     # go to the beginning of the file
     self.file.seek(0)
Beispiel #15
0
	def compile(self, ttFont):
		self.numGMAPs = len(self.GMAPs)
		self.numGlyplets = len(self.glyphlets)
		GMAPoffsets = [0]*(self.numGMAPs + 1)
		glyphletOffsets = [0]*(self.numGlyplets + 1)

		dataList =[ sstruct.pack(GPKGFormat, self)]

		pos = len(dataList[0]) + (self.numGMAPs + 1)*4 + (self.numGlyplets + 1)*4
		GMAPoffsets[0] = pos
		for i in range(1, self.numGMAPs +1):
			pos += len(self.GMAPs[i-1])
			GMAPoffsets[i] = pos
		gmapArray = array.array("I", GMAPoffsets)
		if sys.byteorder != "big":
			gmapArray.byteswap()
		dataList.append(gmapArray.tostring())

		glyphletOffsets[0] = pos
		for i in range(1, self.numGlyplets +1):
			pos += len(self.glyphlets[i-1])
			glyphletOffsets[i] = pos
		glyphletArray = array.array("I", glyphletOffsets)
		if sys.byteorder != "big":
			glyphletArray.byteswap()
		dataList.append(glyphletArray.tostring())
		dataList += self.GMAPs
		dataList += self.glyphlets
		data = bytesjoin(dataList)
		return data
Beispiel #16
0
	def test_incorrect_compressed_size(self):
		data = self.file.read(woff2DirectorySize)
		header = sstruct.unpack(woff2DirectoryFormat, data)
		header['totalCompressedSize'] = 0
		data = sstruct.pack(woff2DirectoryFormat, header)
		with self.assertRaises((brotli.error, ttLib.TTLibError)):
			WOFF2Reader(BytesIO(data + self.file.read()))
Beispiel #17
0
	def compile(self, ttFont):
		axisTags = [axis.AxisTag for axis in ttFont["fvar"].table.VariationAxis]

		sharedCoords = self.compileSharedCoords_(ttFont, axisTags)
		sharedCoordIndices = dict([(sharedCoords[i], i) for i in range(len(sharedCoords))])
		sharedCoordSize = sum([len(c) for c in sharedCoords])

		compiledGlyphs = self.compileGlyphs_(ttFont, axisTags, sharedCoordIndices)
		offset = 0
		offsets = []
		for glyph in compiledGlyphs:
			offsets.append(offset)
			offset += len(glyph)
		offsets.append(offset)
		compiledOffsets, tableFormat = self.compileOffsets_(offsets)

		header = {}
		header["version"] = self.version
		header["reserved"] = self.reserved
		header["axisCount"] = len(axisTags)
		header["sharedCoordCount"] = len(sharedCoords)
		header["offsetToCoord"] = GVAR_HEADER_SIZE + len(compiledOffsets)
		header["glyphCount"] = len(compiledGlyphs)
		header["flags"] = tableFormat
		header["offsetToData"] = header["offsetToCoord"] + sharedCoordSize
		compiledHeader = sstruct.pack(GVAR_HEADER_FORMAT, header)

		result = [compiledHeader, compiledOffsets]
		result.extend(sharedCoords)
		result.extend(compiledGlyphs)
		return bytesjoin(result)
Beispiel #18
0
 def test_incorrect_file_size(self):
     data = self.file.read(woff2DirectorySize)
     header = sstruct.unpack(woff2DirectoryFormat, data)
     header["length"] -= 1
     data = sstruct.pack(woff2DirectoryFormat, header)
     with self.assertRaisesRegex(ttLib.TTLibError, "doesn't match the actual file size"):
         WOFF2Reader(BytesIO(data + self.file.read()))
Beispiel #19
0
	def compile(self, ttFont):
		axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
		sharedTuples =  tv.compileSharedTuples(
			axisTags, itertools.chain(*self.variations.values()))
		sharedTupleIndices = {coord:i for i, coord in enumerate(sharedTuples)}
		sharedTupleSize = sum([len(c) for c in sharedTuples])
		compiledGlyphs = self.compileGlyphs_(
			ttFont, axisTags, sharedTupleIndices)
		offset = 0
		offsets = []
		for glyph in compiledGlyphs:
			offsets.append(offset)
			offset += len(glyph)
		offsets.append(offset)
		compiledOffsets, tableFormat = self.compileOffsets_(offsets)

		header = {}
		header["version"] = self.version
		header["reserved"] = self.reserved
		header["axisCount"] = len(axisTags)
		header["sharedTupleCount"] = len(sharedTuples)
		header["offsetToSharedTuples"] = GVAR_HEADER_SIZE + len(compiledOffsets)
		header["glyphCount"] = len(compiledGlyphs)
		header["flags"] = tableFormat
		header["offsetToGlyphVariationData"] = header["offsetToSharedTuples"] + sharedTupleSize
		compiledHeader = sstruct.pack(GVAR_HEADER_FORMAT, header)

		result = [compiledHeader, compiledOffsets]
		result.extend(sharedTuples)
		result.extend(compiledGlyphs)
		return bytesjoin(result)
Beispiel #20
0
	def _calcMasterChecksum(self, directory):
		# calculate checkSumAdjustment
		tags = self.tables.keys()
		checksums = []
		for i in range(len(tags)):
			checksums.append(self.tables[tags[i]].checkSum)

		# TODO(behdad) I'm fairly sure the checksum for woff is not working correctly.
		# Haven't debugged.
		if self.DirectoryEntry != SFNTDirectoryEntry:
			# Create a SFNT directory for checksum calculation purposes
			self.searchRange, self.entrySelector, self.rangeShift = getSearchRange(self.numTables)
			directory = sstruct.pack(sfntDirectoryFormat, self)
			tables = self.tables.items()
			tables.sort()
			for tag, entry in tables:
				sfntEntry = SFNTDirectoryEntry()
				for item in ['tag', 'checkSum', 'offset', 'length']:
					setattr(sfntEntry, item, getattr(entry, item))
				directory = directory + sfntEntry.toString()

		directory_end = sfntDirectorySize + len(self.tables) * sfntDirectoryEntrySize
		assert directory_end == len(directory)

		checksums.append(calcChecksum(directory))
		checksum = sum(checksums) & 0xffffffff
		# BiboAfba!
		checksumadjustment = (0xB1B0AFBA - checksum) & 0xffffffff
		return checksumadjustment
Beispiel #21
0
 def compile(self, parentTable):
     data = sstruct.pack(METAStringRecordFormat, self)
     if parentTable.metaFlags == 0:
         datum = struct.pack(">H", self.offset)
     elif parentTable.metaFlags == 1:
         datum = struct.pack(">L", self.offset)
     data = data + datum
     return data
Beispiel #22
0
	def compile(self, ttFont):
		packed = sstruct.pack(DSIG_HeaderFormat, self)
		headers = [packed]
		offset = len(packed) + self.usNumSigs * sstruct.calcsize(DSIG_SignatureFormat)
		data = []
		for sigrec in self.signatureRecords:
			# first pack signature block
			sigrec.cbSignature = len(sigrec.pkcs7)
			packed = sstruct.pack(DSIG_SignatureBlockFormat, sigrec) + sigrec.pkcs7
			data.append(packed)
			# update redundant length field
			sigrec.ulLength = len(packed)
			# update running table offset
			sigrec.ulOffset = offset
			headers.append(sstruct.pack(DSIG_SignatureFormat, sigrec))
			offset += sigrec.ulLength
		return ''.join(headers+data)
Beispiel #23
0
 def compile(self, ttFont):
     self.numSilf = len(self.silfs)
     if self.version < 3.0:
         hdr = sstruct.pack(Silf_hdr_format, self)
         hdr += struct.pack(">HH", self.numSilf, 0)
     else:
         hdr = sstruct.pack(Silf_hdr_format_3, self)
     offset = len(hdr) + 4 * self.numSilf
     data = b""
     for s in self.silfs:
         hdr += struct.pack(">L", offset)
         subdata = s.compile(ttFont, self.version)
         offset += len(subdata)
         data += subdata
     if self.version >= 5.0:
         return grUtils.compress(self.scheme, hdr+data)
     return hdr+data
Beispiel #24
0
 def compile(self, axisTags, includePostScriptName):
     result = [sstruct.pack(FVAR_INSTANCE_FORMAT, self)]
     for axis in axisTags:
         fixedCoord = floatToFixed(self.coordinates[axis], 16)
         result.append(struct.pack(">l", fixedCoord))
     if includePostScriptName:
         result.append(struct.pack(">H", self.postscriptNameID))
     return bytesjoin(result)
Beispiel #25
0
	def compile(self, ttFont):
		if 	self.UV is None:
			self.UV = 0
		nameLen =  len(self.name)
		if nameLen < 32:
			self.name = self.name + "\0"*(32 - nameLen)
		data = sstruct.pack(GMAPRecordFormat1, self)
		return data
Beispiel #26
0
	def compile(self, ttFont):
		sbixData = ""
		self.numSets = len(self.bitmapSets)
		sbixHeader = sstruct.pack(sbixHeaderFormat, self)

		# calculate offset to start of first bitmap set
		setOffset = sbixHeaderFormatSize + sbixBitmapSetOffsetFormatSize * self.numSets

		for si in sorted(self.bitmapSets.keys()):
			myBitmapSet = self.bitmapSets[si]
			myBitmapSet.compile(ttFont)
			# append offset to this bitmap set to table header
			myBitmapSet.offset = setOffset
			sbixHeader += sstruct.pack(sbixBitmapSetOffsetFormat, myBitmapSet)
			setOffset += sbixBitmapSetHeaderFormatSize + len(myBitmapSet.data)
			sbixData += myBitmapSet.data

		return sbixHeader + sbixData
Beispiel #27
0
	def compile(self, ttFont):
		sbixData = ""
		self.numStrikes = len(self.strikes)
		sbixHeader = sstruct.pack(sbixHeaderFormat, self)

		# calculate offset to start of first strike
		setOffset = sbixHeaderFormatSize + sbixStrikeOffsetFormatSize * self.numStrikes

		for si in sorted(self.strikes.keys()):
			current_strike = self.strikes[si]
			current_strike.compile(ttFont)
			# append offset to this strike to table header
			current_strike.strikeOffset = setOffset
			sbixHeader += sstruct.pack(sbixStrikeOffsetFormat, current_strike)
			setOffset += len(current_strike.data)
			sbixData += current_strike.data

		return sbixHeader + sbixData
Beispiel #28
0
    def compile(self, ttFont, version=2.0):
        self.numPasses = len(self.passes)
        self.numJLevels = len(self.jLevels)
        self.numCritFeatures = len(self.critFeatures)
        numPseudo = len(self.pMap)
        data = b""
        if version >= 3.0:
            hdroffset = sstruct.calcsize(Silf_part1_format_v3)
        else:
            hdroffset = 0
        data += sstruct.pack(Silf_part1_format, self)
        for j in self.jLevels:
            data += sstruct.pack(Silf_justify_format, j)
        data += sstruct.pack(Silf_part2_format, self)
        if self.numCritFeatures:
            data += struct.pack((">%dH" % self.numCritFeaturs), *self.critFeatures)
        data += struct.pack("BB", 0, len(self.scriptTags))
        if len(self.scriptTags):
            tdata = [struct.pack("4s", x) for x in self.scriptTags]
            data += "".join(tdata)
        data += struct.pack(">H", self.lbGID)
        self.passOffset = len(data)

        data1 = grUtils.bininfo(numPseudo, 6)
        currpos = hdroffset + len(data) + 4 * (self.numPasses + 1)
        self.pseudosOffset = currpos + len(data1)
        for u, p in sorted(self.pMap.items()):
            data1 += struct.pack((">LH" if version >= 3.0 else ">HH"),
                                u, ttFont.getGlyphID(p))
        data1 += self.classes.compile(ttFont, version)
        currpos += len(data1)
        data2 = b""
        datao = b""
        for i, p in enumerate(self.passes):
            base = currpos + len(data2)
            datao += struct.pack(">L", base)
            data2 += p.compile(ttFont, base, version)
        datao += struct.pack(">L", currpos + len(data2))

        if version >= 3.0:
            data3 = sstruct.pack(Silf_part1_format_v3, self)
        else:
            data3 = b""
        return data3 + data + datao + data1 + data2
Beispiel #29
0
	def compile(self, ttFont):
		self.recordsCount = len(self.gmapRecords)
		self.fontNameLength = len(self.psFontName)
		self.recordsOffset = 4 *(((self.fontNameLength + 12)  + 3) // 4)
		data = sstruct.pack(GMAPFormat, self)
		data = data + tobytes(self.psFontName)
		data = data + b"\0" * (self.recordsOffset - len(data))
		for record in self.gmapRecords:
			data = data + record.compile(ttFont)
		return data
Beispiel #30
0
	def compile(self, ttFont):
		glyphIds = list(map(ttFont.getGlyphID, self.names))
		# Make sure all the ids are consecutive. This is required by Format 2.
		assert glyphIds == list(range(self.firstGlyphIndex, self.lastGlyphIndex+1)), "Format 2 ids must be consecutive."
		self.imageDataOffset = min(zip(*self.locations)[0])

		dataList = [EblcIndexSubTable.compile(self, ttFont)]
		dataList.append(struct.pack(">L", self.imageSize))
		dataList.append(sstruct.pack(bigGlyphMetricsFormat, self.metrics))
		return bytesjoin(dataList)
Beispiel #31
0
def packSFNT(header, directory, tableData, flavor="cff",
    calcCheckSum=True, applyPadding=True, sortDirectory=True,
    searchRange=None, entrySelector=None, rangeShift=None):
    # update the checkSum
    if calcCheckSum:
        if flavor == "cff":
            f = "OTTO"
        else:
            f = "\000\001\000\000"
        calcHeadCheckSumAdjustmentSFNT(directory, tableData, flavor=f)
    # update the header
    cSearchRange, cEntrySelector, cRangeShift = getSearchRange(len(directory), 16)
    if searchRange is None:
        searchRange = cSearchRange
    if entrySelector is None:
        entrySelector = cEntrySelector
    if rangeShift is None:
        rangeShift = cRangeShift
    if flavor == "cff":
        header["sfntVersion"] = "OTTO"
    else:
        header["sfntVersion"] = "\000\001\000\000"
    header["searchRange"] = searchRange
    header["entrySelector"] = entrySelector
    header["rangeShift"] = rangeShift
    # version and num tables should already be set
    sfntData = sstruct.pack(sfntDirectoryFormat, header)
    # compile the directory
    sfntDirectoryEntries = {}
    entryOrder = []
    for entry in directory:
        sfntEntry = SFNTDirectoryEntry()
        sfntEntry.tag = entry["tag"]
        sfntEntry.checkSum = entry["checksum"]
        sfntEntry.offset = entry["offset"]
        sfntEntry.length = entry["length"]
        sfntDirectoryEntries[entry["tag"]] = sfntEntry
        entryOrder.append(entry["tag"])
    if sortDirectory:
        entryOrder = sorted(entryOrder)
    for tag in entryOrder:
        entry = sfntDirectoryEntries[tag]
        sfntData += entry.toString()
    # compile the data
    directory = [(entry["offset"], entry["tag"]) for entry in directory]
    for o, tag in sorted(directory):
        data = tableData[tag]
        if applyPadding:
            data = padData(data)
        sfntData += data
    # done
    return sfntData
Beispiel #32
0
 def compile(self, ttFont):
     packed = sstruct.pack(DSIG_HeaderFormat, self)
     headers = [packed]
     offset = len(
         packed) + self.usNumSigs * sstruct.calcsize(DSIG_SignatureFormat)
     data = []
     for sigrec in self.signatureRecords:
         # first pack signature block
         sigrec.cbSignature = len(sigrec.pkcs7)
         packed = sstruct.pack(DSIG_SignatureBlockFormat,
                               sigrec) + sigrec.pkcs7
         data.append(packed)
         # update redundant length field
         sigrec.ulLength = len(packed)
         # update running table offset
         sigrec.ulOffset = offset
         headers.append(sstruct.pack(DSIG_SignatureFormat, sigrec))
         offset += sigrec.ulLength
     if offset % 2:
         # Pad to even bytes
         data.append(b'\0')
     return bytesjoin(headers + data)
    def compile(self, ttFont):
        self.bitmapOffsets = ""
        self.bitmapData = ""

        glyphOrder = ttFont.getGlyphOrder()

        # first bitmap starts right after the header
        bitmapOffset = sbixBitmapSetHeaderFormatSize + sbixBitmapOffsetEntryFormatSize * (
            len(glyphOrder) + 1)
        for glyphName in glyphOrder:
            if glyphName in self.bitmaps:
                # we have a bitmap for this glyph
                myBitmap = self.bitmaps[glyphName]
            else:
                # must add empty bitmap for this glyph
                myBitmap = Bitmap(glyphName=glyphName)
            myBitmap.compile(ttFont)
            myBitmap.ulOffset = bitmapOffset
            self.bitmapData += myBitmap.rawdata
            bitmapOffset += len(myBitmap.rawdata)
            self.bitmapOffsets += sstruct.pack(sbixBitmapOffsetEntryFormat,
                                               myBitmap)

        # add last "offset", really the end address of the last bitmap
        dummy = Bitmap()
        dummy.ulOffset = bitmapOffset
        self.bitmapOffsets += sstruct.pack(sbixBitmapOffsetEntryFormat, dummy)

        # bitmap sets are padded to 4 byte boundaries
        dataLength = len(self.bitmapOffsets) + len(self.bitmapData)
        if dataLength % 4 != 0:
            padding = 4 - (dataLength % 4)
        else:
            padding = 0

        # pack header
        self.data = sstruct.pack(sbixBitmapSetHeaderFormat, self)
        # add offset, image data and padding after header
        self.data += self.bitmapOffsets + self.bitmapData + "\0" * padding
Beispiel #34
0
 def compile(self, ttFont):
     data = sstruct.pack(postFormat, self)
     if self.formatType == 1.0:
         pass  # we're done
     elif self.formatType == 2.0:
         data = data + self.encode_format_2_0(ttFont)
     elif self.formatType == 3.0:
         pass  # we're done
     else:
         # supported format
         raise ttLib.TTLibError("'post' table format %f not supported" %
                                self.formatType)
     return data
 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)
     elif self.version == 5:
         d = self.__dict__.copy()
         d['usLowerOpticalPointSize'] = int(
             round(self.usLowerOpticalPointSize * 20))
         d['usUpperOpticalPointSize'] = int(
             round(self.usUpperOpticalPointSize * 20))
         data = sstruct.pack(OS2_format_5, d)
     else:
         from fontTools import ttLib
         raise ttLib.TTLibError(
             "unknown format for OS/2 table: version %s" % self.version)
     self.panose = panose
     return data
 def compile(self, ttFont):
     ldat = b""
     fdat = b""
     offset = len(self.langs)
     for c, inf in sorted(self.langs.items()):
         ldat += struct.pack(">4sHH", c.encode('utf8'), len(inf),
                             8 * offset + 20)
         for fid, val in inf:
             fdat += struct.pack(">LHH", fid, val, 0)
         offset += len(inf)
     ldat += struct.pack(">LHH", 0x80808080, 0, 8 * offset + 20)
     return sstruct.pack(Sill_hdr, self) + grUtils.bininfo(len(self.langs)) + \
             ldat + fdat
Beispiel #37
0
    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:
            self.rawdata = ""
        else:
            self.rawdata = sstruct.pack(sbixGlyphHeaderFormat,
                                        self) + self.imageData
Beispiel #38
0
    def compile(self, ttFont):
        if not (self.version == 0 or self.version == 1):
            from fontTools import ttLib

            raise ttLib.TTLibError(
                "unknown format for VDMX table: version %s" % self.version)
        data = sstruct.pack(VDMX_HeaderFmt, self)
        for ratio in self.ratRanges:
            data += sstruct.pack(VDMX_RatRangeFmt, ratio)
        # recalculate offsets to VDMX groups
        for offset in self._getOffsets():
            data += struct.pack('>H', offset)
        for group in self.groups:
            recs = len(group)
            startsz = min(group.keys())
            endsz = max(group.keys())
            gHeader = {'recs': recs, 'startsz': startsz, 'endsz': endsz}
            data += sstruct.pack(VDMX_GroupFmt, gHeader)
            for yPelHeight, (yMax, yMin) in group.items():
                vTable = {'yPelHeight': yPelHeight, 'yMax': yMax, 'yMin': yMin}
                data += sstruct.pack(VDMX_vTableFmt, vTable)
        return data
Beispiel #39
0
 def compile(self, glyfTable, recalcBBoxes=True):
     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()
     return data
Beispiel #40
0
 def compile(self, ttFont):
     d = self.__dict__.copy()
     d["nameLength"] = bytechr(len(self.baseGlyphName))
     d["uniqueName"] = self.compilecompileUniqueName(self.uniqueName, 28)
     METAMD5List = eval(self.METAMD5)
     d["METAMD5"] = b""
     for val in METAMD5List:
         d["METAMD5"] += bytechr(val)
     assert (len(d["METAMD5"]) == 16
             ), "Failed to pack 16 byte MD5 hash in SING table"
     data = sstruct.pack(SINGFormat, d)
     data = data + tobytes(self.baseGlyphName)
     return data
Beispiel #41
0
 def compile(self, ttFont):
     tupleVariationCount, tuples, data = compileTupleVariationStore(
         variations=[v for v in self.variations if v.hasImpact()],
         pointCount=len(ttFont["cvt "].values),
         axisTags=[axis.axisTag for axis in ttFont["fvar"].axes],
         sharedTupleIndices={})
     header = {
         "majorVersion": self.majorVersion,
         "minorVersion": self.minorVersion,
         "tupleVariationCount": tupleVariationCount,
         "offsetToData": CVAR_HEADER_SIZE + len(tuples),
     }
     return bytesjoin(
         [sstruct.pack(CVAR_HEADER_FORMAT, header), tuples, data])
Beispiel #42
0
 def compile(self, ttFont, base, version=2.0):
     # build it all up backwards
     oActions = reduce(lambda a, x: (a[0] + len(x), a[1] + [a[0]]),
                       self.actions + [b""], (0, []))[1]
     oConstraints = reduce(lambda a, x: (a[0] + len(x), a[1] + [a[0]]),
                           self.ruleConstraints + [b""], (1, []))[1]
     constraintCode = b"\000" + b"".join(self.ruleConstraints)
     transes = []
     for t in self.stateTrans:
         if sys.byteorder != "big": t.byteswap()
         transes.append(t.tobytes())
         if sys.byteorder != "big": t.byteswap()
     if not len(transes):
         self.startStates = [0]
     oRuleMap = reduce(lambda a, x: (a[0] + len(x), a[1] + [a[0]]),
                       self.rules + [[]], (0, []))[1]
     passRanges = []
     gidcolmap = dict([(ttFont.getGlyphID(x[0]), x[1])
                       for x in self.colMap.items()])
     for e in grUtils.entries(gidcolmap, sameval=True):
         if e[1]:
             passRanges.append((e[0], e[0] + e[1] - 1, e[2][0]))
     self.numRules = len(self.actions)
     self.fsmOffset = (sstruct.calcsize(Silf_pass_format) + 8 +
                       len(passRanges) * 6 + len(oRuleMap) * 2 +
                       2 * oRuleMap[-1] + 2 + 2 * len(self.startStates) +
                       3 * self.numRules + 3 + 4 * self.numRules + 4)
     self.pcCode = self.fsmOffset + 2 * self.numTransitional * self.numColumns + 1 + base
     self.rcCode = self.pcCode + len(self.passConstraints)
     self.aCode = self.rcCode + len(constraintCode)
     self.oDebug = 0
     # now generate output
     data = sstruct.pack(Silf_pass_format, self)
     data += grUtils.bininfo(len(passRanges), 6)
     data += b"".join(struct.pack(">3H", *p) for p in passRanges)
     data += struct.pack((">%dH" % len(oRuleMap)), *oRuleMap)
     flatrules = reduce(lambda a, x: a + x, self.rules, [])
     data += struct.pack((">%dH" % oRuleMap[-1]), *flatrules)
     data += struct.pack("BB", self.minRulePreContext,
                         self.maxRulePreContext)
     data += struct.pack((">%dH" % len(self.startStates)),
                         *self.startStates)
     data += struct.pack((">%dH" % self.numRules), *self.ruleSortKeys)
     data += struct.pack(("%dB" % self.numRules), *self.rulePreContexts)
     data += struct.pack(">BH", self.collisionThreshold,
                         len(self.passConstraints))
     data += struct.pack((">%dH" % (self.numRules + 1)), *oConstraints)
     data += struct.pack((">%dH" % (self.numRules + 1)), *oActions)
     return data + b"".join(transes) + struct.pack("B", 0) + \
             self.passConstraints + constraintCode + b"".join(self.actions)
	def compile(self, ttFont):

		dataList = []
		dataList.append(sstruct.pack(ebdtTableVersionFormat, self))
		dataSize = len(dataList[0])

		# Keep a dict of glyphs that have been seen so they aren't remade.
		# This dict maps the id of the BitmapGlyph to the interval
		# in the data.
		glyphDict = {}

		# Go through the bitmap glyph data. Just in case the data for a glyph
		# changed the size metrics should be recalculated. There are a variety
		# of formats and they get stored in the EBLC table. That is why
		# recalculation is defered to the EblcIndexSubTable class and just
		# pass what is known about bitmap glyphs from this particular table.
		locator = ttFont[self.__class__.locatorName]
		for curStrike, curGlyphDict in zip(locator.strikes, self.strikeData):
			for curIndexSubTable in curStrike.indexSubTables:
				dataLocations = []
				for curName in curIndexSubTable.names:
					# Handle the data placement based on seeing the glyph or not.
					# Just save a reference to the location if the glyph has already
					# been saved in compile. This code assumes that glyphs will only
					# be referenced multiple times from indexFormat5. By luck the
					# code may still work when referencing poorly ordered fonts with
					# duplicate references. If there is a font that is unlucky the
					# respective compile methods for the indexSubTables will fail
					# their assertions. All fonts seem to follow this assumption.
					# More complicated packing may be needed if a counter-font exists.
					glyph = curGlyphDict[curName]
					objectId = id(glyph)
					if objectId not in glyphDict:
						data = glyph.compile(ttFont)
						data = curIndexSubTable.padBitmapData(data)
						startByte = dataSize
						dataSize += len(data)
						endByte = dataSize
						dataList.append(data)
						dataLoc = (startByte, endByte)
						glyphDict[objectId] = dataLoc
					else:
						dataLoc = glyphDict[objectId]
					dataLocations.append(dataLoc)
				# Just use the new data locations in the indexSubTable.
				# The respective compile implementations will take care
				# of any of the problems in the convertion that may arise.
				curIndexSubTable.locations = dataLocations

		return bytesjoin(dataList)
Beispiel #44
0
 def compile(self, ttFont):
     self.updateFirstAndLastCharIndex(ttFont)
     panose = self.panose
     head = ttFont["head"]
     if (self.fsSelection & 1) and not (head.macStyle & 1 << 1):
         log.warning("fsSelection bit 0 (italic) and "
                     "head table macStyle bit 1 (italic) should match")
     if (self.fsSelection & 1 << 5) and not (head.macStyle & 1):
         log.warning("fsSelection bit 5 (bold) and "
                     "head table macStyle bit 0 (bold) should match")
     if (self.fsSelection & 1 << 6) and (self.fsSelection & 1 + (1 << 5)):
         log.warning("fsSelection bit 6 (regular) is set, "
                     "bits 0 (italic) and 5 (bold) must be clear")
     if self.version < 4 and self.fsSelection & 0b1110000000:
         log.warning(
             "fsSelection bits 7, 8 and 9 are only defined in "
             "OS/2 table version 4 and up: version %s", self.version)
     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)
     elif self.version == 5:
         d = self.__dict__.copy()
         d['usLowerOpticalPointSize'] = round(self.usLowerOpticalPointSize *
                                              20)
         d['usUpperOpticalPointSize'] = round(self.usUpperOpticalPointSize *
                                              20)
         data = sstruct.pack(OS2_format_5, d)
     else:
         from fontTools import ttLib
         raise ttLib.TTLibError(
             "unknown format for OS/2 table: version %s" % self.version)
     self.panose = panose
     return data
Beispiel #45
0
 def compile(self, ttFont):
     keys = sorted(self.data.keys())
     headerSize = sstruct.calcsize(META_HEADER_FORMAT)
     dataOffset = headerSize + len(keys) * sstruct.calcsize(DATA_MAP_FORMAT)
     header = sstruct.pack(
         META_HEADER_FORMAT, {
             "version": 1,
             "flags": 0,
             "dataOffset": dataOffset,
             "numDataMaps": len(keys)
         })
     dataMaps = []
     dataBlocks = []
     for tag in keys:
         data = self.data[tag]
         dataMaps.append(
             sstruct.pack(DATA_MAP_FORMAT, {
                 "tag": tag,
                 "dataOffset": dataOffset,
                 "dataLength": len(data)
             }))
         dataBlocks.append(data)
         dataOffset += len(data)
     return bytesjoin([header] + dataMaps + dataBlocks)
Beispiel #46
0
    def compile(self, offset):
        nTracks = len(self)
        sizes = self.sizes()
        nSizes = len(sizes)

        # offset to the start of the size subtable
        offset += TRACK_DATA_FORMAT_SIZE + TRACK_TABLE_ENTRY_FORMAT_SIZE * nTracks
        trackDataHeader = sstruct.pack(TRACK_DATA_FORMAT, {
            'nTracks': nTracks,
            'nSizes': nSizes,
            'sizeTableOffset': offset
        })

        entryDataList = []
        perSizeDataList = []
        # offset to per-size tracking values
        offset += SIZE_VALUE_FORMAT_SIZE * nSizes
        # sort track table entries by track value
        for track, entry in sorted(self.items()):
            assert entry.nameIndex is not None
            entry.track = track
            entry.offset = offset
            entryDataList += [sstruct.pack(TRACK_TABLE_ENTRY_FORMAT, entry)]
            # sort per-size values by size
            for size, value in sorted(entry.items()):
                perSizeDataList += [struct.pack(PER_SIZE_VALUE_FORMAT, value)]
            offset += PER_SIZE_VALUE_FORMAT_SIZE * nSizes
        # sort size values
        sizeDataList = [
            struct.pack(SIZE_VALUE_FORMAT, fl2fi(sv, 16))
            for sv in sorted(sizes)
        ]

        data = bytesjoin([trackDataHeader] + entryDataList + sizeDataList +
                         perSizeDataList)
        return data
Beispiel #47
0
 def compile(self, ttFont):
     data = sstruct.pack(
         Gloc_header,
         dict(version=1.0,
              flags=(bool(self.attribIds) << 1) +
              (self.locations.typecode == 'I'),
              numAttribs=self.numAttribs))
     if sys.byteorder != "big": self.locations.byteswap()
     data += self.locations.tostring()
     if sys.byteorder != "big": self.locations.byteswap()
     if self.attribIds:
         if sys.byteorder != "big": self.attribIds.byteswap()
         data += self.attribIds.tostring()
         if sys.byteorder != "big": self.attribIds.byteswap()
     return data
Beispiel #48
0
    def compile(self, ttFont):
        data = sstruct.pack(Glat_format_0, self)
        if self.version <= 1.9:
            encoder = partial(self.compileAttributes12,
                              fmt=Glat_format_1_entry)
        elif self.version <= 2.9:
            encoder = partial(self.compileAttributes12,
                              fmt=Glat_format_1_entry)
        elif self.version >= 3.0:
            self.compression = (self.scheme << 27) + (1 if self.hasOctaboxes
                                                      else 0)
            data = sstruct.pack(Glat_format_3, self)
            encoder = self.compileAttributes3

        glocs = []
        for n in range(len(self.attributes)):
            glocs.append(len(data))
            data += encoder(self.attributes[ttFont.getGlyphName(n)])
        glocs.append(len(data))
        ttFont['Gloc'].set(glocs)

        if self.version >= 3.0:
            data = grUtils.compress(self.scheme, data)
        return data
Beispiel #49
0
	def test_decompile_badOffset(self):
                # https://github.com/fonttools/fonttools/issues/525
		table = table__n_a_m_e()
		badRecord = {
			"platformID": 1,
			"platEncID": 3,
			"langID": 7,
			"nameID": 1,
			"length": 3,
			"offset": 8765  # out of range
		}
		data = bytesjoin([
                        struct.pack(tostr(">HHH"), 1, 1, 6 + nameRecordSize),
                        sstruct.pack(nameRecordFormat, badRecord)])
		table.decompile(data, ttFont=None)
		self.assertEqual(table.names, [])
 def compile(self, ttFont):
     self.version = 0
     numGlyphs = ttFont['maxp'].numGlyphs
     glyphOrder = ttFont.getGlyphOrder()
     self.recordSize = 4 * ((2 + numGlyphs + 3) // 4)
     pad = (self.recordSize - 2 - numGlyphs) * b"\0"
     self.numRecords = len(self.hdmx)
     data = sstruct.pack(hdmxHeaderFormat, self)
     items = sorted(self.hdmx.items())
     for ppem, widths in items:
         data = data + bytechr(ppem) + bytechr(max(widths.values()))
         for glyphID in range(len(glyphOrder)):
             width = widths[glyphOrder[glyphID]]
             data = data + bytechr(width)
         data = data + pad
     return data
 def compile(self, ttFont):
     axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
     header = {
         "majorVersion": 1,
         "minorVersion": 0,
         "reserved": 0,
         "axisCount": len(axisTags)
     }
     result = [sstruct.pack(AVAR_HEADER_FORMAT, header)]
     for axis in axisTags:
         mappings = sorted(self.segments[axis].items())
         result.append(struct.pack(">H", len(mappings)))
         for key, value in mappings:
             fixedKey = fl2fi(key, 14)
             fixedValue = fl2fi(value, 14)
             result.append(struct.pack(">hh", fixedKey, fixedValue))
     return bytesjoin(result)
Beispiel #52
0
def calcHeadCheckSumAdjustmentSFNT(directory, tableData, flavor=None):
    """
    Set the checkSumAdjustment in the head table data.
    Grumble.
    """
    # if the flavor is None, guess.
    if flavor is None:
        flavor = "\000\001\000\000"
        for entry in directory:
            if entry["tag"] == "CFF ":
                flavor = "OTTO"
                break
    assert flavor in ("OTTO", "\000\001\000\000")
    # make the sfnt header
    searchRange, entrySelector, rangeShift = getSearchRange(len(directory), 16)
    sfntHeaderData = dict(
        sfntVersion=flavor,
        numTables=len(directory),
        searchRange=searchRange,
        entrySelector=entrySelector,
        rangeShift=rangeShift
    )
    sfntData = sstruct.pack(sfntDirectoryFormat, sfntHeaderData)
    # make a SFNT table directory
    directory = [(entry["tag"], entry) for entry in directory]
    for tag, entry in sorted(directory):
        sfntEntry = SFNTDirectoryEntry()
        sfntEntry.tag = entry["tag"]
        sfntEntry.checkSum = entry["checksum"]
        sfntEntry.offset = entry["offset"]
        sfntEntry.length = entry["length"]
        sfntData += sfntEntry.toString()
    # calculate the checksum
    sfntDataChecksum = calcChecksum(sfntData)
    # gather all of the checksums
    checksums = [entry["checksum"] for o, entry in directory]
    checksums.append(sfntDataChecksum)
    # calculate the checksum
    checkSumAdjustment = sum(checksums)
    checkSumAdjustment = (0xB1B0AFBA - checkSumAdjustment) & 0xffffffff
    # set the value in the head table
    headTableData = tableData["head"]
    newHeadTableData = headTableData[:8]
    newHeadTableData += struct.pack(">L", checkSumAdjustment)
    newHeadTableData += headTableData[12:]
    tableData["head"] = newHeadTableData
Beispiel #53
0
	def compile(self, glyfTable, recalcBBoxes=True):
		if hasattr(self, "data"):
			if recalcBBoxes:
				# must unpack glyph in order to recalculate bounding box
				self.expand(glyfTable)
			else:
				return self.data
		if self.numberOfContours == 0:
			return b''
		if recalcBBoxes:
			self.recalcBounds(glyfTable)
		data = sstruct.pack(glyphHeaderFormat, self)
		if self.isComposite():
			data = data + self.compileComponents(glyfTable)
		else:
			data = data + self.compileCoordinates()
		return data
Beispiel #54
0
	def compile(self, glyfTable, recalcBBoxes=True):
		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 + b"\0" * nPadBytes
		return data
def makeGlyfBBox2(bbox):
    font = getTTFont(sfntTTFSourcePath, recalcBBoxes=False)
    glyf = font["glyf"]
    hmtx = font["hmtx"]

    name = "bbox1"
    glyph = getTableModule('glyf').Glyph()
    glyph.numberOfContours = 0
    glyph.xMin = glyph.xMax = glyph.yMin = glyph.yMax = bbox
    glyph.data = sstruct.pack(getTableModule('glyf').glyphHeaderFormat, glyph)
    glyf.glyphs[name] = glyph
    hmtx.metrics[name] = (0, 0)
    glyf.glyphOrder.append(name)

    tableData = getSFNTData(font)[0]
    font.close()
    del font

    header, directory, tableData = defaultSFNTTestData(tableData=tableData, flavor="TTF")
    data = packSFNT(header, directory, tableData, flavor="TTF")
    return data
Beispiel #56
0
 def compile(self, ttFont):
     instanceSize = sstruct.calcsize(FVAR_INSTANCE_FORMAT) + (len(self.axes) * 4)
     includePostScriptNames = any(instance.postscriptNameID != 0xFFFF
                                  for instance in self.instances)
     if includePostScriptNames:
         instanceSize += 2
     header = {
         "version": 0x00010000,
         "offsetToData": sstruct.calcsize(FVAR_HEADER_FORMAT),
         "countSizePairs": 2,
         "axisCount": len(self.axes),
         "axisSize": sstruct.calcsize(FVAR_AXIS_FORMAT),
         "instanceCount": len(self.instances),
         "instanceSize": instanceSize,
     }
     result = [sstruct.pack(FVAR_HEADER_FORMAT, header)]
     result.extend([axis.compile() for axis in self.axes])
     axisTags = [axis.axisTag for axis in self.axes]
     for instance in self.instances:
         result.append(instance.compile(axisTags, includePostScriptNames))
     return bytesjoin(result)
Beispiel #57
0
 def compile(self, ttFont, version=2.0):
     data = b""
     oClasses = []
     if version >= 4.0:
         offset = 8 + 4 * (len(self.linear) + len(self.nonLinear))
     else:
         offset = 6 + 2 * (len(self.linear) + len(self.nonLinear))
     for l in self.linear:
         oClasses.append(len(data) + offset)
         gs = [ttFont.getGlyphID(x) for x in l]
         data += struct.pack((">%dH" % len(l)), *gs)
     for l in self.nonLinear:
         oClasses.append(len(data) + offset)
         gs = [(ttFont.getGlyphID(x[0]), x[1]) for x in l.items()]
         data += grUtils.bininfo(len(gs))
         data += b"".join([struct.pack(">HH", *x) for x in sorted(gs)])
     oClasses.append(len(data) + offset)
     self.numClass = len(oClasses) - 1
     self.numLinear = len(self.linear)
     return sstruct.pack(Silf_classmap_format, self) + \
            struct.pack(((">%dL" if version >= 4.0 else ">%dH") % len(oClasses)),
                         *oClasses) + data
Beispiel #58
0
	def compile(self, ttFont):
		dataList = []
		offset = TRAK_HEADER_FORMAT_SIZE
		for direction in ('horiz', 'vert'):
			trackData = getattr(self, direction + 'Data', TrackData())
			offsetName = direction + 'Offset'
			# set offset to 0 if None or empty
			if not trackData:
				setattr(self, offsetName, 0)
				continue
			# TrackData table format must be longword aligned
			alignedOffset = (offset + 3) & ~3
			padding, offset = b"\x00"*(alignedOffset - offset), alignedOffset
			setattr(self, offsetName, offset)

			data = trackData.compile(offset)
			offset += len(data)
			dataList.append(padding + data)

		self.reserved = 0
		tableData = bytesjoin([sstruct.pack(TRAK_HEADER_FORMAT, self)] + dataList)
		return tableData
Beispiel #59
0
	def transform(self, ttFont):
		""" Return transformed 'glyf' data """
		self.numGlyphs = len(self.glyphs)
		assert len(self.glyphOrder) == self.numGlyphs
		if 'maxp' in ttFont:
			ttFont['maxp'].numGlyphs = self.numGlyphs
		self.indexFormat = ttFont['head'].indexToLocFormat

		for stream in self.subStreams:
			setattr(self, stream, b"")
		bboxBitmapSize = ((self.numGlyphs + 31) >> 5) << 2
		self.bboxBitmap = array.array('B', [0]*bboxBitmapSize)

		for glyphID in range(self.numGlyphs):
			self._encodeGlyph(glyphID)

		self.bboxStream = self.bboxBitmap.tobytes() + self.bboxStream
		for stream in self.subStreams:
			setattr(self, stream + 'Size', len(getattr(self, stream)))
		self.version = 0
		data = sstruct.pack(woff2GlyfTableFormat, self)
		data += bytesjoin([getattr(self, s) for s in self.subStreams])
		return data
 def compile(self, ttFont):
     if not hasattr(self, "names"):
         # only happens when there are NO name table entries read
         # from the TTX file
         self.names = []
     self.names.sort(
     )  # sort according to the spec; see NameRecord.__lt__()
     stringData = b""
     format = 0
     n = len(self.names)
     stringOffset = 6 + n * sstruct.calcsize(nameRecordFormat)
     data = struct.pack(">HHH", format, n, stringOffset)
     lastoffset = 0
     done = {}  # remember the data so we can reuse the "pointers"
     for name in self.names:
         if name.string in done:
             name.offset, name.length = done[name.string]
         else:
             name.offset, name.length = done[name.string] = len(
                 stringData), len(name.string)
             stringData = stringData + name.string
         data = data + sstruct.pack(nameRecordFormat, name)
     return data + stringData