def rescale_font(infont_path, outfont_path):
    def calc_bbox(glyphs):
        def get_outer_bbox(a, b):
            x = min(a[0], b[0])
            y = min(a[1], b[1])
            w = max(a[0] + a[2], b[0] + b[2]) - x
            h = max(a[1] + a[3], b[1] + b[3]) - y
            return (x, y, w, h)

        return reduce(get_outer_bbox, glyphs)

    font = fontforge.open(infont_path)

    #ScaleToEm(800, 200);
    font.ascent = 800
    font.descent = 200

    #bbox=GetFontBoundingBox()
    bbox = calc_bbox([g.boundingBox() for g in font.glyphs()])
    #print "bbox=", bbox

    #SelectAll();
    font.selection.all()

    #Move(-bbox[0], -bbox[1]);
    #Scale(100*1000/(bbox[3]-bbox[1]), 0, 0);
    #Move(0, -200);
    matrix1 = psMat.translate(-bbox[0], -bbox[1])
    matrix2 = psMat.scale(1000.0 / (bbox[3] - bbox[1]))
    matrix3 = psMat.translate(0, -200)
    transform_matrix = psMat.compose(psMat.compose(matrix1, matrix2), matrix3)
    font.transform(transform_matrix)

    font.generate(outfont_path)
def make_new_glyph(text, scale, list_x, y, new_glyph_codepoint, is_first_glyph,
                   font):
    for index, char in enumerate(list(text)):
        if is_first_glyph:
            # 一文字目だけは、コピペして位置とサイズを変更(全ての文字が参照だと、上手くいかないっぽいので)
            char_codepoint = ord(char)
            font.selection.select(char_codepoint)
            font.copy()

            font.selection.select(('more', 'unicode'), new_glyph_codepoint)
            font.paste()

            matrix = psMat.compose(psMat.scale(scale),
                                   psMat.translate(list_x[index], y))
            font[new_glyph_codepoint].transform(matrix)

            is_first_glyph = False

        else:
            # 親文字の二文字目以降は、文字の位置とサイズを設定して参照を追加
            matrix = psMat.compose(psMat.scale(scale),
                                   psMat.translate(list_x[index], y))
            char_codepoint = ord(char)
            font[new_glyph_codepoint].addReference(
                font[char_codepoint].glyphname, matrix)
    return is_first_glyph, font
Esempio n. 3
0
 def resolveReferences(self, owner, scale, anchorMap):
     self.glyph = self.font.temporary['names'][self.name]
     glyph = self.glyph.glyph
     if self.parent:
         pglyph = self.parent.glyph.glyph
         (px, py) = getanchor(pglyph, self.at)
         if px is None:
             px = pglyph.width / 2
         (cx, cy) = getanchor(glyph, self.withap, isMark=True)
         if cx is None:
             cx = glyph.width / 2
         self.scale = psMat.compose(self.scale,
                                    psMat.translate(px - cx, py - cy))
     if self.rsb is not None:
         self.advance = glyph.width - (self.rsb - pointMult(
             (self.rsb, 0), self.scale)[0])
     self.setGlyphAnchors(glyph,
                          anchorMap)  # after attached scale established
     scale = psMat.compose(scale, self.scale)
     owner.addRealGlyph(self.glyph, scale)
     for c in self.children:
         c.resolveReferences(owner, scale, anchorMap)
     if self.parent:
         self.parent.mergeAnchors(self.anchors)
     else:
         owner.mergeAnchors(self.anchors, scale)
     return pointMult(
         (self.advance if self.advance is not None else glyph.width, 0),
         self.scale)[0]
def rescale_font(infont_path, outfont_path):
    def calc_bbox(glyphs):
        def get_outer_bbox(a, b):
            x = min(a[0], b[0])
            y = min(a[1], b[1])
            w = max(a[0] + a[2], b[0] + b[2]) - x
            h = max(a[1] + a[3], b[1] + b[3]) - y
            return (x, y, w, h)
        return reduce(get_outer_bbox, glyphs)

    font = fontforge.open(infont_path)

    #ScaleToEm(800, 200);
    font.ascent = 800
    font.descent = 200

    #bbox=GetFontBoundingBox()
    bbox = calc_bbox([g.boundingBox() for g in font.glyphs()])
    #print "bbox=", bbox

    #SelectAll();
    font.selection.all()

    #Move(-bbox[0], -bbox[1]);
    #Scale(100*1000/(bbox[3]-bbox[1]), 0, 0);
    #Move(0, -200);
    matrix1 = psMat.translate(-bbox[0], -bbox[1])
    matrix2 = psMat.scale(1000.0/(bbox[3]-bbox[1]))
    matrix3 = psMat.translate(0, -200)
    transform_matrix = psMat.compose(psMat.compose(matrix1, matrix2), matrix3)
    font.transform(transform_matrix)

    font.generate(outfont_path)
Esempio n. 5
0
def copyglyph(font, infont, g, u, args) :
    extras = set()
    if args.scale is None :
        scale = psMat.identity()
    else :
        scale = psMat.scale(args.scale)
    o = font.findEncodingSlot(u)
    if o == -1 :
        glyph = font.createChar(u, g.glyphname)
    else :
        glyph = font[o]
    if len(g.references) == 0 :
        font.selection.select(glyph)
        pen = glyph.glyphPen()
        g.draw(pen)
        glyph.transform(scale)
    else :
        for r in g.references :
            t = psMat.compose(r[1], scale)
            newt = psMat.compose(psMat.identity(), psMat.translate(t[4], t[5]))
            glyph.addReference(r[0], newt)
            extras.add(r[0])
    glyph.width = g.width * scale[0]
    if args.anchors :
        for a in g.anchorPoints :
            try :
                l = font.getSubtableOfAnchor(a[1])
            except EnvironmentError :
                font.addAnchorClass("", a[0]*scale[0], a[1]*scale[3])
        glyph.anchorPoints = g.anchorPoints
    return list(extras)
Esempio n. 6
0
def geometric_triangle(rotation=0, black=True):
    sw = 46
    xm = 37
    b = bb + (bh - bw + 2 * xm) / 2.0
    t = b + (bw - 2 * xm) * math.sin(math.pi / 3)
    contours = []

    c = fontforge.contour()
    c.moveTo(bl + xm, b)
    c.lineTo(cx, t)
    c.lineTo(br - xm, b)
    c.closed = True
    contours.append(c)

    if not black:
        xm += sw * math.sqrt(3)
        c = fontforge.contour()
        c.moveTo(bl + xm, b + sw)
        c.lineTo(br - xm, b + sw)
        c.lineTo(cx, t - 2 * sw)
        c.closed = True
        contours.append(c)

    if rotation:
        cy = (b + t) / 2.0
        rotT = psMat.compose(psMat.translate(-cx, -cy),
               psMat.compose(psMat.rotate(rotation),
                             psMat.translate(cx, cy)))
        for c in contours:
            c.transform(rotT)
    return contours
