Esempio n. 1
0
 def makeFont(self, variations):
     glyphs = [".notdef", "space", "I"]
     Axis = getTableModule("fvar").Axis
     Glyph = getTableModule("glyf").Glyph
     glyf, fvar, gvar = newTable("glyf"), newTable("fvar"), newTable("gvar")
     font = FakeFont(glyphs)
     font.tables = {"glyf": glyf, "gvar": gvar, "fvar": fvar}
     glyf.glyphs = {glyph: Glyph() for glyph in glyphs}
     glyf.glyphs["I"].coordinates = [(10, 10), (10, 20), (20, 20), (20, 10)]
     fvar.axes = [Axis(), Axis()]
     fvar.axes[0].axisTag, fvar.axes[1].axisTag = "wght", "wdth"
     gvar.variations = variations
     return font, gvar
Esempio n. 2
0
	def makeFont(self, variations):
		glyphs=[".notdef", "space", "I"]
		Axis = getTableModule("fvar").Axis
		Glyph = getTableModule("glyf").Glyph
		glyf, fvar, gvar = newTable("glyf"), newTable("fvar"), newTable("gvar")
		font = FakeFont(glyphs)
		font.tables = {"glyf": glyf, "gvar": gvar, "fvar": fvar}
		glyf.glyphs = {glyph: Glyph() for glyph in glyphs}
		glyf.glyphs["I"].coordinates = [(10, 10), (10, 20), (20, 20), (20, 10)]
		fvar.axes = [Axis(), Axis()]
		fvar.axes[0].axisTag, fvar.axes[1].axisTag = "wght", "wdth"
		gvar.variations = variations
		return font, gvar
Esempio n. 3
0
def merge(self, m, tables):
	# TODO Handle format=14.
	# Only merges 4/3/1 and 12/3/10 subtables, ignores all other subtables
	# If there is a format 12 table for the same font, ignore the format 4 table
	cmapTables = []
	for fontIdx,table in enumerate(tables):
		format4 = None
		format12 = None
		for subtable in table.tables:
			properties = (subtable.format, subtable.platformID, subtable.platEncID)
			if properties == (4,3,1):
				format4 = subtable
			elif properties == (12,3,10):
				format12 = subtable
		if format12 is not None:
			cmapTables.append((format12, fontIdx))
		elif format4 is not None:
			cmapTables.append((format4, fontIdx))

	# Build a unicode mapping, then decide which format is needed to store it.
	cmap = {}
	for table,fontIdx in cmapTables:
		# handle duplicates
		for uni,gid in table.cmap.items():
			oldgid = cmap.get(uni, None)
			if oldgid is None:
				cmap[uni] = gid
			elif oldgid != gid:
				# Char previously mapped to oldgid, now to gid.
				# Record, to fix up in GSUB 'locl' later.
				if m.duplicateGlyphsPerFont[fontIdx].get(oldgid, gid) == gid:
					m.duplicateGlyphsPerFont[fontIdx][oldgid] = gid
				else:
					# char previously mapped to oldgid but already remapped to a different gid,
					# save new gid as an alternate
					# TODO: try harder to save these
					log.warn("Dropped mapping from codepoint %#06X to glyphId '%s'", uni, gid)

	cmapBmpOnly = {uni: gid for uni,gid in cmap.items() if uni <= 0xFFFF}
	self.tables = []
	module = ttLib.getTableModule('cmap')
	if len(cmapBmpOnly) != len(cmap):
		# format-12 required.
		cmapTable = module.cmap_classes[12](12)
		cmapTable.platformID = 3
		cmapTable.platEncID = 10
		cmapTable.language = 0
		cmapTable.cmap = cmap
		self.tables.append(cmapTable)
	# always create format-4
	cmapTable = module.cmap_classes[4](4)
	cmapTable.platformID = 3
	cmapTable.platEncID = 1
	cmapTable.language = 0
	cmapTable.cmap = cmapBmpOnly
	# ordered by platform then encoding
	self.tables.insert(0, cmapTable)
	self.tableVersion = 0
	self.numSubTables = len(self.tables)
	return self
Esempio n. 4
0
    def _add_object(self, key, value):
        # Make sure item is decompiled
        try:
            value["asdf"]
        except (AttributeError, KeyError, TypeError, ttLib.TTLibError):
            pass
        if isinstance(value, ttLib.getTableModule('glyf').Glyph):
            # Glyph type needs explicit expanding to be useful
            value.expand(self._font['glyf'])
        if isinstance(value, misc.psCharStrings.T2CharString):
            try:
                value.decompile()
            except TypeError:  # Subroutines can't be decompiled
                pass
        if isinstance(value, cffLib.BaseDict):
            for k in value.rawDict.keys():
                getattr(value, k)
        if isinstance(value, cffLib.Index):
            # Load all items
            for i in range(len(value)):
                value[i]
            # Discard offsets as should not be needed anymore
            if hasattr(value, 'offsets'):
                del value.offsets

        self._value_str = value.__class__.__name__
        if isinstance(value, ttLib.tables.DefaultTable.DefaultTable):
            self._value_str += ' (%d Bytes)' % self._font.reader.tables[key].length
        self._items = sorted(value.__dict__.items())
        self._filter_items()
	def _add_object(self, key, value):
		# Make sure item is decompiled
		try:
			value["asdf"]
		except (AttributeError, KeyError, TypeError, ttLib.TTLibError):
			pass
		if isinstance(value, ttLib.getTableModule('glyf').Glyph):
			# Glyph type needs explicit expanding to be useful
			value.expand(self._font['glyf'])
		if isinstance(value, misc.psCharStrings.T2CharString):
			try:
				value.decompile()
			except TypeError:  # Subroutines can't be decompiled
				pass
		if isinstance(value, cffLib.BaseDict):
			for k in value.rawDict.keys():
				getattr(value, k)
		if isinstance(value, cffLib.Index):
			# Load all items
			for i in range(len(value)):
				value[i]
			# Discard offsets as should not be needed anymore
			if hasattr(value, 'offsets'):
				del value.offsets

		self._value_str = value.__class__.__name__
		if isinstance(value, ttLib.tables.DefaultTable.DefaultTable):
			self._value_str += ' (%d Bytes)' % self._font.reader.tables[key].length
		self._items = sorted(value.__dict__.items())
		self._filter_items()
    def fix(self):
        unencoded_glyphs = get_unencoded_glyphs(self.font)
        if not unencoded_glyphs:
            return

        ucs2cmap = None
        cmap = self.font["cmap"]

        # Check if an UCS-2 cmap exists
        for ucs2cmapid in ((3, 1), (0, 3), (3, 0)):
            ucs2cmap = cmap.getcmap(ucs2cmapid[0], ucs2cmapid[1])
            if ucs2cmap:
                break
        # Create UCS-4 cmap and copy the contents of UCS-2 cmap
        # unless UCS 4 cmap already exists
        ucs4cmap = cmap.getcmap(3, 10)
        if not ucs4cmap:
            cmapModule = ttLib.getTableModule('cmap')
            ucs4cmap = cmapModule.cmap_format_12(12)
            ucs4cmap.platformID = 3
            ucs4cmap.platEncID = 10
            ucs4cmap.language = 0
            if ucs2cmap:
                ucs4cmap.cmap = copy.deepcopy(ucs2cmap.cmap)
            cmap.tables.append(ucs4cmap)
        # Map all glyphs to UCS-4 cmap Supplementary PUA-A codepoints
        # by 0xF0000 + glyphID
        ucs4cmap = cmap.getcmap(3, 10)
        for glyphID, glyph in enumerate(self.font.getGlyphOrder()):
            if glyph in unencoded_glyphs:
                ucs4cmap.cmap[0xF0000 + glyphID] = glyph
        self.font['cmap'] = cmap
        return True
Esempio n. 7
0
    def addGlyph(self, uchar, glyph):
        # Add to glyph list
        glyphOrder = self.font.getGlyphOrder()
        # assert glyph not in glyphOrder
        glyphOrder.append(glyph)
        self.font.setGlyphOrder(glyphOrder)

        # Add horizontal metrics (to zero)
        self.font['hmtx'][glyph] = [0, 0]

        # Add to cmap
        for table in self.font['cmap'].tables:
            if not (table.platformID == 3 and table.platEncID in [1, 10]):
                continue
            if not table.cmap:  # Skip UVS cmaps
                continue
            assert uchar not in table.cmap
            table.cmap[uchar] = glyph

        # Add empty glyph outline
        if 'glyf' in self.font:
            self.font['glyf'].glyphs[glyph] = ttLib.getTableModule('glyf').Glyph()
        else:
            cff = self.font['CFF '].cff
            addCFFGlyph(
                glyphName=glyph,
                private=cff.topDictIndex[0].topDict.Private,
                globalSubrs=cff.GlobalSubrs,
                charStringsIndex=cff.topDictIndex[0].topDict.CharStrings.charStrings.charStringsIndex,
                topDict=cff.topDictIndex[0],
                charStrings=cff.topDictIndex[0].CharStrings
            )
        return glyph
Esempio n. 8
0
def merge(self, m, tables):
	# TODO Handle format=14.
	# Only merges 4/3/1 and 12/3/10 subtables, ignores all other subtables
	# If there is a format 12 table for the same font, ignore the format 4 table
	cmapTables = []
	for fontIdx,table in enumerate(tables):
		format4 = None
		format12 = None
		for subtable in table.tables:
			properties = (subtable.format, subtable.platformID, subtable.platEncID)
			if properties == (4,3,1):
				format4 = subtable
			elif properties == (12,3,10):
				format12 = subtable
		if format12 is not None:
			cmapTables.append((format12, fontIdx))
		elif format4 is not None:
			cmapTables.append((format4, fontIdx))

	# Build a unicode mapping, then decide which format is needed to store it.
	cmap = {}
	for table,fontIdx in cmapTables:
		# handle duplicates
		for uni,gid in table.cmap.items():
			oldgid = cmap.get(uni, None)
			if oldgid is None:
				cmap[uni] = gid
			elif oldgid != gid:
				# Char previously mapped to oldgid, now to gid.
				# Record, to fix up in GSUB 'locl' later.
				if m.duplicateGlyphsPerFont[fontIdx].get(oldgid, gid) == gid:
					m.duplicateGlyphsPerFont[fontIdx][oldgid] = gid
				else:
					# char previously mapped to oldgid but already remapped to a different gid,
					# save new gid as an alternate
					# TODO: try harder to save these
					log.warn("Dropped mapping from codepoint %#06X to glyphId '%s'", uni, gid)

	cmapBmpOnly = {uni: gid for uni,gid in cmap.items() if uni <= 0xFFFF}
	self.tables = []
	module = ttLib.getTableModule('cmap')
	if len(cmapBmpOnly) != len(cmap):
		# format-12 required.
		cmapTable = module.cmap_classes[12](12)
		cmapTable.platformID = 3
		cmapTable.platEncID = 10
		cmapTable.language = 0
		cmapTable.cmap = cmap
		self.tables.append(cmapTable)
	# always create format-4
	cmapTable = module.cmap_classes[4](4)
	cmapTable.platformID = 3
	cmapTable.platEncID = 1
	cmapTable.language = 0
	cmapTable.cmap = cmapBmpOnly
	# ordered by platform then encoding
	self.tables.insert(0, cmapTable)
	self.tableVersion = 0
	self.numSubTables = len(self.tables)
	return self
