-
Notifications
You must be signed in to change notification settings - Fork 27
/
otf.py
118 lines (97 loc) · 3.72 KB
/
otf.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# This file contains code to handle .otf files, which we do by converting to ttf files
# This code is heavily based on https://github.com/awesometoolbox/otf2ttf/blob/master/src/otf2ttf/cli.py
# and https://github.com/SwagLyrics/SwagLyrics-For-Spotify/blob/master/swaglyrics/__init__.py#L8-L32
import logging
import os
from fontTools.pens.cu2quPen import Cu2QuPen
from fontTools.misc.cliTools import makeOutputFileName
from fontTools.pens.ttGlyphPen import TTGlyphPen
from fontTools.ttLib import TTFont, newTable
from fontTools.cu2qu import errors # noqa - not used here, but this makes sure that pyinstaller gets it
from pathutils import appdata_dir
log = logging.getLogger("cewe2pdf.config")
# default approximation error, measured in UPEM
MAX_ERR = 1.0
# default 'post' table format
POST_FORMAT = 2.0
# assuming the input contours' direction is correctly set (counter-clockwise),
# we just flip it to clockwise
REVERSE_DIRECTION = True
def glyphs_to_quadratic(
glyphs, max_err=MAX_ERR, reverse_direction=REVERSE_DIRECTION
):
quadGlyphs = {}
for gname in glyphs.keys():
glyph = glyphs[gname]
ttPen = TTGlyphPen(glyphs)
cu2quPen = Cu2QuPen(
ttPen, max_err, reverse_direction=reverse_direction
)
glyph.draw(cu2quPen)
quadGlyphs[gname] = ttPen.glyph()
return quadGlyphs
def otf_to_ttf(ttFont, post_format=POST_FORMAT, **kwargs):
assert ttFont.sfntVersion == "OTTO"
assert "CFF " in ttFont
glyphOrder = ttFont.getGlyphOrder()
ttFont["loca"] = newTable("loca")
ttFont["glyf"] = glyf = newTable("glyf")
glyf.glyphOrder = glyphOrder
glyf.glyphs = glyphs_to_quadratic(ttFont.getGlyphSet(), **kwargs)
del ttFont["CFF "]
glyf.compile(ttFont)
ttFont["maxp"] = 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()
)
maxp.compile(ttFont)
post = ttFont["post"]
post.formatType = post_format
post.extraNames = []
post.mapping = {}
post.glyphOrder = glyphOrder
try:
post.compile(ttFont)
except OverflowError:
post.formatType = 3
log.warning("Dropping glyph names, they do not fit in 'post' table.")
ttFont.sfntVersion = "\000\001\000\000"
def getTtfsFromOtfs(otfFiles, ttfdirPath=None):
resultingTtfFiles = []
if ttfdirPath is None:
ttfdirPath = appdata_dir()
if not os.path.exists(ttfdirPath):
os.mkdir(ttfdirPath)
for otfFile in otfFiles:
if "LiebeGerda-BoldItalic" in otfFile:
log.info("LiebeGerda-BoldItalic not available: the otf->ttf conversion hangs!")
continue # the conversion code hangs on this font!
ttfFile = makeOutputFileName(
otfFile,
outputDir=ttfdirPath,
extension=".ttf",
overWrite=True, # options.overwrite
)
if os.path.exists(ttfFile):
log.info(f"Accepting otf->ttf font conversion: {ttfFile}")
else:
log.warning(f"One-time font conversion otf->ttf: {ttfFile}")
font = TTFont(otfFile, fontNumber=0) # options.face_index
otf_to_ttf(
font,
post_format=POST_FORMAT, # options.post_format
max_err=MAX_ERR, # options.max_error
reverse_direction=REVERSE_DIRECTION, # options.reverse_direction
)
font.save(ttfFile)
resultingTtfFiles.append(ttfFile)
return resultingTtfFiles