Esempio n. 7
0
def aroundCentroid(glyph, xform):
    xLo, yLo, xHi, yHi = glyph.layers[1].boundingBox(
    )  # layers[1] is foreground
    xShift = (xHi - xLo) / 2 + xLo
    yShift = (yHi - yLo) / 2 + yLo
    into = mat.translate(-xShift, -yShift)
    outof = mat.translate(xShift, yShift)
    return mat.compose(mat.compose(into, xform), outof)
Esempio n. 8
0
def blackboard(font, bbold):
    dst = "𝔸𝔹ℂ𝔻𝔼𝔽𝔾ℍ𝕀𝕁𝕂𝕃𝕄ℕ𝕆ℙℚℝ𝕊𝕋𝕌𝕍𝕎𝕏𝕐ℤ" \
        + "𝕒𝕓𝕔𝕕𝕖𝕗𝕘𝕙𝕚𝕛𝕜𝕝𝕞𝕟𝕠𝕡𝕢𝕣𝕤𝕥𝕦𝕧𝕨𝕩𝕪𝕫" \
        + "𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡" \
        + "ℼℽℾℿ⅀" \
        + "⨾∘"
    src = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ") \
        + list("abcdefghijklmnopqrstuvwxyz") \
        + list("0123456789") \
        + [chr(x) for x in [25, 13, 0, 5, 6]] \
        + list(";=")
    adjust = {
        '𝕗': mat.translate(-100, 0),
        '𝕛': mat.translate(90, 0),
        '∘': mat.translate(0, 95),
        '⨾': mat.translate(0, 95),
    }
    for i in range(0, len(dst)):
        bbold.selection.select(("singletons", ), ord(src[i]))
        bbold.copy()
        font.selection.select(("singletons", ), ord(dst[i]))
        font.paste()
        glyph = font[ord(dst[i])]
        xform = moveToMonoNoSquash(glyph)
        if dst[i] in adjust:
            xform = mat.compose(xform, adjust[dst[i]])
        glyph.transform(xform, ('round', ))
        glyph.width, glyph.vwidth = monosize
def space_glyph_by_anchors(bitbucket, glyph = None):
    if glyph == None:
        glyph = bitbucket
    lspace = left_spacing(glyph)
    rspace = right_spacing(glyph)
    if lspace != None and rspace != None:
        for r in glyph.references:
            glyph.useRefsMetrics(r[0], False)
        glyph.transform((1, 0, 0, 1, -lspace, 0))
        glyph.width = rspace - lspace

        # Translate all references to this glyph, as well, but in the
        # opposite direction.
        if lspace != 0:
            f = glyph.font
            for glyph_name in f:
                g = f[glyph_name]
                references = list(g.references)
                refs_changed = False
                for i in range(0, len(references)):
                    if references[i][0] == glyph.glyphname:
                        references[i] = (references[i][0], psMat.compose(references[i][1], (1, 0, 0, 1, lspace, 0)))
                        refs_changed = True
                if refs_changed:
                    g.references = tuple(references)
Esempio n. 10
0
def _add_braille(font):
    font.selection.select(BLACK_CIRCLE)
    font.copy()
    font.selection.select(PRIVATE)
    font.paste()

    font.selection.select(PRIVATE)
    move_to_origin = translate(-512, -582.4)
    make_small = scale(BRAILLE_DIAMETER)
    for glyph in list(font.selection.byGlyphs):
        glyph.transform(compose(move_to_origin, make_small))

    with BRAILLE_JSON.open() as f:
        braille = load(f)

    for b in braille:
        for p in b['points']:
            point = BRAILLE_POINTS[p]
            font.selection.select(PRIVATE)
            for glyph in list(font.selection.byGlyphs):
                glyph.transform(translate(point[0], point[1]))
            font.copy()
            font.selection.select(int(b['code'], 16))
            font.pasteInto()
            for glyph in list(font.selection.byGlyphs):
                glyph.width = WIDTH
            font.selection.select(PRIVATE)
            for glyph in list(font.selection.byGlyphs):
                glyph.transform(translate(-point[0], -point[1]))
    font.selection.select(PRIVATE)
    font.cut()
def _transform_sym(symfont, info):

    x_ratio = 1.0
    y_ratio = 1.0
    x_diff = 0
    y_diff = 0

    if info["name"] == "Seti-UI + Custom":
        x_ratio = 1.1
        y_ratio = 1.1
        x_diff = -100
        y_diff = -450

    elif info["name"] == "Devicons":
        x_ratio = 1.05
        y_ratio = 1.05
        x_diff = -100
        y_diff = -250

    elif info["name"] in ["Powerline Symbols", "Powerline Extra Symbols"]:
        x_ratio = 0.95
        y_ratio = 0.88
        x_diff = 0
        y_diff = -30

    elif info["name"] == "Font Linux":
        y_diff = -120

    elif info["name"] == "Font Awesome Extension":
        y_diff = -400

    elif info["name"] == "Pomicons":
        x_ratio = 1.2
        y_ratio = 1.2
        x_diff = -200
        y_diff = -300

    elif info["name"] == "Octicons":
        x_ratio = 0.95
        y_ratio = 0.95
        x_diff = 30
        y_diff = -100

    elif info["name"] == "Material":
        x_ratio = 1.1
        y_ratio = 1.1
        x_diff = -50
        y_diff = -250

    elif info["name"] == "Codicons":
        x_ratio = 0.85
        y_ratio = 0.85
        x_diff = 35
        y_diff = -300

    scale = psMat.scale(x_ratio, y_ratio)
    translate = psMat.translate(x_diff, y_diff)
    transform = psMat.compose(scale, translate)
    symfont.transform(transform)
Esempio n. 12
0
def _hankaku_glyphs(font):
    origin = translate(-DESCENT, 0)
    # scale will scale glyphs with the origin (0, DESCENT)
    scl = scale(SCALE_DOWN)
    # original glyphs have width to fit this size.
    orig_glyph_width = WIDTH - DESCENT * 2
    glyph_width = float(orig_glyph_width) * SCALE_DOWN
    trans_x = (WIDTH / 2 - glyph_width) / 2
    trans_y = (WIDTH - glyph_width) / 2 - DESCENT
    trans = translate(trans_x, trans_y)
    mat = compose(compose(origin, scl), trans)
    font.selection.none()
    for i in HANKAKU_GLYPHS:
        font.selection.select(("more", "unicode"), i)
    for glyph in font.selection.byGlyphs:
        glyph.transform(mat)
        glyph.width = WIDTH / 2