Esempio n. 9
0
def merge(self, m, tables):

    # TODO Handle format=14.
    if not hasattr(m, 'cmap'):
        computeMegaCmap(m, tables)
    cmap = m.cmap

    cmapBmpOnly = {uni: gid for uni, gid in cmap.items() if uni <= 0xFFFF}
    self.tables = []
    module = ttLib.getTableModule('cmap')
    if len(cmapBmpOnly) != len(cmap):
        # format-12 required.
        cmapTable = module.cmap_classes[12](12)
        cmapTable.platformID = 3
        cmapTable.platEncID = 10
        cmapTable.language = 0
        cmapTable.cmap = cmap
        self.tables.append(cmapTable)
    # always create format-4
    cmapTable = module.cmap_classes[4](4)
    cmapTable.platformID = 3
    cmapTable.platEncID = 1
    cmapTable.language = 0
    cmapTable.cmap = cmapBmpOnly
    # ordered by platform then encoding
    self.tables.insert(0, cmapTable)
    self.tableVersion = 0
    self.numSubTables = len(self.tables)
    return self
Esempio n. 10
0
    def fix(self):
        unencoded_glyphs = get_unencoded_glyphs(self.font)
        if not unencoded_glyphs:
            return

        ucs2cmap = None
        cmap = self.font["cmap"]

        # Check if an UCS-2 cmap exists
        for ucs2cmapid in ((3, 1), (0, 3), (3, 0)):
            ucs2cmap = cmap.getcmap(ucs2cmapid[0], ucs2cmapid[1])
            if ucs2cmap:
                break
        # Create UCS-4 cmap and copy the contents of UCS-2 cmap
        # unless UCS 4 cmap already exists
        ucs4cmap = cmap.getcmap(3, 10)
        if not ucs4cmap:
            cmapModule = ttLib.getTableModule('cmap')
            ucs4cmap = cmapModule.cmap_format_12(12)
            ucs4cmap.platformID = 3
            ucs4cmap.platEncID = 10
            ucs4cmap.language = 0
            if ucs2cmap:
                ucs4cmap.cmap = copy.deepcopy(ucs2cmap.cmap)
            cmap.tables.append(ucs4cmap)
        # Map all glyphs to UCS-4 cmap Supplementary PUA-A codepoints
        # by 0xF0000 + glyphID
        ucs4cmap = cmap.getcmap(3, 10)
        for glyphID, glyph in enumerate(self.font.getGlyphOrder()):
            if glyph in unencoded_glyphs:
                ucs4cmap.cmap[0xF0000 + glyphID] = glyph
        self.font['cmap'] = cmap
        return True
def merge(self, m, tables):
	# TODO Handle format=14.
	cmapTables = [(t,fontIdx) for fontIdx,table in enumerate(tables) for t in table.tables if t.isUnicode()]
	# TODO Better handle format-4 and format-12 coexisting in same font.
	# TODO Insert both a format-4 and format-12 if needed.
	module = ttLib.getTableModule('cmap')
	assert all(t.format in [4, 12] for t,_ in cmapTables)
	format = max(t.format for t,_ in cmapTables)
	cmapTable = module.cmap_classes[format](format)
	cmapTable.cmap = {}
	cmapTable.platformID = 3
	cmapTable.platEncID = max(t.platEncID for t,_ in cmapTables)
	cmapTable.language = 0
	cmap = cmapTable.cmap
	for table,fontIdx in cmapTables:
		# TODO handle duplicates.
		for uni,gid in table.cmap.items():
			oldgid = cmap.get(uni, None)
			if oldgid is None:
				cmap[uni] = gid
			elif oldgid != gid:
				# Char previously mapped to oldgid, now to gid.
				# Record, to fix up in GSUB 'locl' later.
				assert m.duplicateGlyphsPerFont[fontIdx].get(oldgid, gid) == gid
				m.duplicateGlyphsPerFont[fontIdx][oldgid] = gid
	self.tableVersion = 0
	self.tables = [cmapTable]
	self.numSubTables = len(self.tables)
	return self
Esempio n. 12
0
 def makeFont(self):
     cvt, cvar, fvar = newTable("cvt "), newTable("cvar"), newTable("fvar")
     font = {"cvt ": cvt, "cvar": cvar, "fvar": fvar}
     cvt.values = [0, 0, 0, 1000, -2000]
     Axis = getTableModule("fvar").Axis
     fvar.axes = [Axis(), Axis()]
     fvar.axes[0].axisTag, fvar.axes[1].axisTag = "wght", "wdth"
     return font, cvar
Esempio n. 13
0
	def makeSubtable(self, format, platformID, platEncID, cmap):
		module = ttLib.getTableModule('cmap')
		subtable = module.cmap_classes[format](format)
		(subtable.platformID,
			subtable.platEncID,
			subtable.language,
			subtable.cmap) = (platformID, platEncID, 0, cmap)
		return subtable
Esempio n. 14
0
	def makeSubtable(self, format, platformID, platEncID, cmap):
		module = ttLib.getTableModule('cmap')
		subtable = module.cmap_classes[format](format)
		(subtable.platformID,
			subtable.platEncID,
			subtable.language,
			subtable.cmap) = (platformID, platEncID, 0, cmap)
		return subtable
Esempio n. 15
0
 def makeFont(self):
     cvt, cvar, fvar = newTable("cvt "), newTable("cvar"), newTable("fvar")
     font = {"cvt ": cvt, "cvar": cvar, "fvar": fvar}
     cvt.values = [0, 1000, -2000]
     Axis = getTableModule("fvar").Axis
     fvar.axes = [Axis(), Axis()]
     fvar.axes[0].axisTag, fvar.axes[1].axisTag = "wght", "wdth"
     return font, cvar
Esempio n. 16
0
def openOpenTypeFile(path, outFilePath, options):
    from psautohint.BezTools import CFFFontData
    from fontTools.ttLib import TTFont, getTableModule

    # If input font is CFF, build a dummy ttFont in memory.
    # Return ttFont, and flag if is a real OTF font.
    # Return flag is 0 if OTF, and 1 if CFF.
    fontType = 0  # OTF
    try:
        ff = open(path, "rb")
        data = ff.read(10)
        ff.close()
    except (IOError, OSError):
        logMsg("Failed to open and read font file %s." % path)

    if data[:4] == b"OTTO":  # it is an OTF font, can process file directly
        try:
            ttFont = TTFont(path)
        except (IOError, OSError):
            raise ACFontError("Error opening or reading from font file <%s>." %
                              path)
        except TTLibError:
            raise ACFontError("Error parsing font file <%s>." % path)

        try:
            cffTable = ttFont["CFF "]
        except KeyError:
            raise ACFontError("Error: font is not a CFF font <%s>." %
                              fontFileName)

    else:

        # It is not an OTF file.
        if (data[0] == b'\1') and (data[1] == b'\0'):  # CFF file
            fontType = 1
        else:
            logMsg("Font file must be a CFF or OTF fontfile: %s." % path)
            raise ACFontError("Font file must be CFF or OTF file: %s." % path)

        # now package the CFF font as an OTF font.
        ff = open(path, "rb")
        data = ff.read()
        ff.close()
        try:
            ttFont = TTFont()
            cffModule = getTableModule('CFF ')
            cffTable = cffModule.table_C_F_F_('CFF ')
            ttFont['CFF '] = cffTable
            cffTable.decompile(data, ttFont)
        except:
            logMsg("\t%s" %
                   (traceback.format_exception_only(sys.exc_info()[0],
                                                    sys.exc_info()[1])[-1]))
            logMsg("Attempted to read font %s as CFF." % path)
            raise ACFontError("Error parsing font file <%s>." % path)

    fontData = CFFFontData(ttFont, path, outFilePath, fontType, logMsg)
    return fontData
Esempio n. 17
0
def colorize(font):
    COLR = newTable("COLR")
    CPAL = newTable("CPAL")
    glyf = font["glyf"]
    hmtx = font["hmtx"]

    CPAL.version = 0
    COLR.version = 0

    palette = list(GROUPS.values())
    CPAL.palettes = [palette]
    CPAL.numPaletteEntries = len(palette)

    COLR.ColorLayers = {}

    glyphOrder = list(font.getGlyphOrder())
    for name in glyphOrder:
        glyph = glyf[name]

        layers = []
        if glyph.isComposite() and len(glyph.components) > 1:
            componentColors = [getGlyphColor(c.getComponentInfo()[0]) for c in glyph.components]
            if any(componentColors):
                for component in glyph.components:
                    componentName, trans = component.getComponentInfo()
                    componentColor = getGlyphColor(componentName)
                    if componentColor is None:
                        componentColor = 0xFFFF
                    else:
                        componentColor = palette.index(componentColor)
                    if trans == (1, 0, 0, 1, 0, 0):
                        layers.append(newLayer(componentName, componentColor))
                    else:
                        newName = "%s.%s" % (componentName, hash(trans))
                        if newName not in font.glyphOrder:
                            font.glyphOrder.append(newName)

                            newGlyph = getTableModule("glyf").Glyph()
                            newGlyph.numberOfContours = -1
                            newGlyph.components = [component]
                            glyf.glyphs[newName] = newGlyph
                            assert len(glyf.glyphs) == len(font.glyphOrder), (name, newName)

                            width = hmtx[name][0]
                            lsb = hmtx[componentName][1] + trans[4]
                            hmtx.metrics[newName] = [width, lsb]
                        layers.append(newLayer(newName, componentColor))

        if not layers:
            color = getGlyphColor(name)
            if color is not None:
                layers = [newLayer(name, palette.index(color))]

        if layers:
            COLR[name] = layers

    font["COLR"] = COLR
    font["CPAL"] = CPAL
