fonttools 4.60.2__cp311-cp311-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fontTools/__init__.py +8 -0
- fontTools/__main__.py +35 -0
- fontTools/afmLib.py +439 -0
- fontTools/agl.py +5233 -0
- fontTools/annotations.py +30 -0
- fontTools/cffLib/CFF2ToCFF.py +258 -0
- fontTools/cffLib/CFFToCFF2.py +305 -0
- fontTools/cffLib/__init__.py +3694 -0
- fontTools/cffLib/specializer.py +927 -0
- fontTools/cffLib/transforms.py +495 -0
- fontTools/cffLib/width.py +210 -0
- fontTools/colorLib/__init__.py +0 -0
- fontTools/colorLib/builder.py +664 -0
- fontTools/colorLib/errors.py +2 -0
- fontTools/colorLib/geometry.py +143 -0
- fontTools/colorLib/table_builder.py +223 -0
- fontTools/colorLib/unbuilder.py +81 -0
- fontTools/config/__init__.py +90 -0
- fontTools/cu2qu/__init__.py +15 -0
- fontTools/cu2qu/__main__.py +6 -0
- fontTools/cu2qu/benchmark.py +54 -0
- fontTools/cu2qu/cli.py +198 -0
- fontTools/cu2qu/cu2qu.c +15817 -0
- fontTools/cu2qu/cu2qu.cp311-win32.pyd +0 -0
- fontTools/cu2qu/cu2qu.py +563 -0
- fontTools/cu2qu/errors.py +77 -0
- fontTools/cu2qu/ufo.py +363 -0
- fontTools/designspaceLib/__init__.py +3343 -0
- fontTools/designspaceLib/__main__.py +6 -0
- fontTools/designspaceLib/split.py +475 -0
- fontTools/designspaceLib/statNames.py +260 -0
- fontTools/designspaceLib/types.py +147 -0
- fontTools/encodings/MacRoman.py +258 -0
- fontTools/encodings/StandardEncoding.py +258 -0
- fontTools/encodings/__init__.py +1 -0
- fontTools/encodings/codecs.py +135 -0
- fontTools/feaLib/__init__.py +4 -0
- fontTools/feaLib/__main__.py +78 -0
- fontTools/feaLib/ast.py +2143 -0
- fontTools/feaLib/builder.py +1814 -0
- fontTools/feaLib/error.py +22 -0
- fontTools/feaLib/lexer.c +17029 -0
- fontTools/feaLib/lexer.cp311-win32.pyd +0 -0
- fontTools/feaLib/lexer.py +287 -0
- fontTools/feaLib/location.py +12 -0
- fontTools/feaLib/lookupDebugInfo.py +12 -0
- fontTools/feaLib/parser.py +2394 -0
- fontTools/feaLib/variableScalar.py +118 -0
- fontTools/fontBuilder.py +1014 -0
- fontTools/help.py +36 -0
- fontTools/merge/__init__.py +248 -0
- fontTools/merge/__main__.py +6 -0
- fontTools/merge/base.py +81 -0
- fontTools/merge/cmap.py +173 -0
- fontTools/merge/layout.py +526 -0
- fontTools/merge/options.py +85 -0
- fontTools/merge/tables.py +352 -0
- fontTools/merge/unicode.py +78 -0
- fontTools/merge/util.py +143 -0
- fontTools/misc/__init__.py +1 -0
- fontTools/misc/arrayTools.py +424 -0
- fontTools/misc/bezierTools.c +39731 -0
- fontTools/misc/bezierTools.cp311-win32.pyd +0 -0
- fontTools/misc/bezierTools.py +1500 -0
- fontTools/misc/classifyTools.py +170 -0
- fontTools/misc/cliTools.py +53 -0
- fontTools/misc/configTools.py +349 -0
- fontTools/misc/cython.py +27 -0
- fontTools/misc/dictTools.py +83 -0
- fontTools/misc/eexec.py +119 -0
- fontTools/misc/encodingTools.py +72 -0
- fontTools/misc/enumTools.py +23 -0
- fontTools/misc/etree.py +456 -0
- fontTools/misc/filenames.py +245 -0
- fontTools/misc/filesystem/__init__.py +68 -0
- fontTools/misc/filesystem/_base.py +134 -0
- fontTools/misc/filesystem/_copy.py +45 -0
- fontTools/misc/filesystem/_errors.py +54 -0
- fontTools/misc/filesystem/_info.py +75 -0
- fontTools/misc/filesystem/_osfs.py +164 -0
- fontTools/misc/filesystem/_path.py +67 -0
- fontTools/misc/filesystem/_subfs.py +92 -0
- fontTools/misc/filesystem/_tempfs.py +34 -0
- fontTools/misc/filesystem/_tools.py +34 -0
- fontTools/misc/filesystem/_walk.py +55 -0
- fontTools/misc/filesystem/_zipfs.py +204 -0
- fontTools/misc/fixedTools.py +253 -0
- fontTools/misc/intTools.py +25 -0
- fontTools/misc/iterTools.py +12 -0
- fontTools/misc/lazyTools.py +42 -0
- fontTools/misc/loggingTools.py +543 -0
- fontTools/misc/macCreatorType.py +56 -0
- fontTools/misc/macRes.py +261 -0
- fontTools/misc/plistlib/__init__.py +681 -0
- fontTools/misc/plistlib/py.typed +0 -0
- fontTools/misc/psCharStrings.py +1511 -0
- fontTools/misc/psLib.py +398 -0
- fontTools/misc/psOperators.py +572 -0
- fontTools/misc/py23.py +96 -0
- fontTools/misc/roundTools.py +110 -0
- fontTools/misc/sstruct.py +227 -0
- fontTools/misc/symfont.py +242 -0
- fontTools/misc/testTools.py +233 -0
- fontTools/misc/textTools.py +156 -0
- fontTools/misc/timeTools.py +88 -0
- fontTools/misc/transform.py +516 -0
- fontTools/misc/treeTools.py +45 -0
- fontTools/misc/vector.py +147 -0
- fontTools/misc/visitor.py +158 -0
- fontTools/misc/xmlReader.py +188 -0
- fontTools/misc/xmlWriter.py +231 -0
- fontTools/mtiLib/__init__.py +1400 -0
- fontTools/mtiLib/__main__.py +5 -0
- fontTools/otlLib/__init__.py +1 -0
- fontTools/otlLib/builder.py +3465 -0
- fontTools/otlLib/error.py +11 -0
- fontTools/otlLib/maxContextCalc.py +96 -0
- fontTools/otlLib/optimize/__init__.py +53 -0
- fontTools/otlLib/optimize/__main__.py +6 -0
- fontTools/otlLib/optimize/gpos.py +439 -0
- fontTools/pens/__init__.py +1 -0
- fontTools/pens/areaPen.py +52 -0
- fontTools/pens/basePen.py +475 -0
- fontTools/pens/boundsPen.py +98 -0
- fontTools/pens/cairoPen.py +26 -0
- fontTools/pens/cocoaPen.py +26 -0
- fontTools/pens/cu2quPen.py +325 -0
- fontTools/pens/explicitClosingLinePen.py +101 -0
- fontTools/pens/filterPen.py +433 -0
- fontTools/pens/freetypePen.py +462 -0
- fontTools/pens/hashPointPen.py +89 -0
- fontTools/pens/momentsPen.c +13378 -0
- fontTools/pens/momentsPen.cp311-win32.pyd +0 -0
- fontTools/pens/momentsPen.py +879 -0
- fontTools/pens/perimeterPen.py +69 -0
- fontTools/pens/pointInsidePen.py +192 -0
- fontTools/pens/pointPen.py +643 -0
- fontTools/pens/qtPen.py +29 -0
- fontTools/pens/qu2cuPen.py +105 -0
- fontTools/pens/quartzPen.py +43 -0
- fontTools/pens/recordingPen.py +335 -0
- fontTools/pens/reportLabPen.py +79 -0
- fontTools/pens/reverseContourPen.py +96 -0
- fontTools/pens/roundingPen.py +130 -0
- fontTools/pens/statisticsPen.py +312 -0
- fontTools/pens/svgPathPen.py +310 -0
- fontTools/pens/t2CharStringPen.py +88 -0
- fontTools/pens/teePen.py +55 -0
- fontTools/pens/transformPen.py +115 -0
- fontTools/pens/ttGlyphPen.py +335 -0
- fontTools/pens/wxPen.py +29 -0
- fontTools/qu2cu/__init__.py +15 -0
- fontTools/qu2cu/__main__.py +7 -0
- fontTools/qu2cu/benchmark.py +56 -0
- fontTools/qu2cu/cli.py +125 -0
- fontTools/qu2cu/qu2cu.c +16682 -0
- fontTools/qu2cu/qu2cu.cp311-win32.pyd +0 -0
- fontTools/qu2cu/qu2cu.py +405 -0
- fontTools/subset/__init__.py +4096 -0
- fontTools/subset/__main__.py +6 -0
- fontTools/subset/cff.py +184 -0
- fontTools/subset/svg.py +253 -0
- fontTools/subset/util.py +25 -0
- fontTools/svgLib/__init__.py +3 -0
- fontTools/svgLib/path/__init__.py +65 -0
- fontTools/svgLib/path/arc.py +154 -0
- fontTools/svgLib/path/parser.py +322 -0
- fontTools/svgLib/path/shapes.py +183 -0
- fontTools/t1Lib/__init__.py +648 -0
- fontTools/tfmLib.py +460 -0
- fontTools/ttLib/__init__.py +30 -0
- fontTools/ttLib/__main__.py +148 -0
- fontTools/ttLib/macUtils.py +54 -0
- fontTools/ttLib/removeOverlaps.py +395 -0
- fontTools/ttLib/reorderGlyphs.py +285 -0
- fontTools/ttLib/scaleUpem.py +436 -0
- fontTools/ttLib/sfnt.py +661 -0
- fontTools/ttLib/standardGlyphOrder.py +271 -0
- fontTools/ttLib/tables/B_A_S_E_.py +14 -0
- fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
- fontTools/ttLib/tables/C_B_D_T_.py +113 -0
- fontTools/ttLib/tables/C_B_L_C_.py +19 -0
- fontTools/ttLib/tables/C_F_F_.py +61 -0
- fontTools/ttLib/tables/C_F_F__2.py +26 -0
- fontTools/ttLib/tables/C_O_L_R_.py +165 -0
- fontTools/ttLib/tables/C_P_A_L_.py +305 -0
- fontTools/ttLib/tables/D_S_I_G_.py +158 -0
- fontTools/ttLib/tables/D__e_b_g.py +35 -0
- fontTools/ttLib/tables/DefaultTable.py +49 -0
- fontTools/ttLib/tables/E_B_D_T_.py +835 -0
- fontTools/ttLib/tables/E_B_L_C_.py +718 -0
- fontTools/ttLib/tables/F_F_T_M_.py +52 -0
- fontTools/ttLib/tables/F__e_a_t.py +149 -0
- fontTools/ttLib/tables/G_D_E_F_.py +13 -0
- fontTools/ttLib/tables/G_M_A_P_.py +148 -0
- fontTools/ttLib/tables/G_P_K_G_.py +133 -0
- fontTools/ttLib/tables/G_P_O_S_.py +14 -0
- fontTools/ttLib/tables/G_S_U_B_.py +13 -0
- fontTools/ttLib/tables/G_V_A_R_.py +5 -0
- fontTools/ttLib/tables/G__l_a_t.py +235 -0
- fontTools/ttLib/tables/G__l_o_c.py +85 -0
- fontTools/ttLib/tables/H_V_A_R_.py +13 -0
- fontTools/ttLib/tables/J_S_T_F_.py +13 -0
- fontTools/ttLib/tables/L_T_S_H_.py +58 -0
- fontTools/ttLib/tables/M_A_T_H_.py +13 -0
- fontTools/ttLib/tables/M_E_T_A_.py +352 -0
- fontTools/ttLib/tables/M_V_A_R_.py +13 -0
- fontTools/ttLib/tables/O_S_2f_2.py +752 -0
- fontTools/ttLib/tables/S_I_N_G_.py +99 -0
- fontTools/ttLib/tables/S_T_A_T_.py +15 -0
- fontTools/ttLib/tables/S_V_G_.py +223 -0
- fontTools/ttLib/tables/S__i_l_f.py +1040 -0
- fontTools/ttLib/tables/S__i_l_l.py +92 -0
- fontTools/ttLib/tables/T_S_I_B_.py +13 -0
- fontTools/ttLib/tables/T_S_I_C_.py +14 -0
- fontTools/ttLib/tables/T_S_I_D_.py +13 -0
- fontTools/ttLib/tables/T_S_I_J_.py +13 -0
- fontTools/ttLib/tables/T_S_I_P_.py +13 -0
- fontTools/ttLib/tables/T_S_I_S_.py +13 -0
- fontTools/ttLib/tables/T_S_I_V_.py +26 -0
- fontTools/ttLib/tables/T_S_I__0.py +70 -0
- fontTools/ttLib/tables/T_S_I__1.py +163 -0
- fontTools/ttLib/tables/T_S_I__2.py +17 -0
- fontTools/ttLib/tables/T_S_I__3.py +22 -0
- fontTools/ttLib/tables/T_S_I__5.py +60 -0
- fontTools/ttLib/tables/T_T_F_A_.py +14 -0
- fontTools/ttLib/tables/TupleVariation.py +884 -0
- fontTools/ttLib/tables/V_A_R_C_.py +12 -0
- fontTools/ttLib/tables/V_D_M_X_.py +249 -0
- fontTools/ttLib/tables/V_O_R_G_.py +165 -0
- fontTools/ttLib/tables/V_V_A_R_.py +13 -0
- fontTools/ttLib/tables/__init__.py +98 -0
- fontTools/ttLib/tables/_a_n_k_r.py +15 -0
- fontTools/ttLib/tables/_a_v_a_r.py +193 -0
- fontTools/ttLib/tables/_b_s_l_n.py +15 -0
- fontTools/ttLib/tables/_c_i_d_g.py +24 -0
- fontTools/ttLib/tables/_c_m_a_p.py +1591 -0
- fontTools/ttLib/tables/_c_v_a_r.py +94 -0
- fontTools/ttLib/tables/_c_v_t.py +56 -0
- fontTools/ttLib/tables/_f_e_a_t.py +15 -0
- fontTools/ttLib/tables/_f_p_g_m.py +62 -0
- fontTools/ttLib/tables/_f_v_a_r.py +261 -0
- fontTools/ttLib/tables/_g_a_s_p.py +63 -0
- fontTools/ttLib/tables/_g_c_i_d.py +13 -0
- fontTools/ttLib/tables/_g_l_y_f.py +2311 -0
- fontTools/ttLib/tables/_g_v_a_r.py +340 -0
- fontTools/ttLib/tables/_h_d_m_x.py +127 -0
- fontTools/ttLib/tables/_h_e_a_d.py +130 -0
- fontTools/ttLib/tables/_h_h_e_a.py +147 -0
- fontTools/ttLib/tables/_h_m_t_x.py +164 -0
- fontTools/ttLib/tables/_k_e_r_n.py +289 -0
- fontTools/ttLib/tables/_l_c_a_r.py +13 -0
- fontTools/ttLib/tables/_l_o_c_a.py +70 -0
- fontTools/ttLib/tables/_l_t_a_g.py +72 -0
- fontTools/ttLib/tables/_m_a_x_p.py +147 -0
- fontTools/ttLib/tables/_m_e_t_a.py +112 -0
- fontTools/ttLib/tables/_m_o_r_t.py +14 -0
- fontTools/ttLib/tables/_m_o_r_x.py +15 -0
- fontTools/ttLib/tables/_n_a_m_e.py +1242 -0
- fontTools/ttLib/tables/_o_p_b_d.py +14 -0
- fontTools/ttLib/tables/_p_o_s_t.py +319 -0
- fontTools/ttLib/tables/_p_r_e_p.py +16 -0
- fontTools/ttLib/tables/_p_r_o_p.py +12 -0
- fontTools/ttLib/tables/_s_b_i_x.py +129 -0
- fontTools/ttLib/tables/_t_r_a_k.py +332 -0
- fontTools/ttLib/tables/_v_h_e_a.py +139 -0
- fontTools/ttLib/tables/_v_m_t_x.py +19 -0
- fontTools/ttLib/tables/asciiTable.py +20 -0
- fontTools/ttLib/tables/grUtils.py +92 -0
- fontTools/ttLib/tables/otBase.py +1458 -0
- fontTools/ttLib/tables/otConverters.py +2068 -0
- fontTools/ttLib/tables/otData.py +6400 -0
- fontTools/ttLib/tables/otTables.py +2703 -0
- fontTools/ttLib/tables/otTraverse.py +163 -0
- fontTools/ttLib/tables/sbixGlyph.py +149 -0
- fontTools/ttLib/tables/sbixStrike.py +177 -0
- fontTools/ttLib/tables/table_API_readme.txt +91 -0
- fontTools/ttLib/tables/ttProgram.py +594 -0
- fontTools/ttLib/ttCollection.py +125 -0
- fontTools/ttLib/ttFont.py +1148 -0
- fontTools/ttLib/ttGlyphSet.py +490 -0
- fontTools/ttLib/ttVisitor.py +32 -0
- fontTools/ttLib/woff2.py +1680 -0
- fontTools/ttx.py +479 -0
- fontTools/ufoLib/__init__.py +2575 -0
- fontTools/ufoLib/converters.py +407 -0
- fontTools/ufoLib/errors.py +30 -0
- fontTools/ufoLib/etree.py +6 -0
- fontTools/ufoLib/filenames.py +356 -0
- fontTools/ufoLib/glifLib.py +2120 -0
- fontTools/ufoLib/kerning.py +141 -0
- fontTools/ufoLib/plistlib.py +47 -0
- fontTools/ufoLib/pointPen.py +6 -0
- fontTools/ufoLib/utils.py +107 -0
- fontTools/ufoLib/validators.py +1208 -0
- fontTools/unicode.py +50 -0
- fontTools/unicodedata/Blocks.py +817 -0
- fontTools/unicodedata/Mirrored.py +446 -0
- fontTools/unicodedata/OTTags.py +50 -0
- fontTools/unicodedata/ScriptExtensions.py +832 -0
- fontTools/unicodedata/Scripts.py +3639 -0
- fontTools/unicodedata/__init__.py +306 -0
- fontTools/varLib/__init__.py +1600 -0
- fontTools/varLib/__main__.py +6 -0
- fontTools/varLib/avar/__init__.py +0 -0
- fontTools/varLib/avar/__main__.py +72 -0
- fontTools/varLib/avar/build.py +79 -0
- fontTools/varLib/avar/map.py +108 -0
- fontTools/varLib/avar/plan.py +1004 -0
- fontTools/varLib/avar/unbuild.py +271 -0
- fontTools/varLib/avarPlanner.py +8 -0
- fontTools/varLib/builder.py +215 -0
- fontTools/varLib/cff.py +631 -0
- fontTools/varLib/errors.py +219 -0
- fontTools/varLib/featureVars.py +703 -0
- fontTools/varLib/hvar.py +113 -0
- fontTools/varLib/instancer/__init__.py +2052 -0
- fontTools/varLib/instancer/__main__.py +5 -0
- fontTools/varLib/instancer/featureVars.py +190 -0
- fontTools/varLib/instancer/names.py +388 -0
- fontTools/varLib/instancer/solver.py +309 -0
- fontTools/varLib/interpolatable.py +1209 -0
- fontTools/varLib/interpolatableHelpers.py +399 -0
- fontTools/varLib/interpolatablePlot.py +1269 -0
- fontTools/varLib/interpolatableTestContourOrder.py +82 -0
- fontTools/varLib/interpolatableTestStartingPoint.py +107 -0
- fontTools/varLib/interpolate_layout.py +124 -0
- fontTools/varLib/iup.c +19815 -0
- fontTools/varLib/iup.cp311-win32.pyd +0 -0
- fontTools/varLib/iup.py +490 -0
- fontTools/varLib/merger.py +1717 -0
- fontTools/varLib/models.py +642 -0
- fontTools/varLib/multiVarStore.py +253 -0
- fontTools/varLib/mutator.py +529 -0
- fontTools/varLib/mvar.py +40 -0
- fontTools/varLib/plot.py +238 -0
- fontTools/varLib/stat.py +149 -0
- fontTools/varLib/varStore.py +739 -0
- fontTools/voltLib/__init__.py +5 -0
- fontTools/voltLib/__main__.py +206 -0
- fontTools/voltLib/ast.py +452 -0
- fontTools/voltLib/error.py +12 -0
- fontTools/voltLib/lexer.py +99 -0
- fontTools/voltLib/parser.py +664 -0
- fontTools/voltLib/voltToFea.py +911 -0
- fonttools-4.60.2.data/data/share/man/man1/ttx.1 +225 -0
- fonttools-4.60.2.dist-info/METADATA +2250 -0
- fonttools-4.60.2.dist-info/RECORD +353 -0
- fonttools-4.60.2.dist-info/WHEEL +5 -0
- fonttools-4.60.2.dist-info/entry_points.txt +5 -0
- fonttools-4.60.2.dist-info/licenses/LICENSE +21 -0
- fonttools-4.60.2.dist-info/licenses/LICENSE.external +388 -0
- fonttools-4.60.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Instantiate a variation font. Run, eg:
|
|
3
|
+
|
|
4
|
+
.. code-block:: sh
|
|
5
|
+
|
|
6
|
+
$ fonttools varLib.mutator ./NotoSansArabic-VF.ttf wght=140 wdth=85
|
|
7
|
+
|
|
8
|
+
.. warning::
|
|
9
|
+
``fontTools.varLib.mutator`` is deprecated in favor of :mod:`fontTools.varLib.instancer`
|
|
10
|
+
which provides equivalent full instancing and also supports partial instancing.
|
|
11
|
+
Please migrate CLI usage to ``fonttools varLib.instancer`` and API usage to
|
|
12
|
+
:func:`fontTools.varLib.instancer.instantiateVariableFont`.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from fontTools.misc.fixedTools import floatToFixedToFloat, floatToFixed
|
|
16
|
+
from fontTools.misc.loggingTools import deprecateFunction
|
|
17
|
+
from fontTools.misc.roundTools import otRound
|
|
18
|
+
from fontTools.pens.boundsPen import BoundsPen
|
|
19
|
+
from fontTools.ttLib import TTFont, newTable
|
|
20
|
+
from fontTools.ttLib.tables import ttProgram
|
|
21
|
+
from fontTools.ttLib.tables._g_l_y_f import (
|
|
22
|
+
GlyphCoordinates,
|
|
23
|
+
flagOverlapSimple,
|
|
24
|
+
OVERLAP_COMPOUND,
|
|
25
|
+
)
|
|
26
|
+
from fontTools.varLib.models import (
|
|
27
|
+
supportScalar,
|
|
28
|
+
normalizeLocation,
|
|
29
|
+
piecewiseLinearMap,
|
|
30
|
+
)
|
|
31
|
+
from fontTools.varLib.merger import MutatorMerger
|
|
32
|
+
from fontTools.varLib.varStore import VarStoreInstancer
|
|
33
|
+
from fontTools.varLib.mvar import MVAR_ENTRIES
|
|
34
|
+
from fontTools.varLib.iup import iup_delta
|
|
35
|
+
import fontTools.subset.cff
|
|
36
|
+
import os.path
|
|
37
|
+
import logging
|
|
38
|
+
from io import BytesIO
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
log = logging.getLogger("fontTools.varlib.mutator")
|
|
42
|
+
|
|
43
|
+
# map 'wdth' axis (1..200) to OS/2.usWidthClass (1..9), rounding to closest
|
|
44
|
+
OS2_WIDTH_CLASS_VALUES = {}
|
|
45
|
+
percents = [50.0, 62.5, 75.0, 87.5, 100.0, 112.5, 125.0, 150.0, 200.0]
|
|
46
|
+
for i, (prev, curr) in enumerate(zip(percents[:-1], percents[1:]), start=1):
|
|
47
|
+
half = (prev + curr) / 2
|
|
48
|
+
OS2_WIDTH_CLASS_VALUES[half] = i
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def interpolate_cff2_PrivateDict(topDict, interpolateFromDeltas):
|
|
52
|
+
pd_blend_lists = (
|
|
53
|
+
"BlueValues",
|
|
54
|
+
"OtherBlues",
|
|
55
|
+
"FamilyBlues",
|
|
56
|
+
"FamilyOtherBlues",
|
|
57
|
+
"StemSnapH",
|
|
58
|
+
"StemSnapV",
|
|
59
|
+
)
|
|
60
|
+
pd_blend_values = ("BlueScale", "BlueShift", "BlueFuzz", "StdHW", "StdVW")
|
|
61
|
+
for fontDict in topDict.FDArray:
|
|
62
|
+
pd = fontDict.Private
|
|
63
|
+
vsindex = pd.vsindex if (hasattr(pd, "vsindex")) else 0
|
|
64
|
+
for key, value in pd.rawDict.items():
|
|
65
|
+
if (key in pd_blend_values) and isinstance(value, list):
|
|
66
|
+
delta = interpolateFromDeltas(vsindex, value[1:])
|
|
67
|
+
pd.rawDict[key] = otRound(value[0] + delta)
|
|
68
|
+
elif (key in pd_blend_lists) and isinstance(value[0], list):
|
|
69
|
+
"""If any argument in a BlueValues list is a blend list,
|
|
70
|
+
then they all are. The first value of each list is an
|
|
71
|
+
absolute value. The delta tuples are calculated from
|
|
72
|
+
relative master values, hence we need to append all the
|
|
73
|
+
deltas to date to each successive absolute value."""
|
|
74
|
+
delta = 0
|
|
75
|
+
for i, val_list in enumerate(value):
|
|
76
|
+
delta += otRound(interpolateFromDeltas(vsindex, val_list[1:]))
|
|
77
|
+
value[i] = val_list[0] + delta
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def interpolate_cff2_charstrings(topDict, interpolateFromDeltas, glyphOrder):
|
|
81
|
+
charstrings = topDict.CharStrings
|
|
82
|
+
for gname in glyphOrder:
|
|
83
|
+
# Interpolate charstring
|
|
84
|
+
# e.g replace blend op args with regular args,
|
|
85
|
+
# and use and discard vsindex op.
|
|
86
|
+
charstring = charstrings[gname]
|
|
87
|
+
new_program = []
|
|
88
|
+
vsindex = 0
|
|
89
|
+
last_i = 0
|
|
90
|
+
for i, token in enumerate(charstring.program):
|
|
91
|
+
if token == "vsindex":
|
|
92
|
+
vsindex = charstring.program[i - 1]
|
|
93
|
+
if last_i != 0:
|
|
94
|
+
new_program.extend(charstring.program[last_i : i - 1])
|
|
95
|
+
last_i = i + 1
|
|
96
|
+
elif token == "blend":
|
|
97
|
+
num_regions = charstring.getNumRegions(vsindex)
|
|
98
|
+
numMasters = 1 + num_regions
|
|
99
|
+
num_args = charstring.program[i - 1]
|
|
100
|
+
# The program list starting at program[i] is now:
|
|
101
|
+
# ..args for following operations
|
|
102
|
+
# num_args values from the default font
|
|
103
|
+
# num_args tuples, each with numMasters-1 delta values
|
|
104
|
+
# num_blend_args
|
|
105
|
+
# 'blend'
|
|
106
|
+
argi = i - (num_args * numMasters + 1)
|
|
107
|
+
end_args = tuplei = argi + num_args
|
|
108
|
+
while argi < end_args:
|
|
109
|
+
next_ti = tuplei + num_regions
|
|
110
|
+
deltas = charstring.program[tuplei:next_ti]
|
|
111
|
+
delta = interpolateFromDeltas(vsindex, deltas)
|
|
112
|
+
charstring.program[argi] += otRound(delta)
|
|
113
|
+
tuplei = next_ti
|
|
114
|
+
argi += 1
|
|
115
|
+
new_program.extend(charstring.program[last_i:end_args])
|
|
116
|
+
last_i = i + 1
|
|
117
|
+
if last_i != 0:
|
|
118
|
+
new_program.extend(charstring.program[last_i:])
|
|
119
|
+
charstring.program = new_program
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def interpolate_cff2_metrics(varfont, topDict, glyphOrder, loc):
|
|
123
|
+
"""Unlike TrueType glyphs, neither advance width nor bounding box
|
|
124
|
+
info is stored in a CFF2 charstring. The width data exists only in
|
|
125
|
+
the hmtx and HVAR tables. Since LSB data cannot be interpolated
|
|
126
|
+
reliably from the master LSB values in the hmtx table, we traverse
|
|
127
|
+
the charstring to determine the actual bound box."""
|
|
128
|
+
|
|
129
|
+
charstrings = topDict.CharStrings
|
|
130
|
+
boundsPen = BoundsPen(glyphOrder)
|
|
131
|
+
hmtx = varfont["hmtx"]
|
|
132
|
+
hvar_table = None
|
|
133
|
+
if "HVAR" in varfont:
|
|
134
|
+
hvar_table = varfont["HVAR"].table
|
|
135
|
+
fvar = varfont["fvar"]
|
|
136
|
+
varStoreInstancer = VarStoreInstancer(hvar_table.VarStore, fvar.axes, loc)
|
|
137
|
+
|
|
138
|
+
for gid, gname in enumerate(glyphOrder):
|
|
139
|
+
entry = list(hmtx[gname])
|
|
140
|
+
# get width delta.
|
|
141
|
+
if hvar_table:
|
|
142
|
+
if hvar_table.AdvWidthMap:
|
|
143
|
+
width_idx = hvar_table.AdvWidthMap.mapping[gname]
|
|
144
|
+
else:
|
|
145
|
+
width_idx = gid
|
|
146
|
+
width_delta = otRound(varStoreInstancer[width_idx])
|
|
147
|
+
else:
|
|
148
|
+
width_delta = 0
|
|
149
|
+
|
|
150
|
+
# get LSB.
|
|
151
|
+
boundsPen.init()
|
|
152
|
+
charstring = charstrings[gname]
|
|
153
|
+
charstring.draw(boundsPen)
|
|
154
|
+
if boundsPen.bounds is None:
|
|
155
|
+
# Happens with non-marking glyphs
|
|
156
|
+
lsb_delta = 0
|
|
157
|
+
else:
|
|
158
|
+
lsb = otRound(boundsPen.bounds[0])
|
|
159
|
+
lsb_delta = entry[1] - lsb
|
|
160
|
+
|
|
161
|
+
if lsb_delta or width_delta:
|
|
162
|
+
if width_delta:
|
|
163
|
+
entry[0] = max(0, entry[0] + width_delta)
|
|
164
|
+
if lsb_delta:
|
|
165
|
+
entry[1] = lsb
|
|
166
|
+
hmtx[gname] = tuple(entry)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@deprecateFunction(
|
|
170
|
+
"use fontTools.varLib.instancer.instantiateVariableFont instead "
|
|
171
|
+
"for either full or partial instancing",
|
|
172
|
+
)
|
|
173
|
+
def instantiateVariableFont(varfont, location, inplace=False, overlap=True):
|
|
174
|
+
"""Generate a static instance from a variable TTFont and a dictionary
|
|
175
|
+
defining the desired location along the variable font's axes.
|
|
176
|
+
The location values must be specified as user-space coordinates, e.g.:
|
|
177
|
+
|
|
178
|
+
.. code-block::
|
|
179
|
+
|
|
180
|
+
{'wght': 400, 'wdth': 100}
|
|
181
|
+
|
|
182
|
+
By default, a new TTFont object is returned. If ``inplace`` is True, the
|
|
183
|
+
input varfont is modified and reduced to a static font.
|
|
184
|
+
|
|
185
|
+
When the overlap parameter is defined as True,
|
|
186
|
+
OVERLAP_SIMPLE and OVERLAP_COMPOUND bits are set to 1. See
|
|
187
|
+
https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
|
|
188
|
+
"""
|
|
189
|
+
if not inplace:
|
|
190
|
+
# make a copy to leave input varfont unmodified
|
|
191
|
+
stream = BytesIO()
|
|
192
|
+
varfont.save(stream)
|
|
193
|
+
stream.seek(0)
|
|
194
|
+
varfont = TTFont(stream)
|
|
195
|
+
|
|
196
|
+
fvar = varfont["fvar"]
|
|
197
|
+
axes = {a.axisTag: (a.minValue, a.defaultValue, a.maxValue) for a in fvar.axes}
|
|
198
|
+
loc = normalizeLocation(location, axes)
|
|
199
|
+
if "avar" in varfont:
|
|
200
|
+
maps = varfont["avar"].segments
|
|
201
|
+
loc = {k: piecewiseLinearMap(v, maps[k]) for k, v in loc.items()}
|
|
202
|
+
# Quantize to F2Dot14, to avoid surprise interpolations.
|
|
203
|
+
loc = {k: floatToFixedToFloat(v, 14) for k, v in loc.items()}
|
|
204
|
+
# Location is normalized now
|
|
205
|
+
log.info("Normalized location: %s", loc)
|
|
206
|
+
|
|
207
|
+
if "gvar" in varfont:
|
|
208
|
+
log.info("Mutating glyf/gvar tables")
|
|
209
|
+
gvar = varfont["gvar"]
|
|
210
|
+
glyf = varfont["glyf"]
|
|
211
|
+
hMetrics = varfont["hmtx"].metrics
|
|
212
|
+
vMetrics = getattr(varfont.get("vmtx"), "metrics", None)
|
|
213
|
+
# get list of glyph names in gvar sorted by component depth
|
|
214
|
+
glyphnames = sorted(
|
|
215
|
+
gvar.variations.keys(),
|
|
216
|
+
key=lambda name: (
|
|
217
|
+
(
|
|
218
|
+
glyf[name].getCompositeMaxpValues(glyf).maxComponentDepth
|
|
219
|
+
if glyf[name].isComposite()
|
|
220
|
+
else 0
|
|
221
|
+
),
|
|
222
|
+
name,
|
|
223
|
+
),
|
|
224
|
+
)
|
|
225
|
+
for glyphname in glyphnames:
|
|
226
|
+
variations = gvar.variations[glyphname]
|
|
227
|
+
coordinates, _ = glyf._getCoordinatesAndControls(
|
|
228
|
+
glyphname, hMetrics, vMetrics
|
|
229
|
+
)
|
|
230
|
+
origCoords, endPts = None, None
|
|
231
|
+
for var in variations:
|
|
232
|
+
scalar = supportScalar(loc, var.axes)
|
|
233
|
+
if not scalar:
|
|
234
|
+
continue
|
|
235
|
+
delta = var.coordinates
|
|
236
|
+
if None in delta:
|
|
237
|
+
if origCoords is None:
|
|
238
|
+
origCoords, g = glyf._getCoordinatesAndControls(
|
|
239
|
+
glyphname, hMetrics, vMetrics
|
|
240
|
+
)
|
|
241
|
+
delta = iup_delta(delta, origCoords, g.endPts)
|
|
242
|
+
coordinates += GlyphCoordinates(delta) * scalar
|
|
243
|
+
glyf._setCoordinates(glyphname, coordinates, hMetrics, vMetrics)
|
|
244
|
+
else:
|
|
245
|
+
glyf = None
|
|
246
|
+
|
|
247
|
+
if "DSIG" in varfont:
|
|
248
|
+
del varfont["DSIG"]
|
|
249
|
+
|
|
250
|
+
if "cvar" in varfont:
|
|
251
|
+
log.info("Mutating cvt/cvar tables")
|
|
252
|
+
cvar = varfont["cvar"]
|
|
253
|
+
cvt = varfont["cvt "]
|
|
254
|
+
deltas = {}
|
|
255
|
+
for var in cvar.variations:
|
|
256
|
+
scalar = supportScalar(loc, var.axes)
|
|
257
|
+
if not scalar:
|
|
258
|
+
continue
|
|
259
|
+
for i, c in enumerate(var.coordinates):
|
|
260
|
+
if c is not None:
|
|
261
|
+
deltas[i] = deltas.get(i, 0) + scalar * c
|
|
262
|
+
for i, delta in deltas.items():
|
|
263
|
+
cvt[i] += otRound(delta)
|
|
264
|
+
|
|
265
|
+
if "CFF2" in varfont:
|
|
266
|
+
log.info("Mutating CFF2 table")
|
|
267
|
+
glyphOrder = varfont.getGlyphOrder()
|
|
268
|
+
CFF2 = varfont["CFF2"]
|
|
269
|
+
topDict = CFF2.cff.topDictIndex[0]
|
|
270
|
+
vsInstancer = VarStoreInstancer(topDict.VarStore.otVarStore, fvar.axes, loc)
|
|
271
|
+
interpolateFromDeltas = vsInstancer.interpolateFromDeltas
|
|
272
|
+
interpolate_cff2_PrivateDict(topDict, interpolateFromDeltas)
|
|
273
|
+
CFF2.desubroutinize()
|
|
274
|
+
interpolate_cff2_charstrings(topDict, interpolateFromDeltas, glyphOrder)
|
|
275
|
+
interpolate_cff2_metrics(varfont, topDict, glyphOrder, loc)
|
|
276
|
+
del topDict.rawDict["VarStore"]
|
|
277
|
+
del topDict.VarStore
|
|
278
|
+
|
|
279
|
+
if "MVAR" in varfont:
|
|
280
|
+
log.info("Mutating MVAR table")
|
|
281
|
+
mvar = varfont["MVAR"].table
|
|
282
|
+
varStoreInstancer = VarStoreInstancer(mvar.VarStore, fvar.axes, loc)
|
|
283
|
+
records = mvar.ValueRecord
|
|
284
|
+
for rec in records:
|
|
285
|
+
mvarTag = rec.ValueTag
|
|
286
|
+
if mvarTag not in MVAR_ENTRIES:
|
|
287
|
+
continue
|
|
288
|
+
tableTag, itemName = MVAR_ENTRIES[mvarTag]
|
|
289
|
+
delta = otRound(varStoreInstancer[rec.VarIdx])
|
|
290
|
+
if not delta:
|
|
291
|
+
continue
|
|
292
|
+
setattr(
|
|
293
|
+
varfont[tableTag],
|
|
294
|
+
itemName,
|
|
295
|
+
getattr(varfont[tableTag], itemName) + delta,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
log.info("Mutating FeatureVariations")
|
|
299
|
+
for tableTag in "GSUB", "GPOS":
|
|
300
|
+
if not tableTag in varfont:
|
|
301
|
+
continue
|
|
302
|
+
table = varfont[tableTag].table
|
|
303
|
+
if not getattr(table, "FeatureVariations", None):
|
|
304
|
+
continue
|
|
305
|
+
variations = table.FeatureVariations
|
|
306
|
+
for record in variations.FeatureVariationRecord:
|
|
307
|
+
applies = True
|
|
308
|
+
for condition in record.ConditionSet.ConditionTable:
|
|
309
|
+
if condition.Format == 1:
|
|
310
|
+
axisIdx = condition.AxisIndex
|
|
311
|
+
axisTag = fvar.axes[axisIdx].axisTag
|
|
312
|
+
Min = condition.FilterRangeMinValue
|
|
313
|
+
Max = condition.FilterRangeMaxValue
|
|
314
|
+
v = loc[axisTag]
|
|
315
|
+
if not (Min <= v <= Max):
|
|
316
|
+
applies = False
|
|
317
|
+
else:
|
|
318
|
+
applies = False
|
|
319
|
+
if not applies:
|
|
320
|
+
break
|
|
321
|
+
|
|
322
|
+
if applies:
|
|
323
|
+
assert record.FeatureTableSubstitution.Version == 0x00010000
|
|
324
|
+
for rec in record.FeatureTableSubstitution.SubstitutionRecord:
|
|
325
|
+
table.FeatureList.FeatureRecord[rec.FeatureIndex].Feature = (
|
|
326
|
+
rec.Feature
|
|
327
|
+
)
|
|
328
|
+
break
|
|
329
|
+
del table.FeatureVariations
|
|
330
|
+
|
|
331
|
+
if "GDEF" in varfont and varfont["GDEF"].table.Version >= 0x00010003:
|
|
332
|
+
log.info("Mutating GDEF/GPOS/GSUB tables")
|
|
333
|
+
gdef = varfont["GDEF"].table
|
|
334
|
+
instancer = VarStoreInstancer(gdef.VarStore, fvar.axes, loc)
|
|
335
|
+
|
|
336
|
+
merger = MutatorMerger(varfont, instancer)
|
|
337
|
+
merger.mergeTables(varfont, [varfont], ["GDEF", "GPOS"])
|
|
338
|
+
|
|
339
|
+
# Downgrade GDEF.
|
|
340
|
+
del gdef.VarStore
|
|
341
|
+
gdef.Version = 0x00010002
|
|
342
|
+
if gdef.MarkGlyphSetsDef is None:
|
|
343
|
+
del gdef.MarkGlyphSetsDef
|
|
344
|
+
gdef.Version = 0x00010000
|
|
345
|
+
|
|
346
|
+
if not (
|
|
347
|
+
gdef.LigCaretList
|
|
348
|
+
or gdef.MarkAttachClassDef
|
|
349
|
+
or gdef.GlyphClassDef
|
|
350
|
+
or gdef.AttachList
|
|
351
|
+
or (gdef.Version >= 0x00010002 and gdef.MarkGlyphSetsDef)
|
|
352
|
+
):
|
|
353
|
+
del varfont["GDEF"]
|
|
354
|
+
|
|
355
|
+
addidef = False
|
|
356
|
+
if glyf:
|
|
357
|
+
for glyph in glyf.glyphs.values():
|
|
358
|
+
if hasattr(glyph, "program"):
|
|
359
|
+
instructions = glyph.program.getAssembly()
|
|
360
|
+
# If GETVARIATION opcode is used in bytecode of any glyph add IDEF
|
|
361
|
+
addidef = any(op.startswith("GETVARIATION") for op in instructions)
|
|
362
|
+
if addidef:
|
|
363
|
+
break
|
|
364
|
+
if overlap:
|
|
365
|
+
for glyph_name in glyf.keys():
|
|
366
|
+
glyph = glyf[glyph_name]
|
|
367
|
+
# Set OVERLAP_COMPOUND bit for compound glyphs
|
|
368
|
+
if glyph.isComposite():
|
|
369
|
+
glyph.components[0].flags |= OVERLAP_COMPOUND
|
|
370
|
+
# Set OVERLAP_SIMPLE bit for simple glyphs
|
|
371
|
+
elif glyph.numberOfContours > 0:
|
|
372
|
+
glyph.flags[0] |= flagOverlapSimple
|
|
373
|
+
if addidef:
|
|
374
|
+
log.info("Adding IDEF to fpgm table for GETVARIATION opcode")
|
|
375
|
+
asm = []
|
|
376
|
+
if "fpgm" in varfont:
|
|
377
|
+
fpgm = varfont["fpgm"]
|
|
378
|
+
asm = fpgm.program.getAssembly()
|
|
379
|
+
else:
|
|
380
|
+
fpgm = newTable("fpgm")
|
|
381
|
+
fpgm.program = ttProgram.Program()
|
|
382
|
+
varfont["fpgm"] = fpgm
|
|
383
|
+
asm.append("PUSHB[000] 145")
|
|
384
|
+
asm.append("IDEF[ ]")
|
|
385
|
+
args = [str(len(loc))]
|
|
386
|
+
for a in fvar.axes:
|
|
387
|
+
args.append(str(floatToFixed(loc[a.axisTag], 14)))
|
|
388
|
+
asm.append("NPUSHW[ ] " + " ".join(args))
|
|
389
|
+
asm.append("ENDF[ ]")
|
|
390
|
+
fpgm.program.fromAssembly(asm)
|
|
391
|
+
|
|
392
|
+
# Change maxp attributes as IDEF is added
|
|
393
|
+
if "maxp" in varfont:
|
|
394
|
+
maxp = varfont["maxp"]
|
|
395
|
+
setattr(
|
|
396
|
+
maxp, "maxInstructionDefs", 1 + getattr(maxp, "maxInstructionDefs", 0)
|
|
397
|
+
)
|
|
398
|
+
setattr(
|
|
399
|
+
maxp,
|
|
400
|
+
"maxStackElements",
|
|
401
|
+
max(len(loc), getattr(maxp, "maxStackElements", 0)),
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
if "name" in varfont:
|
|
405
|
+
log.info("Pruning name table")
|
|
406
|
+
exclude = {a.axisNameID for a in fvar.axes}
|
|
407
|
+
for i in fvar.instances:
|
|
408
|
+
exclude.add(i.subfamilyNameID)
|
|
409
|
+
exclude.add(i.postscriptNameID)
|
|
410
|
+
if "ltag" in varfont:
|
|
411
|
+
# Drop the whole 'ltag' table if all its language tags are referenced by
|
|
412
|
+
# name records to be pruned.
|
|
413
|
+
# TODO: prune unused ltag tags and re-enumerate langIDs accordingly
|
|
414
|
+
excludedUnicodeLangIDs = [
|
|
415
|
+
n.langID
|
|
416
|
+
for n in varfont["name"].names
|
|
417
|
+
if n.nameID in exclude and n.platformID == 0 and n.langID != 0xFFFF
|
|
418
|
+
]
|
|
419
|
+
if set(excludedUnicodeLangIDs) == set(range(len((varfont["ltag"].tags)))):
|
|
420
|
+
del varfont["ltag"]
|
|
421
|
+
varfont["name"].names[:] = [
|
|
422
|
+
n
|
|
423
|
+
for n in varfont["name"].names
|
|
424
|
+
if n.nameID < 256 or n.nameID not in exclude
|
|
425
|
+
]
|
|
426
|
+
|
|
427
|
+
if "wght" in location and "OS/2" in varfont:
|
|
428
|
+
varfont["OS/2"].usWeightClass = otRound(max(1, min(location["wght"], 1000)))
|
|
429
|
+
if "wdth" in location:
|
|
430
|
+
wdth = location["wdth"]
|
|
431
|
+
for percent, widthClass in sorted(OS2_WIDTH_CLASS_VALUES.items()):
|
|
432
|
+
if wdth < percent:
|
|
433
|
+
varfont["OS/2"].usWidthClass = widthClass
|
|
434
|
+
break
|
|
435
|
+
else:
|
|
436
|
+
varfont["OS/2"].usWidthClass = 9
|
|
437
|
+
if "slnt" in location and "post" in varfont:
|
|
438
|
+
varfont["post"].italicAngle = max(-90, min(location["slnt"], 90))
|
|
439
|
+
|
|
440
|
+
log.info("Removing variable tables")
|
|
441
|
+
for tag in ("avar", "cvar", "fvar", "gvar", "HVAR", "MVAR", "VVAR", "STAT"):
|
|
442
|
+
if tag in varfont:
|
|
443
|
+
del varfont[tag]
|
|
444
|
+
|
|
445
|
+
return varfont
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def main(args=None):
|
|
449
|
+
"""Instantiate a variation font"""
|
|
450
|
+
from fontTools import configLogger
|
|
451
|
+
import argparse
|
|
452
|
+
|
|
453
|
+
parser = argparse.ArgumentParser(
|
|
454
|
+
"fonttools varLib.mutator", description="Instantiate a variable font"
|
|
455
|
+
)
|
|
456
|
+
parser.add_argument("input", metavar="INPUT.ttf", help="Input variable TTF file.")
|
|
457
|
+
parser.add_argument(
|
|
458
|
+
"locargs",
|
|
459
|
+
metavar="AXIS=LOC",
|
|
460
|
+
nargs="*",
|
|
461
|
+
help="List of space separated locations. A location consist in "
|
|
462
|
+
"the name of a variation axis, followed by '=' and a number. E.g.: "
|
|
463
|
+
" wght=700 wdth=80. The default is the location of the base master.",
|
|
464
|
+
)
|
|
465
|
+
parser.add_argument(
|
|
466
|
+
"-o",
|
|
467
|
+
"--output",
|
|
468
|
+
metavar="OUTPUT.ttf",
|
|
469
|
+
default=None,
|
|
470
|
+
help="Output instance TTF file (default: INPUT-instance.ttf).",
|
|
471
|
+
)
|
|
472
|
+
parser.add_argument(
|
|
473
|
+
"--no-recalc-timestamp",
|
|
474
|
+
dest="recalc_timestamp",
|
|
475
|
+
action="store_false",
|
|
476
|
+
help="Don't set the output font's timestamp to the current time.",
|
|
477
|
+
)
|
|
478
|
+
logging_group = parser.add_mutually_exclusive_group(required=False)
|
|
479
|
+
logging_group.add_argument(
|
|
480
|
+
"-v", "--verbose", action="store_true", help="Run more verbosely."
|
|
481
|
+
)
|
|
482
|
+
logging_group.add_argument(
|
|
483
|
+
"-q", "--quiet", action="store_true", help="Turn verbosity off."
|
|
484
|
+
)
|
|
485
|
+
parser.add_argument(
|
|
486
|
+
"--no-overlap",
|
|
487
|
+
dest="overlap",
|
|
488
|
+
action="store_false",
|
|
489
|
+
help="Don't set OVERLAP_SIMPLE/OVERLAP_COMPOUND glyf flags.",
|
|
490
|
+
)
|
|
491
|
+
options = parser.parse_args(args)
|
|
492
|
+
|
|
493
|
+
varfilename = options.input
|
|
494
|
+
outfile = (
|
|
495
|
+
os.path.splitext(varfilename)[0] + "-instance.ttf"
|
|
496
|
+
if not options.output
|
|
497
|
+
else options.output
|
|
498
|
+
)
|
|
499
|
+
configLogger(
|
|
500
|
+
level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
loc = {}
|
|
504
|
+
for arg in options.locargs:
|
|
505
|
+
try:
|
|
506
|
+
tag, val = arg.split("=")
|
|
507
|
+
assert len(tag) <= 4
|
|
508
|
+
loc[tag.ljust(4)] = float(val)
|
|
509
|
+
except (ValueError, AssertionError):
|
|
510
|
+
parser.error("invalid location argument format: %r" % arg)
|
|
511
|
+
log.info("Location: %s", loc)
|
|
512
|
+
|
|
513
|
+
log.info("Loading variable font")
|
|
514
|
+
varfont = TTFont(varfilename, recalcTimestamp=options.recalc_timestamp)
|
|
515
|
+
|
|
516
|
+
instantiateVariableFont(varfont, loc, inplace=True, overlap=options.overlap)
|
|
517
|
+
|
|
518
|
+
log.info("Saving instance font %s", outfile)
|
|
519
|
+
varfont.save(outfile)
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
if __name__ == "__main__":
|
|
523
|
+
import sys
|
|
524
|
+
|
|
525
|
+
if len(sys.argv) > 1:
|
|
526
|
+
sys.exit(main())
|
|
527
|
+
import doctest
|
|
528
|
+
|
|
529
|
+
sys.exit(doctest.testmod().failed)
|
fontTools/varLib/mvar.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
MVAR_ENTRIES = {
|
|
2
|
+
"hasc": ("OS/2", "sTypoAscender"), # horizontal ascender
|
|
3
|
+
"hdsc": ("OS/2", "sTypoDescender"), # horizontal descender
|
|
4
|
+
"hlgp": ("OS/2", "sTypoLineGap"), # horizontal line gap
|
|
5
|
+
"hcla": ("OS/2", "usWinAscent"), # horizontal clipping ascent
|
|
6
|
+
"hcld": ("OS/2", "usWinDescent"), # horizontal clipping descent
|
|
7
|
+
"vasc": ("vhea", "ascent"), # vertical ascender
|
|
8
|
+
"vdsc": ("vhea", "descent"), # vertical descender
|
|
9
|
+
"vlgp": ("vhea", "lineGap"), # vertical line gap
|
|
10
|
+
"hcrs": ("hhea", "caretSlopeRise"), # horizontal caret rise
|
|
11
|
+
"hcrn": ("hhea", "caretSlopeRun"), # horizontal caret run
|
|
12
|
+
"hcof": ("hhea", "caretOffset"), # horizontal caret offset
|
|
13
|
+
"vcrs": ("vhea", "caretSlopeRise"), # vertical caret rise
|
|
14
|
+
"vcrn": ("vhea", "caretSlopeRun"), # vertical caret run
|
|
15
|
+
"vcof": ("vhea", "caretOffset"), # vertical caret offset
|
|
16
|
+
"xhgt": ("OS/2", "sxHeight"), # x height
|
|
17
|
+
"cpht": ("OS/2", "sCapHeight"), # cap height
|
|
18
|
+
"sbxs": ("OS/2", "ySubscriptXSize"), # subscript em x size
|
|
19
|
+
"sbys": ("OS/2", "ySubscriptYSize"), # subscript em y size
|
|
20
|
+
"sbxo": ("OS/2", "ySubscriptXOffset"), # subscript em x offset
|
|
21
|
+
"sbyo": ("OS/2", "ySubscriptYOffset"), # subscript em y offset
|
|
22
|
+
"spxs": ("OS/2", "ySuperscriptXSize"), # superscript em x size
|
|
23
|
+
"spys": ("OS/2", "ySuperscriptYSize"), # superscript em y size
|
|
24
|
+
"spxo": ("OS/2", "ySuperscriptXOffset"), # superscript em x offset
|
|
25
|
+
"spyo": ("OS/2", "ySuperscriptYOffset"), # superscript em y offset
|
|
26
|
+
"strs": ("OS/2", "yStrikeoutSize"), # strikeout size
|
|
27
|
+
"stro": ("OS/2", "yStrikeoutPosition"), # strikeout offset
|
|
28
|
+
"unds": ("post", "underlineThickness"), # underline size
|
|
29
|
+
"undo": ("post", "underlinePosition"), # underline offset
|
|
30
|
+
#'gsp0': ('gasp', 'gaspRange[0].rangeMaxPPEM'), # gaspRange[0]
|
|
31
|
+
#'gsp1': ('gasp', 'gaspRange[1].rangeMaxPPEM'), # gaspRange[1]
|
|
32
|
+
#'gsp2': ('gasp', 'gaspRange[2].rangeMaxPPEM'), # gaspRange[2]
|
|
33
|
+
#'gsp3': ('gasp', 'gaspRange[3].rangeMaxPPEM'), # gaspRange[3]
|
|
34
|
+
#'gsp4': ('gasp', 'gaspRange[4].rangeMaxPPEM'), # gaspRange[4]
|
|
35
|
+
#'gsp5': ('gasp', 'gaspRange[5].rangeMaxPPEM'), # gaspRange[5]
|
|
36
|
+
#'gsp6': ('gasp', 'gaspRange[6].rangeMaxPPEM'), # gaspRange[6]
|
|
37
|
+
#'gsp7': ('gasp', 'gaspRange[7].rangeMaxPPEM'), # gaspRange[7]
|
|
38
|
+
#'gsp8': ('gasp', 'gaspRange[8].rangeMaxPPEM'), # gaspRange[8]
|
|
39
|
+
#'gsp9': ('gasp', 'gaspRange[9].rangeMaxPPEM'), # gaspRange[9]
|
|
40
|
+
}
|