Esempio n. 13
0
def reference_transform(ref, glyph, deg):
    thatglyphname = ref[0]
    thisglyphname = glyph.glyphname
    r = ref[1]

    column_a = "%s's reference to %s:" % (thisglyphname, thatglyphname)
    column_b = str(r)

    ri = psMat.inverse(r)

    result = psMat.identity()
    result = psMat.compose(result, italic_shift_right(deg))
    result = psMat.compose(result, italic_unskew(deg))
    result = psMat.compose(result, r)
    result = psMat.compose(result, italic_skew(deg))
    result = psMat.compose(result, italic_shift_left(deg))

    return (ref[0], result)
Esempio n. 14
0
def referenceTransform(ref, glyph, deg):
    thatglyphname = ref[0]
    thisglyphname = glyph.glyphname
    r = ref[1]

    columnA = "%s's reference to %s:" % (thisglyphname, thatglyphname)
    columnB = str(r)

    ri = psMat.inverse(r)

    result = psMat.identity()
    result = psMat.compose(result, italicShiftRight(deg))
    result = psMat.compose(result, italicUnskew(deg))
    result = psMat.compose(result, r)
    result = psMat.compose(result, italicSkew(deg))
    result = psMat.compose(result, italicShiftLeft(deg))

    return (ref[0], result)
Esempio n. 15
0
def _set_proportion(font):
    scale = psMat.scale(SCALE_DOWN)
    font.selection.all()
    for glyph in list(font.selection.byGlyphs):
        x_to_center = X_TO_CENTER
        trans = psMat.translate(x_to_center, 0)
        mat = psMat.compose(scale, trans)
        glyph.transform(mat)
        glyph.width = EM
Esempio n. 16
0
def follow_references(glyph):
    f = glyph.font
    leaves = []
    for ref in glyph.references:
        if len(f[ref[0]].references) != 0:
            subrefs = follow_references(f[ref[0]])
            leaves += [(r[0], psMat.compose(r[1], ref[1])) for r in subrefs]
        else:
            leaves.append(ref)
    return leaves
Esempio n. 17
0
File: cica.py Progetto: yokazek/Cica
def modify_WM(_f):
    _f.selection.select(0x57)
    _f.transform(psMat.scale(0.95, 1.0))
    _f.copy()
    _f.selection.select(0x4d)
    _f.paste()
    _f.transform(psMat.compose(psMat.rotate(math.radians(180)), psMat.translate(0, 627)))
    for g in _f.selection.byGlyphs:
        g = align_to_center(g)
    return _f
Esempio n. 18
0
def _set_proportion(font):
    scale = psMat.scale(SCALE)
    font.selection.all()
    for glyph in list(font.selection.byGlyphs):
        is_hankaku_kana = glyph.encoding in range(*HANKAKU_KANA)
        x_to_center = X_TO_CENTER / 2 if is_hankaku_kana else X_TO_CENTER
        trans = psMat.translate(x_to_center, 0)
        mat = psMat.compose(scale, trans)
        glyph.transform(mat)
        glyph.width = EM / 2 if is_hankaku_kana else EM
Esempio n. 19
0
def removenestedrefs(char):
    if outfont[char].references == ():
        return [(char, psMat.identity())]
    else:
        newrefs = []
        for (refglyph, transform) in outfont[char].references:
            subrefs = removenestedrefs(refglyph)
            for (newglyph, newtrans) in subrefs:
                newrefs.append((newglyph, psMat.compose(newtrans, transform)))
        return newrefs
Esempio n. 20
0
def set_vbearings_line(line):
    splitted = line.split()
    ch, method = splitted[0:2]
    h2v_shift = splitted[2:]
    c = get_glyph_by_name(ch)
    f.selection.select(c)
    f.copy()
    tag = 'vert'
    name = c.glyphname
    tagged_name = "%s.%s" % (name, tag)
    n = get_glyph_by_name(tagged_name)
    f.selection.select(n)
    alt_path = "../../../splitted/%s/%s/vert/u%04X.svg" % (
        weight, mod, c.unicode)
    if os.path.exists(alt_path):
        n.clear()
        n.importOutlines(alt_path, ('removeoverlap', 'correctdir'))
    else:
        f.paste()
        if method.find('R') >= 0:
            rot = psMat.compose(
                psMat.translate(-em / 2, -ascent + em / 2),
                psMat.compose(psMat.rotate(-math.pi / 2),
                psMat.translate(em / 2, ascent - em / 2)))
            n.transform(rot)
            if method.find('F') >= 0:
                flip = psMat.compose(
                    psMat.translate(-em / 2, -ascent + em / 2),
                    psMat.compose(psMat.scale(-1, 1),
                    psMat.translate(em / 2, ascent - em / 2)))
                n.transform(flip)
        elif method == 'S':
            position = weights_position[weight] * 2
            x, y = h2v_shift[position:position + 2]
            sht = psMat.translate(int(x), int(y))
            n.transform(sht)
    n.width = em
    n.vwidth = em
    if not (tag in alt_glyphs):
        alt_glyphs[tag] = []
    alt_glyphs[tag].append((name, tagged_name))
Esempio n. 21
0
def flattenNestedReferences(font, ref, new_transform=(1, 0, 0, 1, 0, 0)):
    """Flattens nested references by replacing them with the ultimate reference
    and applying any transformation matrices involved, so that the final font
    has only simple composite glyphs. This to work around what seems to be an
    Apple bug that results in ignoring transformation matrix of nested
    references."""

    name = ref[0]
    transform = ref[1]
    glyph = font[name]
    new_ref = []
    if glyph.references and glyph.foreground.isEmpty():
        for nested_ref in glyph.references:
            for i in flattenNestedReferences(font, nested_ref, transform):
                matrix = psMat.compose(i[1], new_transform)
                new_ref.append((i[0], matrix))
    else:
        matrix = psMat.compose(transform, new_transform)
        new_ref.append((name, matrix))

    return new_ref