Esempio n. 18
0
def openOpenTypeFile(path, outFilePath):
	# If input font is  CFF or PS, build a dummy ttFont in memory..
	# return ttFont, and flag if is a real OTF font Return flag is 0 if OTF, 1 if CFF, and 2 if PS/
	fontType  = 0 # OTF
	tempPathCFF = fdkutils.get_temp_file_path()
	try:
		with open(path, "rb") as ff:
			head = ff.read(4)
	except (IOError, OSError):
		logMsg("Failed to open and read font file %s." % path)

	if head == b"OTTO": # it is an OTF font, can process file directly
		try:
			ttFont = TTFont(path)
		except (IOError, OSError):
			raise ACFontError("Error opening or reading from font file <%s>." % path)
		except TTLibError:
			raise ACFontError("Error parsing font file <%s>." % path)

		try:
			cffTable = ttFont["CFF "]
		except KeyError:
			raise ACFontError("Error: font is not a CFF font <%s>." % fontFileName)

	else:
		# It is not an OTF file.
		if head[0:2] == b'\x01\x00': # CFF file
			fontType = 1
			tempPathCFF = path
		else:  # It is a PS file. Convert to CFF.
			fontType =  2
			print("Converting Type1 font to temp CFF font file...")
			command="tx  -cff +b -std \"%s\" \"%s\" 2>&1" % (path, tempPathCFF)
			report = fdkutils.runShellCmd(command)
			if "fatal" in report:
				logMsg("Attempted to convert font %s  from PS to a temporary CFF data file." % path)
				logMsg(report)
				raise ACFontError("Failed to convert PS font %s to a temp CFF font." % path)

		# now package the CFF font as an OTF font.
		with open(tempPathCFF, "rb") as ff:
			data = ff.read()
		try:
			ttFont = TTFont()
			cffModule = getTableModule('CFF ')
			cffTable = cffModule.table_C_F_F_('CFF ')
			ttFont['CFF '] = cffTable
			cffTable.decompile(data, ttFont)
		except:
			logMsg( "\t%s" %(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]))
			logMsg("Attempted to read font %s  as CFF." % path)
			raise ACFontError("Error parsing font file <%s>." % path)

	fontData = CFFFontData(ttFont, path, outFilePath, fontType, logMsg)
	return fontData
Esempio n. 19
0
def openOpenTypeFile(path, outFilePath):
	# If input font is  CFF or PS, build a dummy ttFont in memory..
	# return ttFont, and flag if is a real OTF font Return flag is 0 if OTF, 1 if CFF, and 2 if PS/
	fontType  = 0 # OTF
	tempPathCFF = fdkutils.get_temp_file_path()
	try:
		with open(path, "rb") as ff:
			head = ff.read(4)
	except (IOError, OSError):
		logMsg("Failed to open and read font file %s." % path)

	if head == b"OTTO": # it is an OTF font, can process file directly
		try:
			ttFont = TTFont(path)
		except (IOError, OSError):
			raise ACFontError("Error opening or reading from font file <%s>." % path)
		except TTLibError:
			raise ACFontError("Error parsing font file <%s>." % path)

		try:
			cffTable = ttFont["CFF "]
		except KeyError:
			raise ACFontError("Error: font is not a CFF font <%s>." % fontFileName)

	else:
		# It is not an OTF file.
		if head[0:2] == b'\x01\x00': # CFF file
			fontType = 1
			tempPathCFF = path
		else:  # It is a PS file. Convert to CFF.
			fontType =  2
			print("Converting Type1 font to temp CFF font file...")
			command="tx  -cff +b -std \"%s\" \"%s\" 2>&1" % (path, tempPathCFF)
			report = fdkutils.runShellCmd(command)
			if "fatal" in report:
				logMsg("Attempted to convert font %s  from PS to a temporary CFF data file." % path)
				logMsg(report)
				raise ACFontError("Failed to convert PS font %s to a temp CFF font." % path)

		# now package the CFF font as an OTF font.
		with open(tempPathCFF, "rb") as ff:
			data = ff.read()
		try:
			ttFont = TTFont()
			cffModule = getTableModule('CFF ')
			cffTable = cffModule.table_C_F_F_('CFF ')
			ttFont['CFF '] = cffTable
			cffTable.decompile(data, ttFont)
		except:
			logMsg( "\t%s" %(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])[-1]))
			logMsg("Attempted to read font %s  as CFF." % path)
			raise ACFontError("Error parsing font file <%s>." % path)

	fontData = CFFFontData(ttFont, path, outFilePath, fontType, logMsg)
	return fontData
Esempio n. 20
0
	def _decodeGlyph(self, glyphID):
		glyph = getTableModule('glyf').Glyph()
		glyph.numberOfContours = self.nContourStream[glyphID]
		if glyph.numberOfContours == 0:
			return glyph
		elif glyph.isComposite():
			self._decodeComponents(glyph)
		else:
			self._decodeCoordinates(glyph)
		self._decodeBBox(glyphID, glyph)
		return glyph
Esempio n. 21
0
 def _decodeGlyph(self, glyphID):
     glyph = getTableModule('glyf').Glyph()
     glyph.numberOfContours = self.nContourStream[glyphID]
     if glyph.numberOfContours == 0:
         return glyph
     elif glyph.isComposite():
         self._decodeComponents(glyph)
     else:
         self._decodeCoordinates(glyph)
     self._decodeBBox(glyphID, glyph)
     return glyph
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
Esempio n. 23
0
def assemble_components(comps_data):
    """
    Assemble and return a list of GlyphComponent objects.
    """
    components = []
    for i, cname in enumerate(comps_data.names):
        component = getTableModule('glyf').GlyphComponent()
        component.glyphName = cname
        component.x, component.y = comps_data.positions[i]
        component.flags = 0x204 if i == 0 else 0x4
        components.append(component)
    return components
Esempio n. 24
0
	def _decodeComponents(self, glyph):
		data = self.compositeStream
		glyph.components = []
		more = 1
		haveInstructions = 0
		while more:
			component = getTableModule('glyf').GlyphComponent()
			more, haveInstr, data = component.decompile(data, self)
			haveInstructions = haveInstructions | haveInstr
			glyph.components.append(component)
		self.compositeStream = data
		if haveInstructions:
			self._decodeInstructions(glyph)
Esempio n. 25
0
 def _decodeComponents(self, glyph):
     data = self.compositeStream
     glyph.components = []
     more = 1
     haveInstructions = 0
     while more:
         component = getTableModule('glyf').GlyphComponent()
         more, haveInstr, data = component.decompile(data, self)
         haveInstructions = haveInstructions | haveInstr
         glyph.components.append(component)
     self.compositeStream = data
     if haveInstructions:
         self._decodeInstructions(glyph)
Esempio n. 26
0
 def assemble_components(comps_data):
     """
     Assemble and return a list of GlyphComponent objects.
     """
     components = []
     for i, cname in enumerate(comps_data.names):
         component = getTableModule('glyf').GlyphComponent()
         component.glyphName = cname
         component.x, component.y = comps_data.positions[i]
         component.flags = 0x4
         if i == 0 and comps_data.same_advwidth:
             component.flags = 0x204
         components.append(component)
     return components
Esempio n. 27
0
 def test_compile_v0_sharingColors(self):
     cpal = newTable('CPAL')
     cpal.version = 0
     Color = getTableModule('CPAL').Color
     palette1 = [Color(red=0x22, green=0x33, blue=0x44, alpha=0xff),
                 Color(red=0x99, green=0x88, blue=0x77, alpha=0x11),
                 Color(red=0x55, green=0x55, blue=0x55, alpha=0x55)]
     palette2 = [Color(red=0x22, green=0x33, blue=0x44, alpha=0xff),
                 Color(red=0x99, green=0x88, blue=0x77, alpha=0x11),
                 Color(red=0xFF, green=0xFF, blue=0xFF, alpha=0xFF)]
     cpal.numPaletteEntries = len(palette1)
     cpal.palettes = [palette1, palette1, palette2, palette1]
     self.assertEqual(cpal.compile(ttFont=None),
                      CPAL_DATA_V0_SHARING_COLORS)
Esempio n. 28
0
def makeTempOTF(srcPath):
	ff = file(srcPath, "rb")
	data = ff.read()
	ff.close()
	try:
		ttFont = TTFont()
		cffModule = getTableModule('CFF ')
		cffTable = cffModule.table_C_F_F_('CFF ')
		ttFont['CFF '] = cffTable
		cffTable.decompile(data, ttFont)
	except:
		print "\t%s" %(traceback.format_exception_only(sys.exc_type, sys.exc_value)[-1])
		print "Attempted to read font %s  as CFF." % filePath
		raise LocalError("Error parsing font file <%s>." % filePath)
	return ttFont
Esempio n. 29
0
def makeTempOTF(srcPath):
    ff = file(srcPath, "rb")
    data = ff.read()
    ff.close()
    try:
        ttFont = TTFont()
        cffModule = getTableModule('CFF ')
        cffTable = cffModule.table_C_F_F_('CFF ')
        ttFont['CFF '] = cffTable
        cffTable.decompile(data, ttFont)
    except:
        print "\t%s" % (traceback.format_exception_only(
            sys.exc_type, sys.exc_value)[-1])
        print "Attempted to read font %s  as CFF." % filePath
        raise LocalError("Error parsing font file <%s>." % filePath)
    return ttFont
Esempio n. 30
0
	def test_recalcUnicodeRanges(self):
		font = TTFont()
		font['OS/2'] = os2 = newTable('OS/2')
		font['cmap'] = cmap = newTable('cmap')
		st = getTableModule('cmap').CmapSubtable.newSubtable(4)
		st.platformID, st.platEncID, st.language = 3, 1, 0
		st.cmap = {0x0041:'A', 0x03B1: 'alpha', 0x0410: 'Acyr'}
		cmap.tables = []
		cmap.tables.append(st)
		os2.setUnicodeRanges({0, 1, 9})
		# 'pruneOnly' will clear any bits for which there's no intersection:
		# bit 1 ('Latin 1 Supplement'), in this case. However, it won't set
		# bit 7 ('Greek and Coptic') despite the "alpha" character is present.
		self.assertEqual(os2.recalcUnicodeRanges(font, pruneOnly=True), {0, 9})
		# try again with pruneOnly=False: bit 7 is now set.
		self.assertEqual(os2.recalcUnicodeRanges(font), {0, 7, 9})
		# add a non-BMP char from 'Mahjong Tiles' block (bit 122)
		st.cmap[0x1F000] = 'eastwindtile'
		# the bit 122 and the special bit 57 ('Non Plane 0') are also enabled
		self.assertEqual(os2.recalcUnicodeRanges(font), {0, 7, 9, 57, 122})
