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
fontTools/tfmLib.py
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
"""Module for reading TFM (TeX Font Metrics) files.
|
|
2
|
+
|
|
3
|
+
The TFM format is described in the TFtoPL WEB source code, whose typeset form
|
|
4
|
+
can be found on `CTAN <http://mirrors.ctan.org/info/knuth-pdf/texware/tftopl.pdf>`_.
|
|
5
|
+
|
|
6
|
+
>>> from fontTools.tfmLib import TFM
|
|
7
|
+
>>> tfm = TFM("Tests/tfmLib/data/cmr10.tfm")
|
|
8
|
+
>>>
|
|
9
|
+
>>> # Accessing an attribute gets you metadata.
|
|
10
|
+
>>> tfm.checksum
|
|
11
|
+
1274110073
|
|
12
|
+
>>> tfm.designsize
|
|
13
|
+
10.0
|
|
14
|
+
>>> tfm.codingscheme
|
|
15
|
+
'TeX text'
|
|
16
|
+
>>> tfm.family
|
|
17
|
+
'CMR'
|
|
18
|
+
>>> tfm.seven_bit_safe_flag
|
|
19
|
+
False
|
|
20
|
+
>>> tfm.face
|
|
21
|
+
234
|
|
22
|
+
>>> tfm.extraheader
|
|
23
|
+
{}
|
|
24
|
+
>>> tfm.fontdimens
|
|
25
|
+
{'SLANT': 0.0, 'SPACE': 0.33333396911621094, 'STRETCH': 0.16666698455810547, 'SHRINK': 0.11111164093017578, 'XHEIGHT': 0.4305553436279297, 'QUAD': 1.0000028610229492, 'EXTRASPACE': 0.11111164093017578}
|
|
26
|
+
>>> # Accessing a character gets you its metrics.
|
|
27
|
+
>>> # “width” is always available, other metrics are available only when
|
|
28
|
+
>>> # applicable. All values are relative to “designsize”.
|
|
29
|
+
>>> tfm.chars[ord("g")]
|
|
30
|
+
{'width': 0.5000019073486328, 'height': 0.4305553436279297, 'depth': 0.1944446563720703, 'italic': 0.013888359069824219}
|
|
31
|
+
>>> # Kerning and ligature can be accessed as well.
|
|
32
|
+
>>> tfm.kerning[ord("c")]
|
|
33
|
+
{104: -0.02777862548828125, 107: -0.02777862548828125}
|
|
34
|
+
>>> tfm.ligatures[ord("f")]
|
|
35
|
+
{105: ('LIG', 12), 102: ('LIG', 11), 108: ('LIG', 13)}
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
from types import SimpleNamespace
|
|
39
|
+
|
|
40
|
+
from fontTools.misc.sstruct import calcsize, unpack, unpack2
|
|
41
|
+
|
|
42
|
+
SIZES_FORMAT = """
|
|
43
|
+
>
|
|
44
|
+
lf: h # length of the entire file, in words
|
|
45
|
+
lh: h # length of the header data, in words
|
|
46
|
+
bc: h # smallest character code in the font
|
|
47
|
+
ec: h # largest character code in the font
|
|
48
|
+
nw: h # number of words in the width table
|
|
49
|
+
nh: h # number of words in the height table
|
|
50
|
+
nd: h # number of words in the depth table
|
|
51
|
+
ni: h # number of words in the italic correction table
|
|
52
|
+
nl: h # number of words in the ligature/kern table
|
|
53
|
+
nk: h # number of words in the kern table
|
|
54
|
+
ne: h # number of words in the extensible character table
|
|
55
|
+
np: h # number of font parameter words
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
SIZES_SIZE = calcsize(SIZES_FORMAT)
|
|
59
|
+
|
|
60
|
+
FIXED_FORMAT = "12.20F"
|
|
61
|
+
|
|
62
|
+
HEADER_FORMAT1 = f"""
|
|
63
|
+
>
|
|
64
|
+
checksum: L
|
|
65
|
+
designsize: {FIXED_FORMAT}
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
HEADER_FORMAT2 = f"""
|
|
69
|
+
{HEADER_FORMAT1}
|
|
70
|
+
codingscheme: 40p
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
HEADER_FORMAT3 = f"""
|
|
74
|
+
{HEADER_FORMAT2}
|
|
75
|
+
family: 20p
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
HEADER_FORMAT4 = f"""
|
|
79
|
+
{HEADER_FORMAT3}
|
|
80
|
+
seven_bit_safe_flag: ?
|
|
81
|
+
ignored: x
|
|
82
|
+
ignored: x
|
|
83
|
+
face: B
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
HEADER_SIZE1 = calcsize(HEADER_FORMAT1)
|
|
87
|
+
HEADER_SIZE2 = calcsize(HEADER_FORMAT2)
|
|
88
|
+
HEADER_SIZE3 = calcsize(HEADER_FORMAT3)
|
|
89
|
+
HEADER_SIZE4 = calcsize(HEADER_FORMAT4)
|
|
90
|
+
|
|
91
|
+
LIG_KERN_COMMAND = """
|
|
92
|
+
>
|
|
93
|
+
skip_byte: B
|
|
94
|
+
next_char: B
|
|
95
|
+
op_byte: B
|
|
96
|
+
remainder: B
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
BASE_PARAMS = [
|
|
100
|
+
"SLANT",
|
|
101
|
+
"SPACE",
|
|
102
|
+
"STRETCH",
|
|
103
|
+
"SHRINK",
|
|
104
|
+
"XHEIGHT",
|
|
105
|
+
"QUAD",
|
|
106
|
+
"EXTRASPACE",
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
MATHSY_PARAMS = [
|
|
110
|
+
"NUM1",
|
|
111
|
+
"NUM2",
|
|
112
|
+
"NUM3",
|
|
113
|
+
"DENOM1",
|
|
114
|
+
"DENOM2",
|
|
115
|
+
"SUP1",
|
|
116
|
+
"SUP2",
|
|
117
|
+
"SUP3",
|
|
118
|
+
"SUB1",
|
|
119
|
+
"SUB2",
|
|
120
|
+
"SUPDROP",
|
|
121
|
+
"SUBDROP",
|
|
122
|
+
"DELIM1",
|
|
123
|
+
"DELIM2",
|
|
124
|
+
"AXISHEIGHT",
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
MATHEX_PARAMS = [
|
|
128
|
+
"DEFAULTRULETHICKNESS",
|
|
129
|
+
"BIGOPSPACING1",
|
|
130
|
+
"BIGOPSPACING2",
|
|
131
|
+
"BIGOPSPACING3",
|
|
132
|
+
"BIGOPSPACING4",
|
|
133
|
+
"BIGOPSPACING5",
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
VANILLA = 0
|
|
137
|
+
MATHSY = 1
|
|
138
|
+
MATHEX = 2
|
|
139
|
+
|
|
140
|
+
UNREACHABLE = 0
|
|
141
|
+
PASSTHROUGH = 1
|
|
142
|
+
ACCESSABLE = 2
|
|
143
|
+
|
|
144
|
+
NO_TAG = 0
|
|
145
|
+
LIG_TAG = 1
|
|
146
|
+
LIST_TAG = 2
|
|
147
|
+
EXT_TAG = 3
|
|
148
|
+
|
|
149
|
+
STOP_FLAG = 128
|
|
150
|
+
KERN_FLAG = 128
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class TFMException(Exception):
|
|
154
|
+
def __init__(self, message):
|
|
155
|
+
super().__init__(message)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class TFM:
|
|
159
|
+
def __init__(self, file):
|
|
160
|
+
self._read(file)
|
|
161
|
+
|
|
162
|
+
def __repr__(self):
|
|
163
|
+
return (
|
|
164
|
+
f"<TFM"
|
|
165
|
+
f" for {self.family}"
|
|
166
|
+
f" in {self.codingscheme}"
|
|
167
|
+
f" at {self.designsize:g}pt>"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def _read(self, file):
|
|
171
|
+
if hasattr(file, "read"):
|
|
172
|
+
data = file.read()
|
|
173
|
+
else:
|
|
174
|
+
with open(file, "rb") as fp:
|
|
175
|
+
data = fp.read()
|
|
176
|
+
|
|
177
|
+
self._data = data
|
|
178
|
+
|
|
179
|
+
if len(data) < SIZES_SIZE:
|
|
180
|
+
raise TFMException("Too short input file")
|
|
181
|
+
|
|
182
|
+
sizes = SimpleNamespace()
|
|
183
|
+
unpack2(SIZES_FORMAT, data, sizes)
|
|
184
|
+
|
|
185
|
+
# Do some file structure sanity checks.
|
|
186
|
+
# TeX and TFtoPL do additional functional checks and might even correct
|
|
187
|
+
# “errors” in the input file, but we instead try to output the file as
|
|
188
|
+
# it is as long as it is parsable, even if the data make no sense.
|
|
189
|
+
|
|
190
|
+
if sizes.lf < 0:
|
|
191
|
+
raise TFMException("The file claims to have negative or zero length!")
|
|
192
|
+
|
|
193
|
+
if len(data) < sizes.lf * 4:
|
|
194
|
+
raise TFMException("The file has fewer bytes than it claims!")
|
|
195
|
+
|
|
196
|
+
for name, length in vars(sizes).items():
|
|
197
|
+
if length < 0:
|
|
198
|
+
raise TFMException("The subfile size: '{name}' is negative!")
|
|
199
|
+
|
|
200
|
+
if sizes.lh < 2:
|
|
201
|
+
raise TFMException(f"The header length is only {sizes.lh}!")
|
|
202
|
+
|
|
203
|
+
if sizes.bc > sizes.ec + 1 or sizes.ec > 255:
|
|
204
|
+
raise TFMException(
|
|
205
|
+
f"The character code range {sizes.bc}..{sizes.ec} is illegal!"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
if sizes.nw == 0 or sizes.nh == 0 or sizes.nd == 0 or sizes.ni == 0:
|
|
209
|
+
raise TFMException("Incomplete subfiles for character dimensions!")
|
|
210
|
+
|
|
211
|
+
if sizes.ne > 256:
|
|
212
|
+
raise TFMException(f"There are {ne} extensible recipes!")
|
|
213
|
+
|
|
214
|
+
if sizes.lf != (
|
|
215
|
+
6
|
|
216
|
+
+ sizes.lh
|
|
217
|
+
+ (sizes.ec - sizes.bc + 1)
|
|
218
|
+
+ sizes.nw
|
|
219
|
+
+ sizes.nh
|
|
220
|
+
+ sizes.nd
|
|
221
|
+
+ sizes.ni
|
|
222
|
+
+ sizes.nl
|
|
223
|
+
+ sizes.nk
|
|
224
|
+
+ sizes.ne
|
|
225
|
+
+ sizes.np
|
|
226
|
+
):
|
|
227
|
+
raise TFMException("Subfile sizes don’t add up to the stated total")
|
|
228
|
+
|
|
229
|
+
# Subfile offsets, used in the helper function below. These all are
|
|
230
|
+
# 32-bit word offsets not 8-bit byte offsets.
|
|
231
|
+
char_base = 6 + sizes.lh - sizes.bc
|
|
232
|
+
width_base = char_base + sizes.ec + 1
|
|
233
|
+
height_base = width_base + sizes.nw
|
|
234
|
+
depth_base = height_base + sizes.nh
|
|
235
|
+
italic_base = depth_base + sizes.nd
|
|
236
|
+
lig_kern_base = italic_base + sizes.ni
|
|
237
|
+
kern_base = lig_kern_base + sizes.nl
|
|
238
|
+
exten_base = kern_base + sizes.nk
|
|
239
|
+
param_base = exten_base + sizes.ne
|
|
240
|
+
|
|
241
|
+
# Helper functions for accessing individual data. If this looks
|
|
242
|
+
# nonidiomatic Python, I blame the effect of reading the literate WEB
|
|
243
|
+
# documentation of TFtoPL.
|
|
244
|
+
def char_info(c):
|
|
245
|
+
return 4 * (char_base + c)
|
|
246
|
+
|
|
247
|
+
def width_index(c):
|
|
248
|
+
return data[char_info(c)]
|
|
249
|
+
|
|
250
|
+
def noneexistent(c):
|
|
251
|
+
return c < sizes.bc or c > sizes.ec or width_index(c) == 0
|
|
252
|
+
|
|
253
|
+
def height_index(c):
|
|
254
|
+
return data[char_info(c) + 1] // 16
|
|
255
|
+
|
|
256
|
+
def depth_index(c):
|
|
257
|
+
return data[char_info(c) + 1] % 16
|
|
258
|
+
|
|
259
|
+
def italic_index(c):
|
|
260
|
+
return data[char_info(c) + 2] // 4
|
|
261
|
+
|
|
262
|
+
def tag(c):
|
|
263
|
+
return data[char_info(c) + 2] % 4
|
|
264
|
+
|
|
265
|
+
def remainder(c):
|
|
266
|
+
return data[char_info(c) + 3]
|
|
267
|
+
|
|
268
|
+
def width(c):
|
|
269
|
+
r = 4 * (width_base + width_index(c))
|
|
270
|
+
return read_fixed(r, "v")["v"]
|
|
271
|
+
|
|
272
|
+
def height(c):
|
|
273
|
+
r = 4 * (height_base + height_index(c))
|
|
274
|
+
return read_fixed(r, "v")["v"]
|
|
275
|
+
|
|
276
|
+
def depth(c):
|
|
277
|
+
r = 4 * (depth_base + depth_index(c))
|
|
278
|
+
return read_fixed(r, "v")["v"]
|
|
279
|
+
|
|
280
|
+
def italic(c):
|
|
281
|
+
r = 4 * (italic_base + italic_index(c))
|
|
282
|
+
return read_fixed(r, "v")["v"]
|
|
283
|
+
|
|
284
|
+
def exten(c):
|
|
285
|
+
return 4 * (exten_base + remainder(c))
|
|
286
|
+
|
|
287
|
+
def lig_step(i):
|
|
288
|
+
return 4 * (lig_kern_base + i)
|
|
289
|
+
|
|
290
|
+
def lig_kern_command(i):
|
|
291
|
+
command = SimpleNamespace()
|
|
292
|
+
unpack2(LIG_KERN_COMMAND, data[i:], command)
|
|
293
|
+
return command
|
|
294
|
+
|
|
295
|
+
def kern(i):
|
|
296
|
+
r = 4 * (kern_base + i)
|
|
297
|
+
return read_fixed(r, "v")["v"]
|
|
298
|
+
|
|
299
|
+
def param(i):
|
|
300
|
+
return 4 * (param_base + i)
|
|
301
|
+
|
|
302
|
+
def read_fixed(index, key, obj=None):
|
|
303
|
+
ret = unpack2(f">;{key}:{FIXED_FORMAT}", data[index:], obj)
|
|
304
|
+
return ret[0]
|
|
305
|
+
|
|
306
|
+
# Set all attributes to empty values regardless of the header size.
|
|
307
|
+
unpack(HEADER_FORMAT4, [0] * HEADER_SIZE4, self)
|
|
308
|
+
|
|
309
|
+
offset = 24
|
|
310
|
+
length = sizes.lh * 4
|
|
311
|
+
self.extraheader = {}
|
|
312
|
+
if length >= HEADER_SIZE4:
|
|
313
|
+
rest = unpack2(HEADER_FORMAT4, data[offset:], self)[1]
|
|
314
|
+
if self.face < 18:
|
|
315
|
+
s = self.face % 2
|
|
316
|
+
b = self.face // 2
|
|
317
|
+
self.face = "MBL"[b % 3] + "RI"[s] + "RCE"[b // 3]
|
|
318
|
+
for i in range(sizes.lh - HEADER_SIZE4 // 4):
|
|
319
|
+
rest = unpack2(f">;HEADER{i + 18}:l", rest, self.extraheader)[1]
|
|
320
|
+
elif length >= HEADER_SIZE3:
|
|
321
|
+
unpack2(HEADER_FORMAT3, data[offset:], self)
|
|
322
|
+
elif length >= HEADER_SIZE2:
|
|
323
|
+
unpack2(HEADER_FORMAT2, data[offset:], self)
|
|
324
|
+
elif length >= HEADER_SIZE1:
|
|
325
|
+
unpack2(HEADER_FORMAT1, data[offset:], self)
|
|
326
|
+
|
|
327
|
+
self.fonttype = VANILLA
|
|
328
|
+
scheme = self.codingscheme.upper()
|
|
329
|
+
if scheme.startswith("TEX MATH SY"):
|
|
330
|
+
self.fonttype = MATHSY
|
|
331
|
+
elif scheme.startswith("TEX MATH EX"):
|
|
332
|
+
self.fonttype = MATHEX
|
|
333
|
+
|
|
334
|
+
self.fontdimens = {}
|
|
335
|
+
for i in range(sizes.np):
|
|
336
|
+
name = f"PARAMETER{i+1}"
|
|
337
|
+
if i <= 6:
|
|
338
|
+
name = BASE_PARAMS[i]
|
|
339
|
+
elif self.fonttype == MATHSY and i <= 21:
|
|
340
|
+
name = MATHSY_PARAMS[i - 7]
|
|
341
|
+
elif self.fonttype == MATHEX and i <= 12:
|
|
342
|
+
name = MATHEX_PARAMS[i - 7]
|
|
343
|
+
read_fixed(param(i), name, self.fontdimens)
|
|
344
|
+
|
|
345
|
+
lig_kern_map = {}
|
|
346
|
+
self.right_boundary_char = None
|
|
347
|
+
self.left_boundary_char = None
|
|
348
|
+
if sizes.nl > 0:
|
|
349
|
+
cmd = lig_kern_command(lig_step(0))
|
|
350
|
+
if cmd.skip_byte == 255:
|
|
351
|
+
self.right_boundary_char = cmd.next_char
|
|
352
|
+
|
|
353
|
+
cmd = lig_kern_command(lig_step((sizes.nl - 1)))
|
|
354
|
+
if cmd.skip_byte == 255:
|
|
355
|
+
self.left_boundary_char = 256
|
|
356
|
+
r = 256 * cmd.op_byte + cmd.remainder
|
|
357
|
+
lig_kern_map[self.left_boundary_char] = r
|
|
358
|
+
|
|
359
|
+
self.chars = {}
|
|
360
|
+
for c in range(sizes.bc, sizes.ec + 1):
|
|
361
|
+
if width_index(c) > 0:
|
|
362
|
+
self.chars[c] = info = {}
|
|
363
|
+
info["width"] = width(c)
|
|
364
|
+
if height_index(c) > 0:
|
|
365
|
+
info["height"] = height(c)
|
|
366
|
+
if depth_index(c) > 0:
|
|
367
|
+
info["depth"] = depth(c)
|
|
368
|
+
if italic_index(c) > 0:
|
|
369
|
+
info["italic"] = italic(c)
|
|
370
|
+
char_tag = tag(c)
|
|
371
|
+
if char_tag == NO_TAG:
|
|
372
|
+
pass
|
|
373
|
+
elif char_tag == LIG_TAG:
|
|
374
|
+
lig_kern_map[c] = remainder(c)
|
|
375
|
+
elif char_tag == LIST_TAG:
|
|
376
|
+
info["nextlarger"] = remainder(c)
|
|
377
|
+
elif char_tag == EXT_TAG:
|
|
378
|
+
info["varchar"] = varchar = {}
|
|
379
|
+
for i in range(4):
|
|
380
|
+
part = data[exten(c) + i]
|
|
381
|
+
if i == 3 or part > 0:
|
|
382
|
+
name = "rep"
|
|
383
|
+
if i == 0:
|
|
384
|
+
name = "top"
|
|
385
|
+
elif i == 1:
|
|
386
|
+
name = "mid"
|
|
387
|
+
elif i == 2:
|
|
388
|
+
name = "bot"
|
|
389
|
+
if noneexistent(part):
|
|
390
|
+
varchar[name] = c
|
|
391
|
+
else:
|
|
392
|
+
varchar[name] = part
|
|
393
|
+
|
|
394
|
+
self.ligatures = {}
|
|
395
|
+
self.kerning = {}
|
|
396
|
+
for c, i in sorted(lig_kern_map.items()):
|
|
397
|
+
cmd = lig_kern_command(lig_step(i))
|
|
398
|
+
if cmd.skip_byte > STOP_FLAG:
|
|
399
|
+
i = 256 * cmd.op_byte + cmd.remainder
|
|
400
|
+
|
|
401
|
+
while i < sizes.nl:
|
|
402
|
+
cmd = lig_kern_command(lig_step(i))
|
|
403
|
+
if cmd.skip_byte > STOP_FLAG:
|
|
404
|
+
pass
|
|
405
|
+
else:
|
|
406
|
+
if cmd.op_byte >= KERN_FLAG:
|
|
407
|
+
r = 256 * (cmd.op_byte - KERN_FLAG) + cmd.remainder
|
|
408
|
+
self.kerning.setdefault(c, {})[cmd.next_char] = kern(r)
|
|
409
|
+
else:
|
|
410
|
+
r = cmd.op_byte
|
|
411
|
+
if r == 4 or (r > 7 and r != 11):
|
|
412
|
+
# Ligature step with nonstandard code, we output
|
|
413
|
+
# the code verbatim.
|
|
414
|
+
lig = r
|
|
415
|
+
else:
|
|
416
|
+
lig = ""
|
|
417
|
+
if r % 4 > 1:
|
|
418
|
+
lig += "/"
|
|
419
|
+
lig += "LIG"
|
|
420
|
+
if r % 2 != 0:
|
|
421
|
+
lig += "/"
|
|
422
|
+
while r > 3:
|
|
423
|
+
lig += ">"
|
|
424
|
+
r -= 4
|
|
425
|
+
self.ligatures.setdefault(c, {})[cmd.next_char] = (
|
|
426
|
+
lig,
|
|
427
|
+
cmd.remainder,
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
if cmd.skip_byte >= STOP_FLAG:
|
|
431
|
+
break
|
|
432
|
+
i += cmd.skip_byte + 1
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
if __name__ == "__main__":
|
|
436
|
+
import sys
|
|
437
|
+
|
|
438
|
+
tfm = TFM(sys.argv[1])
|
|
439
|
+
print(
|
|
440
|
+
"\n".join(
|
|
441
|
+
x
|
|
442
|
+
for x in [
|
|
443
|
+
f"tfm.checksum={tfm.checksum}",
|
|
444
|
+
f"tfm.designsize={tfm.designsize}",
|
|
445
|
+
f"tfm.codingscheme={tfm.codingscheme}",
|
|
446
|
+
f"tfm.fonttype={tfm.fonttype}",
|
|
447
|
+
f"tfm.family={tfm.family}",
|
|
448
|
+
f"tfm.seven_bit_safe_flag={tfm.seven_bit_safe_flag}",
|
|
449
|
+
f"tfm.face={tfm.face}",
|
|
450
|
+
f"tfm.extraheader={tfm.extraheader}",
|
|
451
|
+
f"tfm.fontdimens={tfm.fontdimens}",
|
|
452
|
+
f"tfm.right_boundary_char={tfm.right_boundary_char}",
|
|
453
|
+
f"tfm.left_boundary_char={tfm.left_boundary_char}",
|
|
454
|
+
f"tfm.kerning={tfm.kerning}",
|
|
455
|
+
f"tfm.ligatures={tfm.ligatures}",
|
|
456
|
+
f"tfm.chars={tfm.chars}",
|
|
457
|
+
]
|
|
458
|
+
)
|
|
459
|
+
)
|
|
460
|
+
print(tfm)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""fontTools.ttLib -- a package for dealing with TrueType fonts."""
|
|
2
|
+
|
|
3
|
+
from fontTools.config import OPTIONS
|
|
4
|
+
from fontTools.misc.loggingTools import deprecateFunction
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
log = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
OPTIMIZE_FONT_SPEED = OPTIONS["fontTools.ttLib:OPTIMIZE_FONT_SPEED"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TTLibError(Exception):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TTLibFileIsCollectionError(TTLibError):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@deprecateFunction("use logging instead", category=DeprecationWarning)
|
|
23
|
+
def debugmsg(msg):
|
|
24
|
+
import time
|
|
25
|
+
|
|
26
|
+
print(msg + time.strftime(" (%H:%M:%S)", time.localtime(time.time())))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
from fontTools.ttLib.ttFont import *
|
|
30
|
+
from fontTools.ttLib.ttCollection import TTCollection
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from fontTools.ttLib import OPTIMIZE_FONT_SPEED, TTLibError, TTLibFileIsCollectionError
|
|
3
|
+
from fontTools.ttLib.ttFont import *
|
|
4
|
+
from fontTools.ttLib.ttCollection import TTCollection
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main(args=None):
|
|
8
|
+
"""Open/save fonts with TTFont() or TTCollection()
|
|
9
|
+
|
|
10
|
+
./fonttools ttLib [-oFILE] [-yNUMBER] files...
|
|
11
|
+
|
|
12
|
+
If multiple files are given on the command-line,
|
|
13
|
+
they are each opened (as a font or collection),
|
|
14
|
+
and added to the font list.
|
|
15
|
+
|
|
16
|
+
If -o (output-file) argument is given, the font
|
|
17
|
+
list is then saved to the output file, either as
|
|
18
|
+
a single font, if there is only one font, or as
|
|
19
|
+
a collection otherwise.
|
|
20
|
+
|
|
21
|
+
If -y (font-number) argument is given, only the
|
|
22
|
+
specified font from collections is opened.
|
|
23
|
+
|
|
24
|
+
The above allow extracting a single font from a
|
|
25
|
+
collection, or combining multiple fonts into a
|
|
26
|
+
collection.
|
|
27
|
+
|
|
28
|
+
If --lazy or --no-lazy are give, those are passed
|
|
29
|
+
to the TTFont() or TTCollection() constructors.
|
|
30
|
+
"""
|
|
31
|
+
from fontTools import configLogger
|
|
32
|
+
|
|
33
|
+
if args is None:
|
|
34
|
+
args = sys.argv[1:]
|
|
35
|
+
|
|
36
|
+
import argparse
|
|
37
|
+
|
|
38
|
+
parser = argparse.ArgumentParser(
|
|
39
|
+
"fonttools ttLib",
|
|
40
|
+
description="Open/save fonts with TTFont() or TTCollection()",
|
|
41
|
+
epilog="""
|
|
42
|
+
If multiple files are given on the command-line,
|
|
43
|
+
they are each opened (as a font or collection),
|
|
44
|
+
and added to the font list.
|
|
45
|
+
|
|
46
|
+
The above, when combined with -o / --output,
|
|
47
|
+
allows for extracting a single font from a
|
|
48
|
+
collection, or combining multiple fonts into a
|
|
49
|
+
collection.
|
|
50
|
+
""",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument("font", metavar="font", nargs="*", help="Font file.")
|
|
53
|
+
parser.add_argument(
|
|
54
|
+
"-t", "--table", metavar="table", action="append", help="Tables to decompile."
|
|
55
|
+
)
|
|
56
|
+
parser.add_argument(
|
|
57
|
+
"-o", "--output", metavar="FILE", default=None, help="Output file."
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"-y", metavar="NUMBER", default=-1, help="Font number to load from collections."
|
|
61
|
+
)
|
|
62
|
+
parser.add_argument(
|
|
63
|
+
"--lazy", action="store_true", default=None, help="Load fonts lazily."
|
|
64
|
+
)
|
|
65
|
+
parser.add_argument(
|
|
66
|
+
"--no-lazy", dest="lazy", action="store_false", help="Load fonts immediately."
|
|
67
|
+
)
|
|
68
|
+
parser.add_argument(
|
|
69
|
+
"--flavor",
|
|
70
|
+
dest="flavor",
|
|
71
|
+
default=None,
|
|
72
|
+
help="Flavor of output font. 'woff' or 'woff2'.",
|
|
73
|
+
)
|
|
74
|
+
parser.add_argument(
|
|
75
|
+
"--no-recalc-timestamp",
|
|
76
|
+
dest="recalcTimestamp",
|
|
77
|
+
action="store_false",
|
|
78
|
+
help="Keep the original font 'modified' timestamp.",
|
|
79
|
+
)
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"-b",
|
|
82
|
+
dest="recalcBBoxes",
|
|
83
|
+
action="store_false",
|
|
84
|
+
help="Don't recalc glyph bounding boxes: use the values in the original font.",
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"--optimize-font-speed",
|
|
88
|
+
action="store_true",
|
|
89
|
+
help=(
|
|
90
|
+
"Enable optimizations that prioritize speed over file size. This "
|
|
91
|
+
"mainly affects how glyf table and gvar / VARC tables are compiled."
|
|
92
|
+
),
|
|
93
|
+
)
|
|
94
|
+
options = parser.parse_args(args)
|
|
95
|
+
|
|
96
|
+
fontNumber = int(options.y) if options.y is not None else None
|
|
97
|
+
outFile = options.output
|
|
98
|
+
lazy = options.lazy
|
|
99
|
+
flavor = options.flavor
|
|
100
|
+
tables = options.table
|
|
101
|
+
recalcBBoxes = options.recalcBBoxes
|
|
102
|
+
recalcTimestamp = options.recalcTimestamp
|
|
103
|
+
optimizeFontSpeed = options.optimize_font_speed
|
|
104
|
+
|
|
105
|
+
fonts = []
|
|
106
|
+
for f in options.font:
|
|
107
|
+
try:
|
|
108
|
+
font = TTFont(
|
|
109
|
+
f,
|
|
110
|
+
recalcBBoxes=recalcBBoxes,
|
|
111
|
+
recalcTimestamp=recalcTimestamp,
|
|
112
|
+
fontNumber=fontNumber,
|
|
113
|
+
lazy=lazy,
|
|
114
|
+
)
|
|
115
|
+
if optimizeFontSpeed:
|
|
116
|
+
font.cfg[OPTIMIZE_FONT_SPEED] = optimizeFontSpeed
|
|
117
|
+
fonts.append(font)
|
|
118
|
+
except TTLibFileIsCollectionError:
|
|
119
|
+
collection = TTCollection(f, lazy=lazy)
|
|
120
|
+
fonts.extend(collection.fonts)
|
|
121
|
+
|
|
122
|
+
if tables is None:
|
|
123
|
+
if lazy is False:
|
|
124
|
+
tables = ["*"]
|
|
125
|
+
elif optimizeFontSpeed:
|
|
126
|
+
tables = {"glyf", "gvar", "VARC"}.intersection(font.keys())
|
|
127
|
+
else:
|
|
128
|
+
tables = []
|
|
129
|
+
for font in fonts:
|
|
130
|
+
if "GlyphOrder" in tables:
|
|
131
|
+
font.getGlyphOrder()
|
|
132
|
+
for table in tables if "*" not in tables else font.keys():
|
|
133
|
+
font[table] # Decompiles
|
|
134
|
+
|
|
135
|
+
if outFile is not None:
|
|
136
|
+
if len(fonts) == 1:
|
|
137
|
+
fonts[0].flavor = flavor
|
|
138
|
+
fonts[0].save(outFile)
|
|
139
|
+
else:
|
|
140
|
+
if flavor is not None:
|
|
141
|
+
raise TTLibError("Cannot set flavor for collections.")
|
|
142
|
+
collection = TTCollection()
|
|
143
|
+
collection.fonts = fonts
|
|
144
|
+
collection.save(outFile)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
if __name__ == "__main__":
|
|
148
|
+
sys.exit(main())
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""ttLib.macUtils.py -- Various Mac-specific stuff."""
|
|
2
|
+
|
|
3
|
+
from io import BytesIO
|
|
4
|
+
from fontTools.misc.macRes import ResourceReader, ResourceError
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def getSFNTResIndices(path):
|
|
8
|
+
"""Determine whether a file has a 'sfnt' resource fork or not."""
|
|
9
|
+
try:
|
|
10
|
+
reader = ResourceReader(path)
|
|
11
|
+
indices = reader.getIndices("sfnt")
|
|
12
|
+
reader.close()
|
|
13
|
+
return indices
|
|
14
|
+
except ResourceError:
|
|
15
|
+
return []
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def openTTFonts(path):
|
|
19
|
+
"""Given a pathname, return a list of TTFont objects. In the case
|
|
20
|
+
of a flat TTF/OTF file, the list will contain just one font object;
|
|
21
|
+
but in the case of a Mac font suitcase it will contain as many
|
|
22
|
+
font objects as there are sfnt resources in the file.
|
|
23
|
+
"""
|
|
24
|
+
from fontTools import ttLib
|
|
25
|
+
|
|
26
|
+
fonts = []
|
|
27
|
+
sfnts = getSFNTResIndices(path)
|
|
28
|
+
if not sfnts:
|
|
29
|
+
fonts.append(ttLib.TTFont(path))
|
|
30
|
+
else:
|
|
31
|
+
for index in sfnts:
|
|
32
|
+
fonts.append(ttLib.TTFont(path, index))
|
|
33
|
+
if not fonts:
|
|
34
|
+
raise ttLib.TTLibError("no fonts found in file '%s'" % path)
|
|
35
|
+
return fonts
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class SFNTResourceReader(BytesIO):
|
|
39
|
+
"""Simple read-only file wrapper for 'sfnt' resources."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, path, res_name_or_index):
|
|
42
|
+
from fontTools import ttLib
|
|
43
|
+
|
|
44
|
+
reader = ResourceReader(path)
|
|
45
|
+
if isinstance(res_name_or_index, str):
|
|
46
|
+
rsrc = reader.getNamedResource("sfnt", res_name_or_index)
|
|
47
|
+
else:
|
|
48
|
+
rsrc = reader.getIndResource("sfnt", res_name_or_index)
|
|
49
|
+
if rsrc is None:
|
|
50
|
+
raise ttLib.TTLibError("sfnt resource not found: %s" % res_name_or_index)
|
|
51
|
+
reader.close()
|
|
52
|
+
self.rsrc = rsrc
|
|
53
|
+
super(SFNTResourceReader, self).__init__(rsrc.data)
|
|
54
|
+
self.name = path
|