Esempio n. 22
0
	def patch(self):
		for target_font in self.target_fonts:
			source_font = self.source_font
			target_font_em_original = target_font.em
			target_font.em = 2048
			target_font.encoding = 'ISO10646'

			# Rename font
			if self.rename_font:
				target_font.familyname += ' for Powerline and Tmux'
				target_font.fullname += ' for Powerline and Tmux'
				fontname, style = re.match("^([^-]*)(?:(-.*))?$", target_font.fontname).groups()
				target_font.fontname = fontname + 'ForPowerlineAndTmux'
				if style is not None:
					target_font.fontname += style
				target_font.appendSFNTName('English (US)', 'Preferred Family', target_font.familyname)
				target_font.appendSFNTName('English (US)', 'Compatible Full', target_font.fullname)

			source_bb = source_font['block'].boundingBox()
			target_bb = [0, 0, 0, 0]
			target_font_width = 0

			# Find the biggest char width and height in the Latin-1 extended range and the box drawing range
			# This isn't ideal, but it works fairly well - some fonts may need tuning after patching
			for cp in range(0x00, 0x17f) + range(0x2500, 0x2600):
				try:
					bbox = target_font[cp].boundingBox()
				except TypeError:
					continue
				if not target_font_width:
					target_font_width = target_font[cp].width
				if bbox[0] < target_bb[0]:
					target_bb[0] = bbox[0]
				if bbox[1] < target_bb[1]:
					target_bb[1] = bbox[1]
				if bbox[2] > target_bb[2]:
					target_bb[2] = bbox[2]
				if bbox[3] > target_bb[3]:
					target_bb[3] = bbox[3]

			# Find source and target size difference for scaling
			x_ratio = (target_bb[2] - target_bb[0]) / (source_bb[2] - source_bb[0])
			y_ratio = (target_bb[3] - target_bb[1]) / (source_bb[3] - source_bb[1])
			scale = psMat.scale(x_ratio, y_ratio)

			# Find source and target midpoints for translating
			x_diff = target_bb[0] - source_bb[0]
			y_diff = target_bb[1] - source_bb[1]
			translate = psMat.translate(x_diff, y_diff)
			transform = psMat.compose(scale, translate)
			sys.stderr.write("Source: %i %i %i %i\n" % (source_bb[0], source_bb[1], source_bb[2], source_bb[3]))
			sys.stderr.write("Target: %i %i %i %i\n" % (target_bb[0], target_bb[1], target_bb[2], target_bb[3]))
			sys.stderr.write("Offset: %.2f %.2f, Ratio: %.2f %.2f\n" % (x_diff, y_diff, x_ratio, y_ratio))
Esempio n. 23
0
def _add_bar_to_shade_bottom(font):
    font.selection.select(LOWER_BLOCK)
    font.copy()
    font.selection.select(PRIVATE)
    font.paste()

    font.selection.select(LOWER_BLOCK)
    move_to_origin = translate(0, 208)
    shrink_to_fit = scale(1.0, 106.0 / 256)
    move_to_bottom = translate(0, -439)
    mat = compose(compose(move_to_origin, shrink_to_fit), move_to_bottom)
    for glyph in list(font.selection.byGlyphs):
        glyph.transform(mat)
    font.copy()
    font.selection.select(DARK_SHADE)
    font.pasteInto()

    font.selection.select(PRIVATE)
    font.cut()
    font.selection.select(LOWER_BLOCK)
    font.paste()
def decorate(font, glyph, deco_type):
    ascent = font.ascent
    descent = font.descent
    height = ascent + descent
    width = glyph.width
    ratio = 0.95
    line_ratio = 0.1

    if deco_type in (DECORATE_INVERSE, DECORATE_BOTTOMLINE, DECORATE_TOPLINE,
                     DECORATE_BOTHLINE):
        trans1 = psMat.translate((-width / 2.0, -(ascent - descent) / 2.0))
        scale = psMat.scale(ratio, ratio)
        trans2 = psMat.translate((width / 2.0, (ascent - descent) / 2.0))
        comp = psMat.compose(psMat.compose(trans1, scale), trans2)
        glyph.transform(comp)
        glyph.width = width

    if deco_type == DECORATE_INVERSE:
        pen = glyph.glyphPen(replace=False)
        pen.moveTo(0, ascent + height * line_ratio / 2)
        pen.lineTo(width, ascent + height * line_ratio / 2)
        pen.lineTo(width, -descent - height * line_ratio / 2)
        pen.lineTo(0, -descent - height * line_ratio / 2)
        pen.closePath()
    if deco_type in (DECORATE_BOTTOMLINE, DECORATE_BOTHLINE):
        pen = glyph.glyphPen(replace=False)
        pen.moveTo(0, -descent - height * line_ratio / 2)
        pen.lineTo(0, -descent + height * line_ratio / 2)
        pen.lineTo(width, -descent + height * line_ratio / 2)
        pen.lineTo(width, -descent - height * line_ratio / 2)
        pen.closePath()
    if deco_type in (DECORATE_TOPLINE, DECORATE_BOTHLINE):
        pen = glyph.glyphPen(replace=False)
        pen.moveTo(0, ascent + height * line_ratio / 2)
        pen.lineTo(width, ascent + height * line_ratio / 2)
        pen.lineTo(width, ascent - height * line_ratio / 2)
        pen.lineTo(0, ascent - height * line_ratio / 2)
        pen.closePath()
    glyph.correctDirection()
Esempio n. 25
0
def circle_at(center, size=1.0):
    """Create a Fontforge contour, in the shape of a circle, centered at
    the given point. Second parameter, optional, is the radius of the circle
    in em units. If not specified, the radius will default to 1."""
    x = ux(center)
    y = uy(center)
    # psMat is a fontforge module to help in creating transformation matrices
    matrix = psMat.translate(x,y)
    if size != 1.0:
        matrix = psMat.compose(psMat.scale(size), matrix)
    unitcircle = fontforge.unitShape(0)
    unitcircle.transform(matrix)
    return unitcircle
Esempio n. 26
0
 def resolveReferences(self, anchorMap):
     for p, v in self.points.items():  # sort out config defined points
         anchorMap[p][0] == "basemark"
         self.points[p] = (None, v[1], v[0])
     scale = psMat.identity()
     for c in self.children:
         adv = c.resolveReferences(self, scale, anchorMap)
         scale = psMat.compose(scale, psMat.translate(adv, 0))
     if self.advance < 0:
         if self.glyph:
             self.advance = pointMult((self.glyph.width, 0), self.scale)[0]
         else:
             self.advance = adv
         if self.advance < 0: self.advance = 0