Esempio n. 31
0
 def test_recalcUnicodeRanges(self):
     font = TTFont()
     font['OS/2'] = os2 = newTable('OS/2')
     font['cmap'] = cmap = newTable('cmap')
     st = getTableModule('cmap').CmapSubtable.newSubtable(4)
     st.platformID, st.platEncID, st.language = 3, 1, 0
     st.cmap = {0x0041: 'A', 0x03B1: 'alpha', 0x0410: 'Acyr'}
     cmap.tables = []
     cmap.tables.append(st)
     os2.setUnicodeRanges({0, 1, 9})
     # 'pruneOnly' will clear any bits for which there's no intersection:
     # bit 1 ('Latin 1 Supplement'), in this case. However, it won't set
     # bit 7 ('Greek and Coptic') despite the "alpha" character is present.
     self.assertEqual(os2.recalcUnicodeRanges(font, pruneOnly=True), {0, 9})
     # try again with pruneOnly=False: bit 7 is now set.
     self.assertEqual(os2.recalcUnicodeRanges(font), {0, 7, 9})
     # add a non-BMP char from 'Mahjong Tiles' block (bit 122)
     st.cmap[0x1F000] = 'eastwindtile'
     # the bit 122 and the special bit 57 ('Non Plane 0') are also enabled
     self.assertEqual(os2.recalcUnicodeRanges(font), {0, 7, 9, 57, 122})
Esempio n. 32
0
def merge(self, m, tables):
	# TODO Handle format=14.
	cmapTables = [t for table in tables for t in table.tables
		      if t.isUnicode()]
	# TODO Better handle format-4 and format-12 coexisting in same font.
	# TODO Insert both a format-4 and format-12 if needed.
	module = ttLib.getTableModule('cmap')
	assert all(t.format in [4, 12] for t in cmapTables)
	format = max(t.format for t in cmapTables)
	cmapTable = module.cmap_classes[format](format)
	cmapTable.cmap = {}
	cmapTable.platformID = 3
	cmapTable.platEncID = max(t.platEncID for t in cmapTables)
	cmapTable.language = 0
	for table in cmapTables:
		# TODO handle duplicates.
		cmapTable.cmap.update(table.cmap)
	self.tableVersion = 0
	self.tables = [cmapTable]
	self.numSubTables = len(self.tables)
	return self
Esempio n. 33
0
def addGlyph(font, uchar, glyphName):

    # Add to glyph list
    glyphOrder = font.getGlyphOrder()
    assert glyphName not in glyphOrder
    glyphOrder.append(glyphName)
    font.setGlyphOrder(glyphOrder)

    # Add horizontal metrics (to zero)
    font['hmtx'][glyphName] = [0, 0]

    # Add to cmap
    for table in font['cmap'].tables:
        if not (table.platformID == 3 and table.platEncID in [1, 10]):
            continue
        if not table.cmap:  # Skip UVS cmaps
            continue
        assert uchar not in table.cmap
        table.cmap[uchar] = glyphName

    # Add empty glyph outline
    font['glyf'].glyphs[glyphName] = ttLib.getTableModule('glyf').Glyph()
    return glyphName
Esempio n. 34
0
def addGlyph(font, uchar, glyphName):

    # Add to glyph list
    glyphOrder = font.getGlyphOrder()
    assert glyphName not in glyphOrder
    glyphOrder.append(glyphName)
    font.setGlyphOrder(glyphOrder)

    # Add horizontal metrics (to zero)
    font['hmtx'][glyphName] = [0, 0]

    # Add to cmap
    for table in font['cmap'].tables:
        if not (table.platformID == 3 and table.platEncID in [1, 10]):
            continue
        if not table.cmap:  # Skip UVS cmaps
            continue
        assert uchar not in table.cmap
        table.cmap[uchar] = glyphName

    # Add empty glyph outline
    font['glyf'].glyphs[glyphName] = ttLib.getTableModule('glyf').Glyph()
    return glyphName
Esempio n. 35
0
    def addGlyph(self, uchar, glyph):
        # Add to glyph list
        glyphOrder = self.font.getGlyphOrder()
        # assert glyph not in glyphOrder
        glyphOrder.append(glyph)
        self.font.setGlyphOrder(glyphOrder)

        # Add horizontal metrics (to zero)
        self.font['hmtx'][glyph] = [0, 0]

        # Add to cmap
        for table in self.font['cmap'].tables:
            if not (table.platformID == 3 and table.platEncID in [1, 10]):
                continue
            if not table.cmap:  # Skip UVS cmaps
                continue
            assert uchar not in table.cmap
            table.cmap[uchar] = glyph

        # Add empty glyph outline
        if 'glyf' in self.font:
            self.font['glyf'].glyphs[glyph] = ttLib.getTableModule(
                'glyf').Glyph()
        else:
            cff = self.font['CFF '].cff
            self.addCFFGlyph(
                glyphName=glyph,
                private=cff.topDictIndex[0].Private,
                globalSubrs=cff.GlobalSubrs,
                charStringsIndex=cff.topDictIndex[0].CharStrings.
                charStringsIndex,
                # charStringsIndex=cff.topDictIndex[0].CharStrings.charStrings.charStringsIndex,
                topDict=cff.topDictIndex[0],
                charStrings=cff.topDictIndex[0].CharStrings)
            import ipdb
            ipdb.set_trace()
        return glyph
