示例#1
0
def make_ft_program(assembly):
    program = Program()
    program.fromAssembly(assembly)
    # need to compile bytecode for PUSH optimization
    program._assemble()
    del program.assembly
    return program
示例#2
0
 def rebuildPrep(self):
     hintProg = Program()
     hintProg.fromBytecode([184, 1, 255, 133, 184, 0, 4, 141])
     prep = newTable("prep")
     prep.program = hintProg
     self.font["prep"] = prep
     return
示例#3
0
def make_ft_program(assembly):
    program = Program()
    program.fromAssembly(assembly)
    # need to compile bytecode for PUSH optimization
    program._assemble()
    del program.assembly
    return program
示例#4
0
    def test__bool__(self):
        p = Program()
        assert not bool(p)

        bc = array.array("B", [0])
        p.fromBytecode(bc)
        assert bool(p)

        assert p.bytecode.pop() == 0
        assert not bool(p)

        p = Program()
        asm = ['SVTCA[0]']
        p.fromAssembly(asm)
        assert bool(p)

        assert p.assembly.pop() == 'SVTCA[0]'
        assert not bool(p)
示例#5
0
 def test_xml_indentation(self):
     with open(TTPROGRAM_TTX, 'r', encoding='utf-8') as f:
         ttProgramXML = f.read()
     p = Program()
     p.fromBytecode(BYTECODE)
     ttfont = TestFont()
     buf = StringIO()
     writer = XMLWriter(buf)
     try:
         p.toXML(writer, ttfont)
     finally:
         output_string = buf.getvalue()
     assert output_string == ttProgramXML
示例#6
0
def _merge_TTHinting(font, model, master_ttfs, tolerance=0.5):

	log.info("Merging TT hinting")
	assert "cvar" not in font

	# Check that the existing hinting is compatible

	# fpgm and prep table

	for tag in ("fpgm", "prep"):
		all_pgms = [m[tag].program for m in master_ttfs if tag in m]
		if len(all_pgms) == 0:
			continue
		if tag in font:
			font_pgm = font[tag].program
		else:
			font_pgm = Program()
		if any(pgm != font_pgm for pgm in all_pgms):
			log.warning("Masters have incompatible %s tables, hinting is discarded." % tag)
			_remove_TTHinting(font)
			return

	# glyf table

	for name, glyph in font["glyf"].glyphs.items():
		all_pgms = [
			m["glyf"][name].program
			for m in master_ttfs
			if hasattr(m["glyf"][name], "program")
		]
		if not any(all_pgms):
			continue
		glyph.expand(font["glyf"])
		if hasattr(glyph, "program"):
			font_pgm = glyph.program
		else:
			font_pgm = Program()
		if any(pgm != font_pgm for pgm in all_pgms if pgm):
			log.warning("Masters have incompatible glyph programs in glyph '%s', hinting is discarded." % name)
			_remove_TTHinting(font)
			return

	# cvt table

	all_cvs = [Vector(m["cvt "].values) for m in master_ttfs if "cvt " in m]
	
	if len(all_cvs) == 0:
		# There is no cvt table to make a cvar table from, we're done here.
		return

	if len(all_cvs) != len(master_ttfs):
		log.warning("Some masters have no cvt table, hinting is discarded.")
		_remove_TTHinting(font)
		return

	num_cvt0 = len(all_cvs[0])
	if (any(len(c) != num_cvt0 for c in all_cvs)):
		log.warning("Masters have incompatible cvt tables, hinting is discarded.")
		_remove_TTHinting(font)
		return

	# We can build the cvar table now.

	cvar = font["cvar"] = newTable('cvar')
	cvar.version = 1
	cvar.variations = []

	deltas = model.getDeltas(all_cvs)
	supports = model.supports
	for i,(delta,support) in enumerate(zip(deltas[1:], supports[1:])):
		delta = [int(round(d)) for d in delta]
		if all(abs(v) <= tolerance for v in delta):
			continue
		var = TupleVariation(support, delta)
		cvar.variations.append(var)
示例#7
0
 def test_roundtrip(self):
     p = Program()
     p.fromBytecode(BYTECODE)
     asm = p.getAssembly(preserve=True)
     p.fromAssembly(asm)
     assert BYTECODE == p.getBytecode()