Esempio n. 27
0
File: cica.py Progetto: yokazek/Cica
def add_gopher(_f):
    gopher = fontforge.open(os.path.join(SOURCE, 'gopher.sfd'))
    for g in gopher.glyphs():
        if g.isWorthOutputting:
            gopher.selection.select(0x40)
            gopher.copy()
            _f.selection.select(0xE160)
            _f.paste()
            g.transform(psMat.compose(psMat.scale(-1, 1), psMat.translate(g.width, 0)))
            gopher.copy()
            _f.selection.select(0xE161)
            _f.paste()
    gopher.close()
    return _f
Esempio n. 28
0
 def readXml(self, elem):
     for e in elem:
         if e.tag == "advance":
             self.advance = int(e.get("width", None))
         elif e.tag == "rsb":
             self.rsb = int(e.get("rsb", None))
         elif e.tag == "lsb":
             self.lsb = int(e.get("lsb", None))
         elif e.tag == "shift":
             self.scale = psMat.compose(
                 self.scale,
                 psMat.translate(int(e.get("x", 0)), int(e.get("y", 0))))
         elif e.tag == "scale":
             self.scale = psMat.compose(
                 self.scale,
                 psMat.scale(float(e.get("x", 1.)), float(e.get("y", 1.))))
         elif e.tag == "attach":
             (font, name) = findGlyph(e)
             child = GlyphRef(font,
                              name,
                              parent=self,
                              at=e.get("at"),
                              withap=e.get("with"))
             child.readXml(e)
Esempio n. 29
0
def normalizeGlyph(g, letter):
    bb = g.boundingBox()  #compact box that contains the letter
    dy = bb[3] - bb[1]  # xmin,ymin,xmax,ymax
    newScale = 800 / (dy)
    transforms = deque()
    #shifting
    if letter in SPECIAL_Y_TRANS:
        transforms.append(
            psMat.translate(-bb[0], -bb[1] - SPECIAL_Y_TRANS[letter] *
                            (bb[3] - bb[1])))
    elif letter in DOWN_CHARS:
        #print('DOWN CASE: ', letter)
        #print(bb)
        transforms.append(
            psMat.translate(-bb[0], -bb[1] - 0.35 *
                            (bb[3] - bb[1])))  # 0,0 35% of its height
    else:
        transforms.append(psMat.translate(-bb[0], -bb[1]))

    # if letter in SPECIAL_CHARS:
    #     print('i: ', letter)
    #     print(bb)
    #     transforms.append(psMat.translate(300, 0) )
    # scaling
    if dy > 800:
        transforms.append(psMat.scale(newScale))
    if letter in MID_CHARS and letter not in SPECIAL_Y_SCALE:
        transforms.append(psMat.scale(0.5))
    elif letter in SPECIAL_Y_SCALE:
        transforms.append(psMat.scale(SPECIAL_Y_SCALE[letter]))

    #composing
    while len(transforms) > 1:
        el1 = transforms.popleft()
        el2 = transforms.popleft()
        transforms.appendleft(psMat.compose(el1, el2))
    g.transform(transforms[0])
    print('POST: ', letter)
    bb2 = g.boundingBox()
    g.width = bb2[2]
    g.simplify()
    # g.round()
    # g.cluster(0, 100)
    print(g.boundingBox(), g.width)

    return g
Esempio n. 30
0
def add_smalltriangle(_f):
    _f.selection.select(0x25bc)
    _f.copy()
    _f.selection.select(0x25be)
    _f.paste()
    _f.transform(psMat.compose(psMat.scale(0.64), psMat.translate(0, 68)))
    _f.copy()
    _f.selection.select(0x25b8)
    _f.paste()
    _f.transform(psMat.rotate(math.radians(90)))

    for g in _f.glyphs():
        if g.encoding == 0x25be or g.encoding == 0x25b8:
            g.width = 512
            g = align_to_center(g)

    return _f
Esempio n. 31
0
def modify_ellipsis(_f):
    """3点リーダーを半角にする
    DejaVuSansMono の U+22EF(⋯) をU+2026(…)、U+22EE(⋮)、U+22F0(⋰)、U+22F1(⋱)
    にコピーした上で回転させて生成

    三点リーダの文字幅について · Issue #41 · miiton/Cica https://github.com/miiton/Cica/issues/41
    """
    _f.selection.select(0x22ef)
    _f.copy()
    _f.selection.select(0x2026)
    _f.paste()
    _f.selection.select(0x22ee)
    _f.paste()
    _f.selection.select(0x22f0)
    _f.paste()
    _f.selection.select(0x22f1)
    _f.paste()
    for g in _f.glyphs("encoding"):
        if g.encoding < 0x22ee:
            continue
        elif g.encoding > 0x22f1:
            break
        elif g.encoding == 0x22ee:
            bb = g.boundingBox()
            cx = (bb[2] + bb[0]) / 2
            cy = (bb[3] + bb[1]) / 2
            trcen = psMat.translate(-cx, -cy)
            rotcen = psMat.compose(
                trcen,
                psMat.compose(psMat.rotate(math.radians(90)),
                              psMat.inverse(trcen)))
            g.transform(rotcen)
        elif g.encoding == 0x22f0:
            bb = g.boundingBox()
            cx = (bb[2] + bb[0]) / 2
            cy = (bb[3] + bb[1]) / 2
            trcen = psMat.translate(-cx, -cy)
            rotcen = psMat.compose(
                trcen,
                psMat.compose(psMat.rotate(math.radians(45)),
                              psMat.inverse(trcen)))
            g.transform(rotcen)
        elif g.encoding == 0x22f1:
            bb = g.boundingBox()
            cx = (bb[2] + bb[0]) / 2
            cy = (bb[3] + bb[1]) / 2
            trcen = psMat.translate(-cx, -cy)
            rotcen = psMat.compose(
                trcen,
                psMat.compose(psMat.rotate(math.radians(-45)),
                              psMat.inverse(trcen)))
            g.transform(rotcen)
    return _f
Esempio n. 32
0
def add_smalltriangle(_font):
    _font.selection.select(0x25bc)  # ▼ BLACK DOWN-POINTING TRIANGLE
    _font.copy()
    _font.selection.select(0x25be)  # ▾ BLACK DOWN-POINTING SMALL TRIANGLE
    _font.paste()
    _font.transform(psMat.compose(psMat.scale(0.64), psMat.translate(0, 68)))
    _font.copy()
    _font.selection.select(0x25b8)  # ▸ BLACK RIGHT-POINTING SMALL TRIANGLE
    _font.paste()
    _font.transform(psMat.rotate(math.radians(90)))

    for g in _font.glyphs():
        if g.encoding == 0x25be or g.encoding == 0x25b8:
            g.width = WIDTH // 2
            g.left_side_bearing = g.right_side_bearing = int(
                (g.left_side_bearing + g.right_side_bearing) / 2)
            g.width = WIDTH // 2

    return _font