Esempio n. 36
0
    def _decodeTriplets(self, glyph):
        def withSign(flag, baseval):
            assert 0 <= baseval and baseval < 65536, 'integer overflow'
            return baseval if flag & 1 else -baseval

        nPoints = glyph.endPtsOfContours[-1] + 1
        flagSize = nPoints
        if flagSize > len(self.flagStream):
            raise TTLibError("not enough 'flagStream' data")
        flagsData = self.flagStream[:flagSize]
        self.flagStream = self.flagStream[flagSize:]
        flags = array.array('B', flagsData)

        triplets = array.array('B', self.glyphStream)
        nTriplets = len(triplets)
        assert nPoints <= nTriplets

        x = 0
        y = 0
        glyph.coordinates = getTableModule('glyf').GlyphCoordinates.zeros(
            nPoints)
        glyph.flags = array.array("B")
        tripletIndex = 0
        for i in range(nPoints):
            flag = flags[i]
            onCurve = not bool(flag >> 7)
            flag &= 0x7f
            if flag < 84:
                nBytes = 1
            elif flag < 120:
                nBytes = 2
            elif flag < 124:
                nBytes = 3
            else:
                nBytes = 4
            assert ((tripletIndex + nBytes) <= nTriplets)
            if flag < 10:
                dx = 0
                dy = withSign(flag,
                              ((flag & 14) << 7) + triplets[tripletIndex])
            elif flag < 20:
                dx = withSign(flag, (((flag - 10) & 14) << 7) +
                              triplets[tripletIndex])
                dy = 0
            elif flag < 84:
                b0 = flag - 20
                b1 = triplets[tripletIndex]
                dx = withSign(flag, 1 + (b0 & 0x30) + (b1 >> 4))
                dy = withSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f))
            elif flag < 120:
                b0 = flag - 84
                dx = withSign(flag,
                              1 + ((b0 // 12) << 8) + triplets[tripletIndex])
                dy = withSign(
                    flag >> 1,
                    1 + (((b0 % 12) >> 2) << 8) + triplets[tripletIndex + 1])
            elif flag < 124:
                b2 = triplets[tripletIndex + 1]
                dx = withSign(flag, (triplets[tripletIndex] << 4) + (b2 >> 4))
                dy = withSign(flag >> 1,
                              ((b2 & 0x0f) << 8) + triplets[tripletIndex + 2])
            else:
                dx = withSign(flag, (triplets[tripletIndex] << 8) +
                              triplets[tripletIndex + 1])
                dy = withSign(flag >> 1, (triplets[tripletIndex + 2] << 8) +
                              triplets[tripletIndex + 3])
            tripletIndex += nBytes
            x += dx
            y += dy
            glyph.coordinates[i] = (x, y)
            glyph.flags.append(int(onCurve))
        bytesConsumed = tripletIndex
        self.glyphStream = self.glyphStream[bytesConsumed:]
Esempio n. 37
0
def newLayer(name, colorID):
    return getTableModule("COLR").LayerRecord(name=name, colorID=colorID)
Esempio n. 38
0
def newLayer(name, colorID):
    return getTableModule("COLR").LayerRecord(name=name, colorID=colorID)
Esempio n. 39
0
def merge(self, m, tables):
	# TODO Handle format=14.
	# Only merges 4/3/1 and 12/3/10 subtables, ignores all other subtables
	# If there is a format 12 table for the same font, ignore the format 4 table
	cmapTables = []
	for fontIdx,table in enumerate(tables):
		format4 = None
		format12 = None
		for subtable in table.tables:
			properties = (subtable.format, subtable.platformID, subtable.platEncID)
			if properties == (4,3,1):
				format4 = subtable
			elif properties == (12,3,10):
				format12 = subtable
		if format12 is not None:
			cmapTables.append((format12, fontIdx))
		elif format4 is not None:
			cmapTables.append((format4, fontIdx))

	# Build a unicode mapping, then decide which format is needed to store it.
	cmap = {}
	fontIndexForGlyph = {}
	glyphSets = [None for f in m.fonts] if hasattr(m, 'fonts') else None
	for table,fontIdx in cmapTables:
		# handle duplicates
		for uni,gid in table.cmap.items():
			oldgid = cmap.get(uni, None)
			if oldgid is None:
				cmap[uni] = gid
				fontIndexForGlyph[gid] = fontIdx
			elif oldgid != gid:
				# Char previously mapped to oldgid, now to gid.
				# Record, to fix up in GSUB 'locl' later.
				if m.duplicateGlyphsPerFont[fontIdx].get(oldgid) is None:
					if glyphSets is not None:
						oldFontIdx = fontIndexForGlyph[oldgid]
						for idx in (fontIdx, oldFontIdx):
							if glyphSets[idx] is None:
								glyphSets[idx] = m.fonts[idx].getGlyphSet()
						if _glyphsAreSame(glyphSets[oldFontIdx], glyphSets[fontIdx], oldgid, gid):
							continue
					m.duplicateGlyphsPerFont[fontIdx][oldgid] = gid
				elif m.duplicateGlyphsPerFont[fontIdx][oldgid] != gid:
					# Char previously mapped to oldgid but oldgid is already remapped to a different
					# gid, because of another Unicode character.
					# TODO: Try harder to do something about these.
					log.warning("Dropped mapping from codepoint %#06X to glyphId '%s'", uni, gid)

	cmapBmpOnly = {uni: gid for uni,gid in cmap.items() if uni <= 0xFFFF}
	self.tables = []
	module = ttLib.getTableModule('cmap')
	if len(cmapBmpOnly) != len(cmap):
		# format-12 required.
		cmapTable = module.cmap_classes[12](12)
		cmapTable.platformID = 3
		cmapTable.platEncID = 10
		cmapTable.language = 0
		cmapTable.cmap = cmap
		self.tables.append(cmapTable)
	# always create format-4
	cmapTable = module.cmap_classes[4](4)
	cmapTable.platformID = 3
	cmapTable.platEncID = 1
	cmapTable.language = 0
	cmapTable.cmap = cmapBmpOnly
	# ordered by platform then encoding
	self.tables.insert(0, cmapTable)
	self.tableVersion = 0
	self.numSubTables = len(self.tables)
	return self
Esempio n. 40
0
def colorize(font):
    COLR = newTable("COLR")
    CPAL = newTable("CPAL")
    hmtx = font["hmtx"]

    glyf = font.get("glyf", None)
    CFF = font.get("CFF ", None)

    if glyf is None:
        assert False, "CFF is not supported"

    CPAL.version = 0
    COLR.version = 0

    palette = list(GROUPS.values())
    CPAL.palettes = [palette]
    CPAL.numPaletteEntries = len(palette)

    COLR.ColorLayers = {}

    glyphOrder = list(font.getGlyphOrder())
    for name in glyphOrder:
        glyph = glyf[name]

        layers = []
        if glyph.isComposite() and len(glyph.components) > 1:
            componentColors = [
                getGlyphColor(c.getComponentInfo()[0])
                for c in glyph.components
            ]
            if any(componentColors):
                for component in glyph.components:
                    componentName, trans = component.getComponentInfo()
                    componentColor = getGlyphColor(componentName)

                    if componentColor is None:
                        # Special palette index that means the glyph has no
                        # specified color and takes the text color.
                        componentColor = 0xFFFF
                    else:
                        componentColor = palette.index(componentColor)

                    # Unique identifier for each layer, so we can reuse
                    # identical layers and avoid needless duplication.
                    width = hmtx[name][0]
                    lsb = hmtx[componentName][1] + trans[4]
                    componentHash = hash((trans, width, lsb))

                    if componentName not in HASHES:
                        HASHES[componentName] = []

                    if componentHash not in HASHES[componentName]:
                        HASHES[componentName].append(componentHash)

                    index = HASHES[componentName].index(componentHash)
                    newName = "%s.l%s" % (componentName, index)

                    if newName not in font.glyphOrder:
                        font.glyphOrder.append(newName)

                        newGlyph = getTableModule("glyf").Glyph()
                        newGlyph.numberOfContours = -1
                        newGlyph.components = [component]
                        glyf.glyphs[newName] = newGlyph
                        assert (len(glyf.glyphs) == len(
                            font.glyphOrder)), (name, newName)

                        hmtx.metrics[newName] = [width, lsb]
                    layers.append(newLayer(newName, componentColor))

        if not layers:
            color = getGlyphColor(name)
            if color is not None:
                layers = [newLayer(name, palette.index(color))]

        if layers:
            COLR[name] = layers

    font["COLR"] = COLR
    font["CPAL"] = CPAL
Esempio n. 41
0
import argparse

from fontTools.ttLib import TTFont, getTableModule, newTable

Color = getTableModule("CPAL").Color

RED = Color(red=0xcc, green=0x33, blue=0x33, alpha=0xff)
YELLOW = Color(red=0xee, green=0x99, blue=0x33, alpha=0xff)
GREEN = Color(red=0x00, green=0xa5, blue=0x50, alpha=0xff)
BLUE = Color(red=0x33, green=0x66, blue=0x99, alpha=0xff)
BLACK = Color(red=0x00, green=0x00, blue=0x00, alpha=0xff)

HAMAZAT_GLYPHS = (
    "uni0621",
    "uni0654",
    "uni0655",
)

MARKS_GLYPHS = (
    "uni0618",
    "uni0619",
    "uni061A",
    "uni064B",
    "uni064C",
    "uni064D",
    "uni064E",
    "uni064F",
    "uni0650",
    "uni0651",
    "uni0652",
    "uni0657",
Esempio n. 42
0
def openFile(path, txPath):
    # If input font is  CFF or PS, build a dummy ttFont in memory for use by AC.
    # return ttFont, and flag if is a real OTF font Return flag is 0 if OTF, 1 if CFF, and 2 if PS/
    fontType = 0  # OTF
    tempPath = os.path.dirname(path)
    tempPathBase = os.path.join(tempPath, "temp.ac")
    tempPathCFF = tempPathBase + ".cff"
    try:
        ff = file(path, "rb")
        data = ff.read(10)
        ff.close()
    except (IOError, OSError):
        logMsg("Failed to open and read font file %s." % path)

    if data[:4] == "OTTO":  # it is an OTF font, can process file directly
        try:
            ttFont = TTFont(path)
        except (IOError, OSError):
            raise ACFontError("Error opening or reading from font file <%s>." %
                              path)
        except TTLibError:
            raise ACFontError("Error parsing font file <%s>." % path)

        try:
            cffTable = ttFont["CFF "]
        except KeyError:
            raise ACFontError("Error: font is not a CFF font <%s>." %
                              fontFileName)

        return ttFont, fontType

    # It is not an OTF file.
    if (data[0] == '\1') and (data[1] == '\0'):  # CFF file
        fontType = 1
        tempPathCFF = path
    elif not "%" in data:
        #not a PS file either
        logMsg("Font file must be a PS, CFF or OTF  fontfile: %s." % path)
        raise ACFontError("Font file must be PS, CFF or OTF file: %s." % path)

    else:  # It is a PS file. Convert to CFF.
        fontType = 2
        command = "%s   -cff +b  \"%s\" \"%s\" 2>&1" % (txPath, path,
                                                        tempPathCFF)
        report = FDKUtils.runShellCmd(command)
        if "fatal" in report:
            logMsg(
                "Attempted to convert font %s  from PS to a temporary CFF data file."
                % path)
            logMsg(report)
            raise ACFontError(
                "Failed to convert PS font %s to a temp CFF font." % path)

    # now package the CFF font as an OTF font for use by AC.
    ff = file(tempPathCFF, "rb")
    data = ff.read()
    ff.close()
    try:
        ttFont = TTFont()
        cffModule = getTableModule('CFF ')
        cffTable = cffModule.table_C_F_F_('CFF ')
        ttFont['CFF '] = cffTable
        cffTable.decompile(data, ttFont)
    except:
        import traceback
        traceback.print_exc()
        logMsg("Attempted to read font %s  as CFF." % path)
        raise ACFontError("Error parsing font file <%s>." % fontFileName)

    # Delete the temporary temp.ac.cff file
    if os.path.exists(tempPathCFF):
        os.remove(tempPathCFF)

    return ttFont, fontType
Esempio n. 43
0
def openFile(path, txPath):
    # If input font is  CFF or PS, build a dummy ttFont.
    tempPathCFF = None
    cffPath = None

    # If it is CID-keyed font, we need to convert it to a name-keyed font. This is a hack, but I really don't want to add CID support to
    # the very simple-minded PDF library.
    command = "%s   -dump -0  \"%s\" 2>&1" % (txPath, path)
    report = fdkutils.runShellCmd(command)
    if "CIDFontName" in report:
        tfd, tempPath1 = tempfile.mkstemp()
        os.close(tfd)
        command = "%s   -t1 -decid -usefd 0  \"%s\" \"%s\" 2>&1" % (
            txPath, path, tempPath1)
        report = fdkutils.runShellCmd(command)
        if "fatal" in report:
            logMsg(report)
            logMsg(
                "Failed to convert CID-keyed font %s to a temporary Typ1 data file."
                % path)

        tfd, tempPathCFF = tempfile.mkstemp()
        os.close(tfd)
        command = "%s   -cff +b  \"%s\" \"%s\" 2>&1" % (txPath, tempPath1,
                                                        tempPathCFF)
        report = fdkutils.runShellCmd(command)
        if "fatal" in report:
            logMsg(report)
            logMsg(
                "Failed to convert CID-keyed font %s to a temporary CFF data file."
                % path)
        cffPath = tempPathCFF
        os.remove(tempPath1)

    elif os.path.isdir(path):
        # See if it is a UFO font by truing to dump it.
        command = "%s   -dump -0  \"%s\" 2>&1" % (txPath, path)
        report = fdkutils.runShellCmd(command)
        if not "sup.srcFontType" in report:
            logMsg(report)
            logMsg("Failed to open directory %s as a UFO font." % path)

        tfd, tempPathCFF = tempfile.mkstemp()
        os.close(tfd)
        command = "%s   -cff +b  \"%s\" \"%s\" 2>&1" % (txPath, path,
                                                        tempPathCFF)
        report = fdkutils.runShellCmd(command)
        if "fatal" in report:
            logMsg(report)
            logMsg(
                "Failed to convert ufo font %s to a temporary CFF data file." %
                path)
        cffPath = tempPathCFF

    else:
        try:
            with open(path, "rb") as ff:
                head = ff.read(10)
        except (IOError, OSError):
            traceback.print_exc()
            raise FontError(
                "Failed to open and read font file %s. Check file/directory permissions."
                % path)

        if len(head) < 10:
            raise FontError(
                "Error: font file was zero size: may be a resource fork font, which this program does not process. <%s>."
                % path)

        # it is an OTF/TTF font, can process file directly
        elif head[:4] in (b"OTTO", b"true", b"\0\1\0\0"):
            try:
                ttFont = TTFont(path)
            except (IOError, OSError):
                raise FontError(
                    "Error opening or reading from font file <%s>." % path)
            except TTLibError:
                raise

            if 'CFF ' not in ttFont and 'glyf' not in ttFont:
                raise FontError(
                    "Error: font is not a CFF or TrueType font <%s>." % path)

            return ttFont, tempPathCFF

        # It is not an SFNT file.
        elif head[0:2] == b'\x01\x00':  # CFF file
            cffPath = path

        elif b"%" not in head:
            # not a PS file either
            logMsg("Font file must be a PS, CFF or OTF  fontfile: %s." % path)
            raise FontError("Font file must be PS, CFF or OTF file: %s." %
                            path)

        else:  # It is a PS file. Convert to CFF.
            tfd, tempPathCFF = tempfile.mkstemp()
            os.close(tfd)
            cffPath = tempPathCFF
            command = "%s   -cff +b  \"%s\" \"%s\" 2>&1" % (txPath, path,
                                                            tempPathCFF)
            report = fdkutils.runShellCmd(command)
            if "fatal" in report:
                logMsg(
                    "Attempted to convert font %s  from PS to a temporary CFF data file."
                    % path)
                logMsg(report)
                raise FontError(
                    "Failed to convert PS font %s to a temp CFF font." % path)

    # now package the CFF font as an OTF font
    with open(cffPath, "rb") as ff:
        data = ff.read()
    try:
        ttFont = TTFont()
        cffModule = getTableModule('CFF ')
        cffTable = cffModule.table_C_F_F_('CFF ')
        ttFont['CFF '] = cffTable
        cffTable.decompile(data, ttFont)
    except:
        traceback.print_exc()
        logMsg("Attempted to read font %s  as CFF." % path)
        raise FontError("Error parsing font file <%s>." % path)
    return ttFont, tempPathCFF
Esempio n. 44
0
def openOpenTypeFile(path, outFilePath):
	# If input font is  CFF or PS, build a dummy ttFont in memory..
	# return ttFont, and flag if is a real OTF font Return flag is 0 if OTF, 1 if CFF, and 2 if PS/
	fontType  = 0 # OTF
	tempPathCFF = path + kTempCFFSuffix
	try:
		ff = file(path, "rb")
		data = ff.read(10)
		ff.close()
	except (IOError, OSError):
		logMsg("Failed to open and read font file %s." % path)

	if data[:4] == "OTTO": # it is an OTF font, can process file directly
		try:
			ttFont = TTFont(path)
		except (IOError, OSError):
			raise focusFontError("Error opening or reading from font file <%s>." % path)
		except TTLibError:
			raise focusFontError("Error parsing font file <%s>." % path)

		try:
			cffTable = ttFont["CFF "]
		except KeyError:
			raise focusFontError("Error: font is not a CFF font <%s>." % fontFileName)

	else:
	
		# It is not an OTF file.
		if (data[0] == '\1') and (data[1] == '\0'): # CFF file
			fontType = 1
			tempPathCFF = path
		elif not "%" in data:
			#not a PS file either
			logMsg("Font file must be a PS, CFF or OTF  fontfile: %s." % path)
			raise focusFontError("Font file must be PS, CFF or OTF file: %s." % path)
	
		else:  # It is a PS file. Convert to CFF.	
			fontType =  2
			print "Converting Type1 font to temp CFF font file..."
			command="tx  -cff +b -std \"%s\" \"%s\" 2>&1" % (path, tempPathCFF)
			report = FDKUtils.runShellCmd(command)
			if "fatal" in report:
				logMsg("Attempted to convert font %s  from PS to a temporary CFF data file." % path)
				logMsg(report)
				raise focusFontError("Failed to convert PS font %s to a temp CFF font." % path)
		
		# now package the CFF font as an OTF font.
		ff = file(tempPathCFF, "rb")
		data = ff.read()
		ff.close()
		try:
			ttFont = TTFont()
			cffModule = getTableModule('CFF ')
			cffTable = cffModule.table_C_F_F_('CFF ')
			ttFont['CFF '] = cffTable
			cffTable.decompile(data, ttFont)
		except:
			logMsg( "\t%s" %(traceback.format_exception_only(sys.exc_type, sys.exc_value)[-1]))
			logMsg("Attempted to read font %s  as CFF." % path)
			raise focusFontError("Error parsing font file <%s>." % path)

	fontData = CFFFontData(ttFont, path, outFilePath, fontType, logMsg)
	return fontData
Esempio n. 45
0
def openFile(path, txPath):
	# If input font is  CFF or PS, build a dummy ttFont.
	tempPathCFF = None
	try:
		ff = file(path, "rb")
		data = ff.read(10)
		ff.close()
	except (IOError, OSError):
		import traceback
		traceback.print_exc()
		raise FontError("Failed to open and read font file %s. Check file/directory permissions." % path)
		
	if len(data) < 10:
		raise FontError("Error: font file was zero size: may be a resource fork font, which this program does not process. <%s>." % path)

	if (data[:4] == "OTTO") or (data[:4] == "true") or (data[:4] == "\0\1\0\0"): # it is an OTF/TTF font, can process file directly
		try:
			ttFont = ttLib.TTFont(path)
		except (IOError, OSError):
			raise FontError("Error opening or reading from font file <%s>." % path)
		except TTLibError:
			raise FontError("Error parsing font file 333 <%s>." % path)

		if not (ttFont.has_key('CFF ') or ttFont.has_key('glyf')):
			raise FontError("Error: font is not a CFF or TrueType font <%s>." % path)

		return ttFont, tempPathCFF

	# It is not an OTF file.
	if (data[0] == '\1') and (data[1] == '\0'): # CFF file
		cffPath = path
	elif not "%" in data:
		#not a PS file either
		logMsg("Font file must be a PS, CFF or OTF  fontfile: %s." % path)
		raise FontError("Font file must be PS, CFF or OTF file: %s." % path)

	else:  # It is a PS file. Convert to CFF.	
		tfd,tempPathCFF = tempfile.mkstemp()
		os.close(tfd)
		cffPath = tempPathCFF
		command="%s   -cff +b  \"%s\" \"%s\" 2>&1" % (txPath, path, tempPathCFF)
		report = FDKUtils.runShellCmd(command)
		if "fatal" in report:
			logMsg("Attempted to convert font %s  from PS to a temporary CFF data file." % path)
			logMsg(report)
			raise FontError("Failed to convert PS font %s to a temp CFF font." % path)

	# now package the CFF font as an OTF font for use by autohint.
	ff = file(cffPath, "rb")
	data = ff.read()
	ff.close()
	try:
		ttFont = ttLib.TTFont()
		cffModule = ttLib.getTableModule('CFF ')
		cffTable = cffModule.table_C_F_F_('CFF ')
		ttFont['CFF '] = cffTable
		cffTable.decompile(data, ttFont)
	except:
		import traceback
		traceback.print_exc()
		logMsg("Attempted to read font %s  as CFF." % path)
		raise FontError("Error parsing font file <%s>." % path)
	return ttFont, tempPathCFF
Esempio n. 46
0
def openOpenTypeFile(path, outFilePath):
    # If input font is  CFF or PS, build a dummy ttFont in memory..
    # return ttFont, and flag if is a real OTF font Return flag is 0 if OTF, 1 if CFF, and 2 if PS/
    fontType = 0  # OTF
    tempPathCFF = path + kTempCFFSuffix
    try:
        ff = file(path, "rb")
        data = ff.read(10)
        ff.close()
    except (IOError, OSError):
        logMsg("Failed to open and read font file %s." % path)

    if data[:4] == "OTTO":  # it is an OTF font, can process file directly
        try:
            ttFont = TTFont(path)
        except (IOError, OSError):
            raise ACFontError("Error opening or reading from font file <%s>." %
                              path)
        except TTLibError:
            raise ACFontError("Error parsing font file <%s>." % path)

        try:
            cffTable = ttFont["CFF "]
        except KeyError:
            raise ACFontError("Error: font is not a CFF font <%s>." %
                              fontFileName)

    else:

        # It is not an OTF file.
        if (data[0] == '\1') and (data[1] == '\0'):  # CFF file
            fontType = 1
            tempPathCFF = path
        elif not "%" in data:
            #not a PS file either
            logMsg("Font file must be a PS, CFF or OTF  fontfile: %s." % path)
            raise ACFontError("Font file must be PS, CFF or OTF file: %s." %
                              path)

        else:  # It is a PS file. Convert to CFF.
            fontType = 2
            print "Converting Type1 font to temp CFF font file..."
            command = "tx  -cff +b -std \"%s\" \"%s\" 2>&1" % (path,
                                                               tempPathCFF)
            report = FDKUtils.runShellCmd(command)
            if "fatal" in report:
                logMsg(
                    "Attempted to convert font %s  from PS to a temporary CFF data file."
                    % path)
                logMsg(report)
                raise ACFontError(
                    "Failed to convert PS font %s to a temp CFF font." % path)

        # now package the CFF font as an OTF font.
        ff = file(tempPathCFF, "rb")
        data = ff.read()
        ff.close()
        try:
            ttFont = TTFont()
            cffModule = getTableModule('CFF ')
            cffTable = cffModule.table_C_F_F_('CFF ')
            ttFont['CFF '] = cffTable
            cffTable.decompile(data, ttFont)
        except:
            logMsg("\t%s" % (traceback.format_exception_only(
                sys.exc_type, sys.exc_value)[-1]))
            logMsg("Attempted to read font %s  as CFF." % path)
            raise ACFontError("Error parsing font file <%s>." % path)

    fontData = CFFFontData(ttFont, path, outFilePath, fontType, logMsg)
    return fontData
Esempio n. 47
0
import argparse

from fontTools.ttLib import TTFont, getTableModule, newTable

Color = getTableModule("CPAL").Color

RED = Color(red=0xCC, green=0x33, blue=0x33, alpha=0xFF)
YELLOW = Color(red=0xEE, green=0x99, blue=0x33, alpha=0xFF)
GREEN = Color(red=0x00, green=0xA5, blue=0x50, alpha=0xFF)
BLUE = Color(red=0x33, green=0x66, blue=0x99, alpha=0xFF)

HAMAZAT_GLYPHS = ("uni0621", "uni0654", "uni0655")

MARKS_GLYPHS = (
    "uni0618",
    "uni0619",
    "uni061A",
    "uni064B",
    "uni064C",
    "uni064D",
    "uni064E",
    "uni064F",
    "uni0650",
    "uni0651",
    "uni0652",
    "uni0657",
    "uni0658",
    "uni065C",
    "uni0670",
    "uni06DC",  # XXX: can be both a mark and a pause
    "uni06DF",
Esempio n. 48
0
def openFile(path, txPath):
	# If input font is  CFF or PS, build a dummy ttFont.
	tempPathCFF = None
	cffPath = None

	# If it is CID-keyed font, we need to convert it to a name-keyed font. This is a hack, but I really don't want to add CID support to
	# the very simple-minded PDF library.
	command="%s   -dump -0  \"%s\" 2>&1" % (txPath, path)
	report = FDKUtils.runShellCmd(command)
	if "CIDFontName" in report:
		tfd,tempPath1 = tempfile.mkstemp()
		os.close(tfd)
		command="%s   -t1 -decid -usefd 0  \"%s\" \"%s\" 2>&1" % (txPath, path, tempPath1)
		report = FDKUtils.runShellCmd(command)
		if "fatal" in report:
			logMsg(report)
			logMsg("Failed to convert CID-keyed font %s to a temporary Typ1 data file." % path)

		tfd,tempPathCFF = tempfile.mkstemp()
		os.close(tfd)
		command="%s   -cff +b  \"%s\" \"%s\" 2>&1" % (txPath, tempPath1, tempPathCFF)
		report = FDKUtils.runShellCmd(command)
		if "fatal" in report:
			logMsg(report)
			logMsg("Failed to convert CID-keyed font %s to a temporary CFF data file." % path)
		cffPath = tempPathCFF
		os.remove(tempPath1)
	elif os.path.isdir(path):
		# See if it is a UFO font by truing to dump it.
		command="%s   -dump -0  \"%s\" 2>&1" % (txPath, path)
		report = FDKUtils.runShellCmd(command)
		if not "sup.srcFontType" in report:
			logMsg(report)
			logMsg("Failed to open directory %s as a UFO font." % path)
			
		tfd,tempPathCFF = tempfile.mkstemp()
		os.close(tfd)
		command="%s   -cff +b  \"%s\" \"%s\" 2>&1" % (txPath, path, tempPathCFF)
		report = FDKUtils.runShellCmd(command)
		if "fatal" in report:
			logMsg(report)
			logMsg("Failed to convert ufo font %s to a temporary CFF data file." % path)
		cffPath = tempPathCFF
	else:
		try:
			ff = file(path, "rb")
			data = ff.read(10)
			ff.close()
		except (IOError, OSError):
			import traceback
			traceback.print_exc()
			raise FontError("Failed to open and read font file %s. Check file/directory permissions." % path)
		
		if len(data) < 10:
			raise FontError("Error: font file was zero size: may be a resource fork font, which this program does not process. <%s>." % path)
		if (data[:4] == "OTTO") or (data[:4] == "true") or (data[:4] == "\0\1\0\0"): # it is an OTF/TTF font, can process file directly
			try:
				ttFont = ttLib.TTFont(path)
			except (IOError, OSError):
				raise FontError("Error opening or reading from font file <%s>." % path)
			except TTLibError:
				raise FontError("Error parsing font file 333 <%s>." % path)
	
			if not (ttFont.has_key('CFF ') or ttFont.has_key('glyf')):
				raise FontError("Error: font is not a CFF or TrueType font <%s>." % path)
	
			return ttFont, tempPathCFF
	
		# It is not an OTF file.
		if (data[0] == '\1') and (data[1] == '\0'): # CFF file
			cffPath = path
		elif not "%" in data:
			#not a PS file either
			logMsg("Font file must be a PS, CFF or OTF  fontfile: %s." % path)
			raise FontError("Font file must be PS, CFF or OTF file: %s." % path)
	
		else:  # It is a PS file. Convert to CFF.	
			tfd,tempPathCFF = tempfile.mkstemp()
			os.close(tfd)
			cffPath = tempPathCFF
			command="%s   -cff +b  \"%s\" \"%s\" 2>&1" % (txPath, path, tempPathCFF)
			report = FDKUtils.runShellCmd(command)
			if "fatal" in report:
				logMsg("Attempted to convert font %s  from PS to a temporary CFF data file." % path)
				logMsg(report)
				raise FontError("Failed to convert PS font %s to a temp CFF font." % path)

	# now package the CFF font as an OTF font
	ff = file(cffPath, "rb")
	data = ff.read()
	ff.close()
	try:
		ttFont = ttLib.TTFont()
		cffModule = ttLib.getTableModule('CFF ')
		cffTable = cffModule.table_C_F_F_('CFF ')
		ttFont['CFF '] = cffTable
		cffTable.decompile(data, ttFont)
	except:
		import traceback
		traceback.print_exc()
		logMsg("Attempted to read font %s  as CFF." % path)
		raise FontError("Error parsing font file <%s>." % path)
	return ttFont, tempPathCFF
Esempio n. 49
0
    def fix(self, check=False):
        retval = False
        fontfile = os.path.basename(self.fontpath)

        space = self.getGlyph(0x0020)
        nbsp = self.getGlyph(0x00A0)
        if space not in ["space", "uni0020"]:
            logger.error(
                'ER: {}: Glyph 0x0020 is called "{}": Change to "space" or "uni0020"'
                .format(fontfile, space))
        if nbsp not in ["nbsp", "uni00A0", "nonbreakingspace", "nbspace"]:
            logger.error(
                'ER: {}: Glyph 0x00A0 is called "{}": Change to "nbsp" or "uni00A0"'
                .format(fontfile, nbsp))

        isNbspAdded = isSpaceAdded = False
        if not nbsp:
            isNbspAdded = True
            try:
                nbsp = self.addGlyph(0x00A0, 'nbsp')
            except Exception as ex:
                logger.error('ER: {}'.format(ex))
                return False
        if not space:
            isSpaceAdded = True
            try:
                space = self.addGlyph(0x0020, 'space')
            except Exception as ex:
                logger.error('ER: {}'.format(ex))
                return False

        for g in [space, nbsp]:
            if self.glyphHasInk(g):
                if check:
                    logger.error(
                        'ER: {}: Glyph "{}" has ink. Delete any contours or components'
                        .format(fontfile, g))
                else:
                    logger.error(
                        'ER: {}: Glyph "{}" has ink. Fixed: Overwritten by an empty glyph'
                        .format(fontfile, g))
                    #overwrite existing glyph with an empty one
                    self.font['glyf'].glyphs[g] = ttLib.getTableModule(
                        'glyf').Glyph()
                    retval = True

        spaceWidth = self.getWidth(space)
        nbspWidth = self.getWidth(nbsp)

        if spaceWidth != nbspWidth or nbspWidth < 0:

            self.setWidth(nbsp, min(nbspWidth, spaceWidth))
            self.setWidth(space, min(nbspWidth, spaceWidth))

            if isNbspAdded:
                if check:
                    msg = 'ER: {} space {} nbsp None: Add nbsp with advanceWidth {}'
                else:
                    msg = 'ER: {} space {} nbsp None: Added nbsp with advanceWidth {}'
                logger.error(msg.format(fontfile, spaceWidth, spaceWidth))

            if isSpaceAdded:
                if check:
                    msg = 'ER: {} space None nbsp {}: Add space with advanceWidth {}'
                else:
                    msg = 'ER: {} space None nbsp {}: Added space with advanceWidth {}'
                logger.error(msg.format(fontfile, nbspWidth, nbspWidth))

            if nbspWidth > spaceWidth and spaceWidth >= 0:
                if check:
                    msg = 'ER: {} space {} nbsp {}: Change space advanceWidth to {}'
                else:
                    msg = 'ER: {} space {} nbsp {}: Fixed space advanceWidth to {}'
                logger.error(
                    msg.format(fontfile, spaceWidth, nbspWidth, nbspWidth))
            else:
                if check:
                    msg = 'ER: {} space {} nbsp {}: Change nbsp advanceWidth to {}'
                else:
                    msg = 'ER: {} space {} nbsp {}: Fixed nbsp advanceWidth to {}'
                logger.error(
                    msg.format(fontfile, spaceWidth, nbspWidth, spaceWidth))
            return True

        logger.info('OK: {} space {} nbsp {}'.format(fontfile, spaceWidth,
                                                     nbspWidth))
        return retval
Esempio n. 50
0
def merge(self, m, tables):
	# TODO Handle format=14.
	# Only merge format 4 and 12 Unicode subtables, ignores all other subtables
	# If there is a format 12 table for the same font, ignore the format 4 table
	cmapTables = []
	for fontIdx,table in enumerate(tables):
		format4 = None
		format12 = None
		for subtable in table.tables:
			properties = (subtable.format, subtable.platformID, subtable.platEncID)
			if properties in CmapUnicodePlatEncodings.BMP:
				format4 = subtable
			elif properties in CmapUnicodePlatEncodings.FullRepertoire:
				format12 = subtable
			else:
				log.warning(
					"Dropped cmap subtable from font [%s]:\t"
					"format %2s, platformID %2s, platEncID %2s",
					fontIdx, subtable.format, subtable.platformID, subtable.platEncID
				)
		if format12 is not None:
			cmapTables.append((format12, fontIdx))
		elif format4 is not None:
			cmapTables.append((format4, fontIdx))

	# Build a unicode mapping, then decide which format is needed to store it.
	cmap = {}
	fontIndexForGlyph = {}
	glyphSets = [None for f in m.fonts] if hasattr(m, 'fonts') else None
	for table,fontIdx in cmapTables:
		# handle duplicates
		for uni,gid in table.cmap.items():
			oldgid = cmap.get(uni, None)
			if oldgid is None:
				cmap[uni] = gid
				fontIndexForGlyph[gid] = fontIdx
			elif oldgid != gid:
				# Char previously mapped to oldgid, now to gid.
				# Record, to fix up in GSUB 'locl' later.
				if m.duplicateGlyphsPerFont[fontIdx].get(oldgid) is None:
					if glyphSets is not None:
						oldFontIdx = fontIndexForGlyph[oldgid]
						for idx in (fontIdx, oldFontIdx):
							if glyphSets[idx] is None:
								glyphSets[idx] = m.fonts[idx].getGlyphSet()
						if _glyphsAreSame(glyphSets[oldFontIdx], glyphSets[fontIdx], oldgid, gid):
							continue
					m.duplicateGlyphsPerFont[fontIdx][oldgid] = gid
				elif m.duplicateGlyphsPerFont[fontIdx][oldgid] != gid:
					# Char previously mapped to oldgid but oldgid is already remapped to a different
					# gid, because of another Unicode character.
					# TODO: Try harder to do something about these.
					log.warning("Dropped mapping from codepoint %#06X to glyphId '%s'", uni, gid)

	cmapBmpOnly = {uni: gid for uni,gid in cmap.items() if uni <= 0xFFFF}
	self.tables = []
	module = ttLib.getTableModule('cmap')
	if len(cmapBmpOnly) != len(cmap):
		# format-12 required.
		cmapTable = module.cmap_classes[12](12)
		cmapTable.platformID = 3
		cmapTable.platEncID = 10
		cmapTable.language = 0
		cmapTable.cmap = cmap
		self.tables.append(cmapTable)
	# always create format-4
	cmapTable = module.cmap_classes[4](4)
	cmapTable.platformID = 3
	cmapTable.platEncID = 1
	cmapTable.language = 0
	cmapTable.cmap = cmapBmpOnly
	# ordered by platform then encoding
	self.tables.insert(0, cmapTable)
	self.tableVersion = 0
	self.numSubTables = len(self.tables)
	return self
Esempio n. 51
0
	def _decodeTriplets(self, glyph):

		def withSign(flag, baseval):
			assert 0 <= baseval and baseval < 65536, 'integer overflow'
			return baseval if flag & 1 else -baseval

		nPoints = glyph.endPtsOfContours[-1] + 1
		flagSize = nPoints
		if flagSize > len(self.flagStream):
			raise TTLibError("not enough 'flagStream' data")
		flagsData = self.flagStream[:flagSize]
		self.flagStream = self.flagStream[flagSize:]
		flags = array.array('B', flagsData)

		triplets = array.array('B', self.glyphStream)
		nTriplets = len(triplets)
		assert nPoints <= nTriplets

		x = 0
		y = 0
		glyph.coordinates = getTableModule('glyf').GlyphCoordinates.zeros(nPoints)
		glyph.flags = array.array("B")
		tripletIndex = 0
		for i in range(nPoints):
			flag = flags[i]
			onCurve = not bool(flag >> 7)
			flag &= 0x7f
			if flag < 84:
				nBytes = 1
			elif flag < 120:
				nBytes = 2
			elif flag < 124:
				nBytes = 3
			else:
				nBytes = 4
			assert ((tripletIndex + nBytes) <= nTriplets)
			if flag < 10:
				dx = 0
				dy = withSign(flag, ((flag & 14) << 7) + triplets[tripletIndex])
			elif flag < 20:
				dx = withSign(flag, (((flag - 10) & 14) << 7) + triplets[tripletIndex])
				dy = 0
			elif flag < 84:
				b0 = flag - 20
				b1 = triplets[tripletIndex]
				dx = withSign(flag, 1 + (b0 & 0x30) + (b1 >> 4))
				dy = withSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f))
			elif flag < 120:
				b0 = flag - 84
				dx = withSign(flag, 1 + ((b0 // 12) << 8) + triplets[tripletIndex])
				dy = withSign(flag >> 1,
					1 + (((b0 % 12) >> 2) << 8) + triplets[tripletIndex + 1])
			elif flag < 124:
				b2 = triplets[tripletIndex + 1]
				dx = withSign(flag, (triplets[tripletIndex] << 4) + (b2 >> 4))
				dy = withSign(flag >> 1,
					((b2 & 0x0f) << 8) + triplets[tripletIndex + 2])
			else:
				dx = withSign(flag,
					(triplets[tripletIndex] << 8) + triplets[tripletIndex + 1])
				dy = withSign(flag >> 1,
					(triplets[tripletIndex + 2] << 8) + triplets[tripletIndex + 3])
			tripletIndex += nBytes
			x += dx
			y += dy
			glyph.coordinates[i] = (x, y)
			glyph.flags.append(int(onCurve))
		bytesConsumed = tripletIndex
		self.glyphStream = self.glyphStream[bytesConsumed:]
Esempio n. 52
0
def openFile(path, txPath):
    # If input font is  CFF or PS, build a dummy ttFont.
    tempPathCFF = None
    try:
        ff = file(path, "rb")
        data = ff.read(10)
        ff.close()
    except (IOError, OSError):
        import traceback
        traceback.print_exc()
        raise FontError(
            "Failed to open and read font file %s. Check file/directory permissions."
            % path)

    if len(data) < 10:
        raise FontError(
            "Error: font file was zero size: may be a resource fork font, which this program does not process. <%s>."
            % path)

    if (data[:4] == "OTTO") or (data[:4] == "true") or (
            data[:4]
            == "\0\1\0\0"):  # it is an OTF/TTF font, can process file directly
        try:
            ttFont = ttLib.TTFont(path)
        except (IOError, OSError):
            raise FontError("Error opening or reading from font file <%s>." %
                            path)
        except TTLibError:
            raise FontError("Error parsing font file 333 <%s>." % path)

        if not (ttFont.has_key('CFF ') or ttFont.has_key('glyf')):
            raise FontError("Error: font is not a CFF or TrueType font <%s>." %
                            path)

        return ttFont, tempPathCFF

    # It is not an OTF file.
    if (data[0] == '\1') and (data[1] == '\0'):  # CFF file
        cffPath = path
    elif not "%" in data:
        #not a PS file either
        logMsg("Font file must be a PS, CFF or OTF  fontfile: %s." % path)
        raise FontError("Font file must be PS, CFF or OTF file: %s." % path)

    else:  # It is a PS file. Convert to CFF.
        tfd, tempPathCFF = tempfile.mkstemp()
        os.close(tfd)
        cffPath = tempPathCFF
        command = "%s   -cff +b  \"%s\" \"%s\" 2>&1" % (txPath, path,
                                                        tempPathCFF)
        report = FDKUtils.runShellCmd(command)
        if "fatal" in report:
            logMsg(
                "Attempted to convert font %s  from PS to a temporary CFF data file."
                % path)
            logMsg(report)
            raise FontError(
                "Failed to convert PS font %s to a temp CFF font." % path)

    # now package the CFF font as an OTF font for use by autohint.
    ff = file(cffPath, "rb")
    data = ff.read()
    ff.close()
    try:
        ttFont = ttLib.TTFont()
        cffModule = ttLib.getTableModule('CFF ')
        cffTable = cffModule.table_C_F_F_('CFF ')
        ttFont['CFF '] = cffTable
        cffTable.decompile(data, ttFont)
    except:
        import traceback
        traceback.print_exc()
        logMsg("Attempted to read font %s  as CFF." % path)
        raise FontError("Error parsing font file <%s>." % path)
    return ttFont, tempPathCFF
Esempio n. 53
0
    def fix(self, check=False):
        retval = False
        fontfile = os.path.basename(self.fontpath)

        space = self.getGlyph(0x0020)
        nbsp = self.getGlyph(0x00A0)
        if space not in ["space", "uni0020"]:
            logger.error(
                'ER: {}: Glyph 0x0020 is called "{}": Change to "space" or "uni0020"'
                .format(fontfile, space))
        if nbsp not in ["nbsp", "uni00A0"]:
            logger.error(
                'ER: {}: Glyph 0x00A0 is called "{}": Change to "nbsp" or "uni00A0"'
                .format(fontfile, nbsp))

        isNbspAdded = isSpaceAdded = False
        if not nbsp:
            isNbspAdded = True
            try:
                nbsp = self.addGlyph(0x00A0, 'nbsp')
            except Exception as ex:
                logger.error('ER: {}'.format(ex))
                return False
        if not space:
            isSpaceAdded = True
            try:
                space = self.addGlyph(0x0020, 'space')
            except Exception as ex:
                logger.error('ER: {}'.format(ex))
                return False

        for g in [space, nbsp]:
            if self.glyphHasInk(g):
                if check:
                    logger.error(
                        'ER: {}: Glyph "{}" has ink. Delete any contours or components'
                        .format(fontfile, g))
                else:
                    logger.error(
                        'ER: {}: Glyph "{}" has ink. Fixed: Overwritten by an empty glyph'
                        .format(fontfile, g))
                    #overwrite existing glyph with an empty one
                    self.font['glyf'].glyphs[g] = ttLib.getTableModule(
                        'glyf').Glyph()
                    retval = True

        spaceWidth = self.getWidth(space)
        nbspWidth = self.getWidth(nbsp)

        if spaceWidth != nbspWidth or nbspWidth < 0:

            self.setWidth(nbsp, min(nbspWidth, spaceWidth))
            self.setWidth(space, min(nbspWidth, spaceWidth))

            if isNbspAdded:
                if check:
                    msg = 'ER: {} space {} nbsp None: Add nbsp with advanceWidth {}'
                else:
                    msg = 'ER: {} space {} nbsp None: Added nbsp with advanceWidth {}'
                logger.error(msg.format(fontfile, spaceWidth, spaceWidth))

            if isSpaceAdded:
                if check:
                    msg = 'ER: {} space None nbsp {}: Add space with advanceWidth {}'
                else:
                    msg = 'ER: {} space None nbsp {}: Added space with advanceWidth {}'
                logger.error(msg.format(fontfile, nbspWidth, nbspWidth))

            if nbspWidth > spaceWidth and spaceWidth >= 0:
                if check:
                    msg = 'ER: {} space {} nbsp {}: Change space advanceWidth to {}'
                else:
                    msg = 'ER: {} space {} nbsp {}: Fixed space advanceWidth to {}'
                logger.error(
                    msg.format(fontfile, spaceWidth, nbspWidth, nbspWidth))
            else:
                if check:
                    msg = 'ER: {} space {} nbsp {}: Change nbsp advanceWidth to {}'
                else:
                    msg = 'ER: {} space {} nbsp {}: Fixed nbsp advanceWidth to {}'
                logger.error(
                    msg.format(fontfile, spaceWidth, nbspWidth, spaceWidth))
            return True

        logger.info('OK: {} space {} nbsp {}'.format(fontfile, spaceWidth,
                                                     nbspWidth))
        return retval
Esempio n. 54
0
def colorize(font):
    COLR = newTable("COLR")
    CPAL = newTable("CPAL")
    glyf = font["glyf"]
    hmtx = font["hmtx"]

    CPAL.version = 0
    COLR.version = 0

    palette = list(GROUPS.values())
    palette.append(BLACK)
    CPAL.palettes = [palette]
    CPAL.numPaletteEntries = len(palette)

    COLR.ColorLayers = {}

    glyphOrder = list(font.getGlyphOrder())
    for name in glyphOrder:
        glyph = glyf[name]

        layers = []
        if glyph.isComposite() and len(glyph.components) > 1:
            componentColors = [
                getGlyphColor(c.getComponentInfo()[0])
                for c in glyph.components
            ]
            if any(componentColors):
                for component in glyph.components:
                    componentName, trans = component.getComponentInfo()
                    componentColor = getGlyphColor(componentName)
                    if trans == (1, 0, 0, 1, 0, 0):
                        if componentColor is None:
                            # broken in current versions of Firefox,
                            # see https://bugzilla.mozilla.org/show_bug.cgi?id=1283932
                            #layers.append(newLayer(componentName, 0xFFFF)) # broken if FF47
                            layers.append(
                                newLayer(componentName, palette.index(BLACK)))
                        else:
                            layers.append(
                                newLayer(componentName,
                                         palette.index(componentColor)))
                    else:
                        newName = "%s.%s" % (componentName, hash(trans))
                        if newName not in font.glyphOrder:
                            font.glyphOrder.append(newName)

                            newGlyph = getTableModule("glyf").Glyph()
                            newGlyph.numberOfContours = -1
                            newGlyph.components = [component]
                            glyf.glyphs[newName] = newGlyph
                            assert (len(glyf.glyphs) == len(
                                font.glyphOrder)), (name, newName)

                            width = hmtx[name][0]
                            lsb = hmtx[componentName][1] + trans[4]
                            hmtx.metrics[newName] = [width, lsb]

                        if componentColor is None:
                            # broken in current versions of Firefox,
                            # see https://bugzilla.mozilla.org/show_bug.cgi?id=1283932
                            #layers.append(newLayer(componentName, 0xFFFF)) # broken if FF47
                            layers.append(
                                newLayer(newName, palette.index(BLACK)))
                        else:
                            layers.append(
                                newLayer(newName,
                                         palette.index(componentColor)))

        if not layers:
            color = getGlyphColor(name)
            if color is not None:
                layers = [newLayer(name, palette.index(color))]

        if layers:
            COLR[name] = layers

    font["COLR"] = COLR
    font["CPAL"] = CPAL