162 lines
5.4 KiB
Python
162 lines
5.4 KiB
Python
|
#!/usr/bin/env python3
|
||
|
'''FontForge: Copy glyphs from one font to another, without using ffbuilder'''
|
||
|
__url__ = 'https://github.com/silnrsi/pysilfont'
|
||
|
__copyright__ = 'Copyright (c) 2015-2019 SIL International (https://www.sil.org)'
|
||
|
__license__ = 'Released under the MIT License (https://opensource.org/licenses/MIT)'
|
||
|
__author__ = 'Martin Hosken'
|
||
|
|
||
|
from silfont.core import execute
|
||
|
import psMat
|
||
|
import io
|
||
|
|
||
|
|
||
|
''' This will need updating, since FontForge is no longer supported as a tool by execute() So:
|
||
|
- ifont and ofont will need to be changed to have type 'filename'
|
||
|
- ifont will then need to be opened using fontforge.open
|
||
|
- The font will need to be saved with font.save
|
||
|
- execute will need to be called with the tool set to None instead of "FF"
|
||
|
'''
|
||
|
|
||
|
|
||
|
argspec = [
|
||
|
('ifont',{'help': 'Input font file'}, {'type': 'infont'}),
|
||
|
('ofont',{'help': 'Output font file','nargs': '?' }, {'type': 'outfont', 'def': 'new'}),
|
||
|
('-i','--input',{'help': 'Font to get glyphs from', 'required' : True}, {'type': 'infont'}),
|
||
|
('-r','--range',{'help': 'StartUnicode..EndUnicode no spaces, e.g. 20..7E', 'action' : 'append'}, {}),
|
||
|
('--rangefile',{'help': 'File with USVs e.g. 20 or a range e.g. 20..7E or both', 'action' : 'append'}, {}),
|
||
|
('-n','--name',{'help': 'Include glyph named name', 'action' : 'append'}, {}),
|
||
|
('--namefile',{'help': 'File with glyph names', 'action' : 'append'}, {}),
|
||
|
('-a','--anchors',{'help' : 'Copy across anchor points', 'action' : 'store_true'}, {}),
|
||
|
('-f','--force',{'help' : 'Overwrite existing glyphs in the font', 'action' : 'store_true'}, {}),
|
||
|
('-s','--scale',{'type' : float, 'help' : 'Scale glyphs by this factor'}, {})
|
||
|
]
|
||
|
|
||
|
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)
|
||
|
|
||
|
def doit(args) :
|
||
|
font = args.ifont
|
||
|
infont = args.input
|
||
|
font.encoding = "Original"
|
||
|
infont.encoding = "Original" # compact the font so findEncodingSlot will work
|
||
|
infont.layers["Fore"].is_quadratic = font.layers["Fore"].is_quadratic
|
||
|
|
||
|
# list of glyphs to copy
|
||
|
glist = list()
|
||
|
|
||
|
# glyphs specified on the command line
|
||
|
for n in args.name or [] :
|
||
|
glist.append(n)
|
||
|
|
||
|
# glyphs specified in a file
|
||
|
for filename in args.namefile or [] :
|
||
|
namefile = io.open(filename, 'r')
|
||
|
for line in namefile :
|
||
|
# ignore comments
|
||
|
line = line.partition('#')[0]
|
||
|
line = line.strip()
|
||
|
|
||
|
# ignore blank lines
|
||
|
if (line == ''):
|
||
|
continue
|
||
|
|
||
|
glist.append(line)
|
||
|
|
||
|
# copy glyphs by name
|
||
|
reportErrors = True
|
||
|
while len(glist) :
|
||
|
tglist = glist[:]
|
||
|
glist = []
|
||
|
for n in tglist:
|
||
|
if n in font and not args.force :
|
||
|
if reportErrors :
|
||
|
print("Glyph {} already present. Skipping".format(n))
|
||
|
continue
|
||
|
if n not in infont :
|
||
|
print("Can't find glyph {}".format(n))
|
||
|
continue
|
||
|
g = infont[n]
|
||
|
glist.extend(copyglyph(font, infont, g, -1, args))
|
||
|
reportErrors = False
|
||
|
|
||
|
# list of characters to copy
|
||
|
ulist = list()
|
||
|
|
||
|
# characters specified on the command line
|
||
|
for r in args.range or [] :
|
||
|
(rstart, rend) = [int(x, 16) for x in r.split('..')]
|
||
|
for u in range(rstart, rend + 1) :
|
||
|
ulist.append(u)
|
||
|
|
||
|
# characters specified in a file
|
||
|
for filename in args.rangefile or [] :
|
||
|
rangefile = io.open(filename, 'r')
|
||
|
for line in rangefile :
|
||
|
# ignore comments
|
||
|
line = line.partition('#')[0]
|
||
|
line = line.strip()
|
||
|
|
||
|
# ignore blank lines
|
||
|
if (line == ''):
|
||
|
continue
|
||
|
|
||
|
# obtain USVs
|
||
|
try:
|
||
|
(rstart, rend) = line.split('..')
|
||
|
except ValueError:
|
||
|
rstart = line
|
||
|
rend = line
|
||
|
|
||
|
rstart = int(rstart, 16)
|
||
|
rend = int(rend, 16)
|
||
|
|
||
|
for u in range(rstart, rend + 1):
|
||
|
ulist.append(u)
|
||
|
|
||
|
# copy the characters from the generated list
|
||
|
for u in ulist:
|
||
|
o = font.findEncodingSlot(u)
|
||
|
if o != -1 and not args.force :
|
||
|
print("Glyph for {:x} already present. Skipping".format(u))
|
||
|
continue
|
||
|
e = infont.findEncodingSlot(u)
|
||
|
if e == -1 :
|
||
|
print("Can't find glyph for {:04x}".format(u))
|
||
|
continue
|
||
|
g = infont[e]
|
||
|
copyglyph(font, infont, g, u, args)
|
||
|
|
||
|
return font
|
||
|
|
||
|
def cmd() : execute("FF",doit,argspec)
|
||
|
if __name__ == "__main__": cmd()
|