Esempio n. 33
0
def operators(font, dejavu):
    for c in "⋆⋄⊕⊖⊗⊘⊙⊚⊞⊟⊠⊡":
        glyph = mvGlyph(font, dejavu, c)
        xform = mat.scale(1000 / 2048)
        glyph.transform(xform, ('round', ))
        glyph.width, glyph.vwidth = monosize
    for c in "≺≻≼≽⊀⊁⋠⋡≍≭≎≏":
        glyph = mvGlyph(font, dejavu, c)
        xform = mat.scale(1000 / 2048)
        glyph.transform(xform, ('round', ))
        xform = aroundCentroid(glyph, mat.scale(0.8))
        if c in "≼≽⋠⋡":
            xform = mat.compose(xform, mat.translate(0, -70))
        glyph.transform(xform, ('round', ))
        glyph.width, glyph.vwidth = monosize
    for c in "⊢":  #⊨⊩⊫":
        glyph = mvGlyph(font, dejavu, c)
        xform = mat.scale(1000 / 2048)
        glyph.transform(xform, ('round', ))
        glyph.width, glyph.vwidth = monosize
Esempio n. 34
0
def normalizeGlyph(g, letter):
    bb = g.boundingBox()
    dy = bb[3] - bb[1]
    newScale = 800 / (dy)
    transforms = []
    if letter in SPECIAL_CHARS:
        print('SPECIAL CASE: ', letter)
        print(bb)
        transforms.append(
            psMat.translate(-bb[0], -bb[1] - 0.5 * (bb[3] - bb[1])))
    else:
        transforms.append(psMat.translate(-bb[0], -bb[1]))

    if dy > 800:
        transforms.append(psMat.scale(newScale))
    if len(transforms) > 1:
        g.transform(psMat.compose(*transforms))
    else:
        g.transform(transforms[0])
    print(g.boundingBox())
    return g
Esempio n. 35
0
def _zenkaku_glyphs(font):
    hankaku_start = 0x21
    zenkaku_start = 0xFF01
    glyphs_num = 95
    trans = translate(WIDTH / 4, 0)
    font.selection.none()
    for i in range(0, glyphs_num):
        font.selection.select(i + hankaku_start)
        font.copy()
        font.selection.select(i + zenkaku_start)
        font.paste()
    font.selection.none()
    # select copied glyphs + 2 (0xff5f & 0xff60)
    font.selection.select(("ranges", "unicode"), zenkaku_start,
                          zenkaku_start + glyphs_num + 1)
    for glyph in list(font.selection.byGlyphs):
        paren = ZENKAKU_PARENTHESIS.get(glyph.encoding)
        if not paren:
            glyph.transform(trans)
        elif paren == "left":
            glyph.transform(compose(trans, trans))
        glyph.width = WIDTH
Esempio n. 36
0
def matRescale(origin_x, origin_y, scale_x, scale_y):
    return psMat.compose(
        psMat.translate(-origin_x, -origin_y),
        psMat.compose(psMat.scale(scale_x, scale_y),
                      psMat.translate(origin_x, origin_y)))
Esempio n. 37
0
fontforge.setPrefs('CoverageFormatsAllowed', 1)

ttfname = sys.argv[1]
middlefamily, weight = os.path.splitext(ttfname)[0].split('-')[1:]
modules = sys.argv[2:]

is_monospace = middlefamily[1] == 'm'

ascent = 860
descent = 140
em = ascent + descent

kanji_scale = 0.98
kanji_matrix = psMat.compose(
    psMat.translate(-em / 2, -ascent + em / 2), psMat.compose(
    psMat.scale(kanji_scale),
    psMat.translate(em / 2, ascent - em / 2)))

svg_uni_name = re.compile('^u[0-9A-F]{4,5}$', re.IGNORECASE)
feature_name = re.compile('^([- 0-9a-zA-Z]{4})_(uni[0-9A-F]{4,5})$')

alt_glyphs = {}
def svgname_to_glyphname(name):
    if svg_uni_name.match(name):
        return (int(name[1:], 16),)
    m = feature_name.match(name)
    if m:
        tag = m.group(1)
        name = m.group(2)
        tagged_name = "%s.%s" % (name, tag)
        if not (tag in alt_glyphs):
Esempio n. 38
0
descent = 234

bl = 0
br = width
bw = br - bl
cx = (bl + br) / 2.0
bb = -descent
bt = ascent
bh = bt - bb
cy = (bb + bt) / 2.0
swl2 = 72 / 2.0
swh2 = 146 / 2.0
dg2 = 118 / 2.0
dd = dg2 + 2 * swl2

xrefT = psMat.compose(psMat.translate(-2 * cx, 0), psMat.scale(-1, 1))
yrefT = psMat.compose(psMat.translate(0, -2 * cy), psMat.scale(1, -1))

def addchar(font, cp, contours):
    glyph = font.createChar(cp, 'uni{:04X}'.format(cp))
    pen = glyph.glyphPen()
    for c in contours:
        c.draw(pen)
    pen = None
    glyph.removeOverlap()
    glyph.simplify(1, ('forcelines',))
    glyph.round()
    glyph.correctDirection()
    glyph.canonicalStart()
    glyph.canonicalContours()
    glyph.width = width