示例#8
0
def _merge_TTHinting(font, masterModel, master_ttfs):

    log.info("Merging TT hinting")
    assert "cvar" not in font

    # Check that the existing hinting is compatible

    # fpgm and prep table

    for tag in ("fpgm", "prep"):
        all_pgms = [m[tag].program for m in master_ttfs if tag in m]
        if len(all_pgms) == 0:
            continue
        if tag in font:
            font_pgm = font[tag].program
        else:
            font_pgm = Program()
        if any(pgm != font_pgm for pgm in all_pgms):
            log.warning(
                "Masters have incompatible %s tables, hinting is discarded." %
                tag)
            _remove_TTHinting(font)
            return

    # glyf table

    for name, glyph in font["glyf"].glyphs.items():
        all_pgms = [
            m["glyf"][name].program for m in master_ttfs
            if name in m['glyf'] and hasattr(m["glyf"][name], "program")
        ]
        if not any(all_pgms):
            continue
        glyph.expand(font["glyf"])
        if hasattr(glyph, "program"):
            font_pgm = glyph.program
        else:
            font_pgm = Program()
        if any(pgm != font_pgm for pgm in all_pgms if pgm):
            log.warning(
                "Masters have incompatible glyph programs in glyph '%s', hinting is discarded."
                % name)
            # TODO Only drop hinting from this glyph.
            _remove_TTHinting(font)
            return

    # cvt table

    all_cvs = [
        Vector(m["cvt "].values) if 'cvt ' in m else None for m in master_ttfs
    ]

    nonNone_cvs = models.nonNone(all_cvs)
    if not nonNone_cvs:
        # There is no cvt table to make a cvar table from, we're done here.
        return

    if not models.allEqual(len(c) for c in nonNone_cvs):
        log.warning(
            "Masters have incompatible cvt tables, hinting is discarded.")
        _remove_TTHinting(font)
        return

    variations = []
    deltas, supports = masterModel.getDeltasAndSupports(
        all_cvs, round=round
    )  # builtin round calls into Vector.__round__, which uses builtin round as we like
    for i, (delta, support) in enumerate(zip(deltas[1:], supports[1:])):
        if all(v == 0 for v in delta):
            continue
        var = TupleVariation(support, delta)
        variations.append(var)

    # We can build the cvar table now.
    if variations:
        cvar = font["cvar"] = newTable('cvar')
        cvar.version = 1
        cvar.variations = variations
示例#9
0
    def otf2ttf(self, maxErr=1.0, postFormat=2.0, reverseDirection=True):
        # maxErr = 1.0, approximation error, measured in units per em (UPM).
        # postFormat = 2.0, default `post` table format.
        # reverseDirection = True, assuming the input contours' direction is correctly set (counter-clockwise), we just flip it to clockwise.
        if self.font.sfntVersion != "OTTO" or not self.font.has_key(
                "CFF ") or not self.font.has_key("post"):
            print("WARNING: Invalid CFF-based font. --otf2ttf is now ignored.",
                  file=sys.stderr)
            self.jobs.convert_otf2ttf = False
            return

        # Convert cubic to quadratic
        quadGlyphs = {}
        glyphOrder = self.font.getGlyphOrder()
        glyphSet = self.font.getGlyphSet()
        for glyphName in glyphSet.keys():
            glyph = glyphSet[glyphName]
            ttPen = TTGlyphPen(glyphSet)
            cu2quPen = Cu2QuPen(ttPen, maxErr, reverseDirection)
            glyph.draw(cu2quPen)
            quadGlyphs[glyphName] = ttPen.glyph()

        # Create quadratic `glyf` table
        glyf = newTable("glyf")
        glyf.glyphOrder = glyphOrder
        glyf.glyphs = quadGlyphs
        self.font["glyf"] = glyf

        # Create global instruction table `prep` with basic rendering settings
        hintProg = Program()
        hintProg.fromBytecode([184, 1, 255, 133, 184, 0, 4, 141])
        prep = newTable("prep")
        prep.program = hintProg
        self.font["prep"] = prep

        # Create `gasp` table
        gasp = newTable("gasp")
        gasp.version = 1
        gasp.gaspRange = {65535: 10}
        self.font["gasp"] = gasp

        # Create partial TrueType `maxp` table (v1.0)
        maxp = newTable("maxp")
        maxp.tableVersion = 0x00010000
        maxp.maxZones = 1
        maxp.maxTwilightPoints = 0
        maxp.maxStorage = 0
        maxp.maxFunctionDefs = 0
        maxp.maxInstructionDefs = 0
        maxp.maxStackElements = 0
        maxp.maxSizeOfInstructions = 0
        maxp.maxComponentElements = max(
            len(g.components if hasattr(g, "components") else [])
            for g in glyf.glyphs.values())
        self.font["maxp"] = maxp

        # Create an empty `loca` table, which will be automatically generated upon compile
        self.font["loca"] = newTable("loca")

        # Modify `post` table
        post = self.font["post"]
        post.formatType = postFormat
        post.extraNames = []
        post.mapping = {}
        post.glyphOrder = glyphOrder

        # Change sfntVersion from CFF to TrueType
        self.font.sfntVersion = "\x00\x01\x00\x00"

        # Recalculate missing properties in `head`, `glyf`, `maxp` upon compile
        self.font.recalcBBoxes = True

        # Clean-ups
        del self.font["CFF "]
        if self.font.has_key("VORG"):
            del self.font["VORG"]
        return