Esempio n. 39
0
    def patch(self):
        for target_font in self.target_fonts:
            source_font = self.source_font
            target_font_em_original = target_font.em
            target_font.em = 2048
            target_font.encoding = 'ISO10646'

            # Rename font
            if self.rename_font:
                target_font.familyname += ' for Kovid'
                target_font.fullname += ' for Kovid'
                fontname, style = re.match("^([^-]*)(?:(-.*))?$",
                                           target_font.fontname).groups()
                target_font.fontname = fontname + 'ForKovid'
                if style is not None:
                    target_font.fontname += style
                target_font.appendSFNTName('English (US)', 'Preferred Family',
                                           target_font.familyname)
                target_font.appendSFNTName('English (US)', 'Compatible Full',
                                           target_font.fullname)

            source_bb = source_font['block'].boundingBox()
            target_bb = [0, 0, 0, 0]
            target_font_width = 0

            # Find the biggest char width and height in the Latin-1 extended range and the box drawing range
            # This isn't ideal, but it works fairly well - some fonts may need tuning after patching
            for cp in chain(range(0x00, 0x17f), range(0x2500, 0x2600)):
                try:
                    bbox = target_font[cp].boundingBox()
                except TypeError:
                    continue
                if not target_font_width:
                    target_font_width = target_font[cp].width
                if bbox[0] < target_bb[0]:
                    target_bb[0] = bbox[0]
                if bbox[1] < target_bb[1]:
                    target_bb[1] = bbox[1]
                if bbox[2] > target_bb[2]:
                    target_bb[2] = bbox[2]
                if bbox[3] > target_bb[3]:
                    target_bb[3] = bbox[3]

            # Find source and target size difference for scaling
            x_ratio = (target_bb[2] - target_bb[0]) / (source_bb[2] -
                                                       source_bb[0])
            y_ratio = (target_bb[3] - target_bb[1]) / (source_bb[3] -
                                                       source_bb[1])
            scale = psMat.scale(x_ratio, y_ratio)

            # Find source and target midpoints for translating
            x_diff = target_bb[0] - source_bb[0]
            y_diff = target_bb[1] - source_bb[1]
            translate = psMat.translate(x_diff, y_diff)
            transform = psMat.compose(scale, translate)

            # Create new glyphs from symbol font
            for source_glyph in source_font.glyphs():
                if source_glyph == source_font['block']:
                    # Skip the symbol font block glyph
                    continue

                # Select and copy symbol from its encoding point
                source_font.selection.select(source_glyph.encoding)
                source_font.copy()

                # Select and paste symbol to its unicode code point
                target_font.selection.select(source_glyph.unicode)
                target_font.paste()

                # Transform the glyph
                target_font.transform(transform)

                # Reset the font's glyph width so it's still considered monospaced
                target_font[source_glyph.unicode].width = target_font_width

            target_font.em = target_font_em_original

            # Generate patched font
            extension = os.path.splitext(target_font.path)[1]
            if extension.lower() not in ['.ttf', '.otf']:
                # Default to OpenType if input is not TrueType/OpenType
                extension = '.otf'
            target_font.generate(
                os.path.join(self.destdir,
                             '{0}{1}'.format(target_font.fullname, extension)))
Esempio n. 40
0
def matRescale(origin_x, origin_y, scale_x, scale_y):
    return psMat.compose(
        psMat.translate(-origin_x, -origin_y), psMat.compose(
        psMat.scale(scale_x, scale_y), 
        psMat.translate(origin_x, origin_y)))
Esempio n. 41
0
	def patch(self):
		for target_font in self.target_fonts:
			source_font = self.source_font
			target_font_em_original = target_font.em
			target_font.em = 2048
			target_font.encoding = 'ISO10646'

			# Rename font
			if self.rename_font:
				target_font.familyname += ' for Powerline'
				target_font.fullname += ' for Powerline'
				target_font.fontname += 'ForPowerline'
				target_font.appendSFNTName('English (US)', 'Preferred Family', target_font.familyname)
				target_font.appendSFNTName('English (US)', 'Compatible Full', target_font.fullname)

			source_bb = source_font['block'].boundingBox()
			target_bb = [0, 0, 0, 0]
			target_font_width = 0

			# Find the biggest char width and height in the Latin-1 extended range and the box drawing range
			# This isn't ideal, but it works fairly well - some fonts may need tuning after patching
			for cp in range(0x00, 0x17f) + range(0x2500, 0x2600):
				try:
					bbox = target_font[cp].boundingBox()
				except TypeError:
					continue
				if not target_font_width:
					target_font_width = target_font[cp].width
				if bbox[0] < target_bb[0]:
					target_bb[0] = bbox[0]
				if bbox[1] < target_bb[1]:
					target_bb[1] = bbox[1]
				if bbox[2] > target_bb[2]:
					target_bb[2] = bbox[2]
				if bbox[3] > target_bb[3]:
					target_bb[3] = bbox[3]

			# Find source and target size difference for scaling
			x_ratio = (target_bb[2] - target_bb[0]) / (source_bb[2] - source_bb[0])
			y_ratio = (target_bb[3] - target_bb[1]) / (source_bb[3] - source_bb[1])
			scale = psMat.scale(x_ratio, y_ratio)

			# Find source and target midpoints for translating
			x_diff = target_bb[0] - source_bb[0]
			y_diff = target_bb[1] - source_bb[1]
			translate = psMat.translate(x_diff, y_diff)
			transform = psMat.compose(scale, translate)

			# Create new glyphs from symbol font
			for source_glyph in source_font.glyphs():
				if source_glyph == source_font['block']:
					# Skip the symbol font block glyph
					continue

				# Select and copy symbol from its encoding point
				source_font.selection.select(source_glyph.encoding)
				source_font.copy()

				# Select and paste symbol to its unicode code point
				target_font.selection.select(source_glyph.unicode)
				target_font.paste()

				# Transform the glyph
				target_font.transform(transform)

				# Reset the font's glyph width so it's still considered monospaced
				target_font[source_glyph.unicode].width = target_font_width

			target_font.em = target_font_em_original

			# Generate patched font
			target_font.generate('{0}.otf'.format(target_font.fullname))
Esempio n. 42
0
        if char == -1:
            char = letter.replace("&#", "").replace(";", "")
            letter = fontforge.nameFromUnicode(int(char))
        print "letter: %s" % letter
        print "char: %s" % char
        importGlyph(f, letter, int(char))


bottom = font["h"].boundingBox()[1]
top = font["h"].boundingBox()[3]

height = top - bottom
scale_ratio = 780 / height
scale_matrix = psMat.scale(scale_ratio)
translate_matrix = psMat.translate(0, font.descent * scale_ratio)
matrix = psMat.compose(scale_matrix, translate_matrix)
print matrix

# Series of transformations on all glyphs
font.selection.all()
font.transform(matrix)
font.autoWidth(100, 30) 
font.autoHint()

autokern(font)


font.descent = 216
font.ascent = 780

# create the output ufo file
Esempio n. 43
0
def copy_glyphs(glyphs, source_font, target_font, new_font, new_suffix,
                overwrite):
    target_font_em_original = target_font.em
    target_font.em = 2048
    target_font.encoding = 'ISO10646'

    # Rename font
    target_font.familyname += new_suffix
    target_font.fullname += new_suffix
    fontname, style = re.match("^([^-]*)(?:(-.*))?$",
                               target_font.fontname).groups()
    target_font.fontname = fontname + new_suffix.replace(' ', '')
    if style is not None:
        target_font.fontname += style
    target_font.appendSFNTName('English (US)', 'Preferred Family',
                               target_font.familyname)
    target_font.appendSFNTName('English (US)', 'Compatible Full',
                               target_font.fullname)

    # range(0x00, 0x17f) + range(0x2500, 0x2600):
    ipdb.set_trace()
    source_bb = source_font['block'].boundingBox()
    target_bb = [0, 0, 0, 0]
    target_font_width = 0

    # Find the biggest char width and height in the Latin-1 extended range and the box drawing range
    # This isn't ideal, but it works fairly well - some fonts may need tuning after patching
    for cp in range(0x00, 0x17f) + range(0x2500, 0x2600):
        try:
            bbox = target_font[cp].boundingBox()
        except TypeError:
            continue
        if not target_font_width:
            target_font_width = target_font[cp].width
        if bbox[0] < target_bb[0]:
            target_bb[0] = bbox[0]
        if bbox[1] < target_bb[1]:
            target_bb[1] = bbox[1]
        if bbox[2] > target_bb[2]:
            target_bb[2] = bbox[2]
        if bbox[3] > target_bb[3]:
            target_bb[3] = bbox[3]

    # Find source and target size difference for scaling
    x_ratio = (target_bb[2] - target_bb[0]) / (source_bb[2] - source_bb[0])
    y_ratio = (target_bb[3] - target_bb[1]) / (source_bb[3] - source_bb[1])
    scale = psMat.scale(x_ratio, y_ratio)

    # Find source and target midpoints for translating
    x_diff = target_bb[0] - source_bb[0]
    y_diff = target_bb[1] - source_bb[1]
    translate = psMat.translate(x_diff, y_diff)
    transform = psMat.compose(scale, translate)
    sys.stderr.write("Source: %i %i %i %i\n" % (source_bb[0], source_bb[1], source_bb[2], source_bb[3]))
    sys.stderr.write("Target: %i %i %i %i\n" % (target_bb[0], target_bb[1], target_bb[2], target_bb[3]))
    sys.stderr.write("Offset: %.2f %.2f, Ratio: %.2f %.2f\n" % (x_diff, y_diff, x_ratio, y_ratio))
    # print(scale)
    # print(translate)
    # print(transform)

    # Create new glyphs from symbol font
    for source_glyph in source_font.glyphs():
        if source_glyph == source_font['block']:
            # Skip the symbol font block glyph
            continue

        # Select and copy symbol from its encoding point
        source_font.selection.select(source_glyph.encoding)
        source_font.copy()

        # Select and paste symbol to its unicode code point
        target_font.selection.select(source_glyph.unicode)
        target_font.paste()

        # Transform the glyph
        target_font.transform(transform)

        # Reset the font's glyph width so it's still considered monospaced
        target_font[source_glyph.unicode].width = target_font_width

    target_font.em = target_font_em_original

    # Generate patched font
    extension = os.path.splitext(target_font.path)[1]
    if extension.lower() not in ['.ttf', '.otf']:
        # Default to OpenType if input is not TrueType/OpenType
        extension = '.otf'
    target_font.generate('{0}{1}'.format(target_font.fullname, extension))
Esempio n. 44
0
def patch_one_font(source_font, target_font, rename_font=True):
	target_font_em_original = target_font.em
	target_font.em = 2048
	target_font.encoding = 'ISO10646'

	# Rename font
	if rename_font:
		target_font.familyname += ' for Powerline'
		target_font.fullname += ' for Powerline'
		fontname, style = FONT_NAME_RE.match(target_font.fontname).groups()
		target_font.fontname = fontname + 'ForPowerline'
		if style is not None:
			target_font.fontname += style
		target_font.appendSFNTName(
			'English (US)', 'Preferred Family', target_font.familyname)
		target_font.appendSFNTName(
			'English (US)', 'Compatible Full', target_font.fullname)

	source_bb = source_font['block'].boundingBox()
	target_bb = [0, 0, 0, 0]
	target_font_width = 0

	# Find the biggest char width and height in the Latin-1 extended range and
	# the box drawing range This isn't ideal, but it works fairly well - some
	# fonts may need tuning after patching.
	for cp in chain(range(0x00, 0x17f), range(0x2500, 0x2600)):
		try:
			bbox = target_font[cp].boundingBox()
		except TypeError:
			continue
		if not target_font_width:
			target_font_width = target_font[cp].width
		if bbox[0] < target_bb[0]:
			target_bb[0] = bbox[0]
		if bbox[1] < target_bb[1]:
			target_bb[1] = bbox[1]
		if bbox[2] > target_bb[2]:
			target_bb[2] = bbox[2]
		if bbox[3] > target_bb[3]:
			target_bb[3] = bbox[3]

	# Find source and target size difference for scaling
	x_ratio = (target_bb[2] - target_bb[0]) / (source_bb[2] - source_bb[0])
	y_ratio = (target_bb[3] - target_bb[1]) / (source_bb[3] - source_bb[1])
	scale = psMat.scale(x_ratio, y_ratio)

	# Find source and target midpoints for translating
	x_diff = target_bb[0] - source_bb[0]
	y_diff = target_bb[1] - source_bb[1]
	translate = psMat.translate(x_diff, y_diff)
	transform = psMat.compose(scale, translate)

	# Create new glyphs from symbol font
	for source_glyph in source_font.glyphs():
		if source_glyph == source_font['block']:
			# Skip the symbol font block glyph
			continue

		# Select and copy symbol from its encoding point
		source_font.selection.select(source_glyph.encoding)
		source_font.copy()

		# Select and paste symbol to its unicode code point
		target_font.selection.select(source_glyph.unicode)
		target_font.paste()

		# Transform the glyph
		target_font.transform(transform)

		# Reset the font's glyph width so it's still considered monospaced
		target_font[source_glyph.unicode].width = target_font_width

	target_font.em = target_font_em_original

	# FIXME: Menlo and Meslo font do have these substitutes, but U+FB01 and
	#        U+FB02 still do not show up for fi and fl.
	if 0xFB01 in target_font:
		target_font[0xFB01].removePosSub('*')  # fi ligature
	if 0xFB02 in target_font:
		target_font[0xFB02].removePosSub('*')  # fl ligature

	# Generate patched font
	extension = os.path.splitext(target_font.path)[1]
	if extension.lower() not in ['.ttf', '.otf']:
		# Default to OpenType if input is not TrueType/OpenType
		extension = '.otf'
	target_font.generate('{0}{1}'.format(target_font.fullname, extension))