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/annotations.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import TYPE_CHECKING, Iterable, Optional, TypeVar, Union
|
|
3
|
+
from collections.abc import Callable, Sequence
|
|
4
|
+
from fontTools.misc.filesystem._base import FS
|
|
5
|
+
from os import PathLike
|
|
6
|
+
from xml.etree.ElementTree import Element as ElementTreeElement
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from fontTools.ufoLib import UFOFormatVersion
|
|
10
|
+
from fontTools.ufoLib.glifLib import GLIFFormatVersion
|
|
11
|
+
from lxml.etree import _Element as LxmlElement
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
T = TypeVar("T") # Generic type
|
|
15
|
+
K = TypeVar("K") # Generic dict key type
|
|
16
|
+
V = TypeVar("V") # Generic dict value type
|
|
17
|
+
|
|
18
|
+
GlyphNameToFileNameFunc = Optional[Callable[[str, set[str]], str]]
|
|
19
|
+
ElementType = Union[ElementTreeElement, "LxmlElement"]
|
|
20
|
+
FormatVersion = Union[int, tuple[int, int]]
|
|
21
|
+
FormatVersions = Optional[Iterable[FormatVersion]]
|
|
22
|
+
GLIFFormatVersionInput = Optional[Union[int, tuple[int, int], "GLIFFormatVersion"]]
|
|
23
|
+
UFOFormatVersionInput = Optional[Union[int, tuple[int, int], "UFOFormatVersion"]]
|
|
24
|
+
IntFloat = Union[int, float]
|
|
25
|
+
KerningPair = tuple[str, str]
|
|
26
|
+
KerningDict = dict[KerningPair, IntFloat]
|
|
27
|
+
KerningGroups = dict[str, Sequence[str]]
|
|
28
|
+
KerningNested = dict[str, dict[str, IntFloat]]
|
|
29
|
+
PathStr = Union[str, PathLike[str]]
|
|
30
|
+
PathOrFS = Union[PathStr, FS]
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""CFF2 to CFF converter."""
|
|
2
|
+
|
|
3
|
+
from fontTools.ttLib import TTFont, newTable
|
|
4
|
+
from fontTools.misc.cliTools import makeOutputFileName
|
|
5
|
+
from fontTools.misc.psCharStrings import T2StackUseExtractor
|
|
6
|
+
from fontTools.cffLib import (
|
|
7
|
+
TopDictIndex,
|
|
8
|
+
buildOrder,
|
|
9
|
+
buildDefaults,
|
|
10
|
+
topDictOperators,
|
|
11
|
+
privateDictOperators,
|
|
12
|
+
FDSelect,
|
|
13
|
+
)
|
|
14
|
+
from .transforms import desubroutinizeCharString
|
|
15
|
+
from .specializer import specializeProgram
|
|
16
|
+
from .width import optimizeWidths
|
|
17
|
+
from collections import defaultdict
|
|
18
|
+
import logging
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
__all__ = ["convertCFF2ToCFF", "main"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
log = logging.getLogger("fontTools.cffLib")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _convertCFF2ToCFF(cff, otFont):
|
|
28
|
+
"""Converts this object from CFF2 format to CFF format. This conversion
|
|
29
|
+
is done 'in-place'. The conversion cannot be reversed.
|
|
30
|
+
|
|
31
|
+
The CFF2 font cannot be variable. (TODO Accept those and convert to the
|
|
32
|
+
default instance?)
|
|
33
|
+
|
|
34
|
+
This assumes a decompiled CFF2 table. (i.e. that the object has been
|
|
35
|
+
filled via :meth:`decompile` and e.g. not loaded from XML.)"""
|
|
36
|
+
|
|
37
|
+
cff.major = 1
|
|
38
|
+
|
|
39
|
+
topDictData = TopDictIndex(None)
|
|
40
|
+
for item in cff.topDictIndex:
|
|
41
|
+
# Iterate over, such that all are decompiled
|
|
42
|
+
item.cff2GetGlyphOrder = None
|
|
43
|
+
topDictData.append(item)
|
|
44
|
+
cff.topDictIndex = topDictData
|
|
45
|
+
topDict = topDictData[0]
|
|
46
|
+
|
|
47
|
+
if hasattr(topDict, "VarStore"):
|
|
48
|
+
raise ValueError("Variable CFF2 font cannot be converted to CFF format.")
|
|
49
|
+
|
|
50
|
+
opOrder = buildOrder(topDictOperators)
|
|
51
|
+
topDict.order = opOrder
|
|
52
|
+
for key in topDict.rawDict.keys():
|
|
53
|
+
if key not in opOrder:
|
|
54
|
+
del topDict.rawDict[key]
|
|
55
|
+
if hasattr(topDict, key):
|
|
56
|
+
delattr(topDict, key)
|
|
57
|
+
|
|
58
|
+
charStrings = topDict.CharStrings
|
|
59
|
+
|
|
60
|
+
fdArray = topDict.FDArray
|
|
61
|
+
if not hasattr(topDict, "FDSelect"):
|
|
62
|
+
# FDSelect is optional in CFF2, but required in CFF.
|
|
63
|
+
fdSelect = topDict.FDSelect = FDSelect()
|
|
64
|
+
fdSelect.gidArray = [0] * len(charStrings.charStrings)
|
|
65
|
+
|
|
66
|
+
defaults = buildDefaults(privateDictOperators)
|
|
67
|
+
order = buildOrder(privateDictOperators)
|
|
68
|
+
for fd in fdArray:
|
|
69
|
+
fd.setCFF2(False)
|
|
70
|
+
privateDict = fd.Private
|
|
71
|
+
privateDict.order = order
|
|
72
|
+
for key in order:
|
|
73
|
+
if key not in privateDict.rawDict and key in defaults:
|
|
74
|
+
privateDict.rawDict[key] = defaults[key]
|
|
75
|
+
for key in privateDict.rawDict.keys():
|
|
76
|
+
if key not in order:
|
|
77
|
+
del privateDict.rawDict[key]
|
|
78
|
+
if hasattr(privateDict, key):
|
|
79
|
+
delattr(privateDict, key)
|
|
80
|
+
|
|
81
|
+
# Add ending operators
|
|
82
|
+
for cs in charStrings.values():
|
|
83
|
+
cs.decompile()
|
|
84
|
+
cs.program.append("endchar")
|
|
85
|
+
for subrSets in [cff.GlobalSubrs] + [
|
|
86
|
+
getattr(fd.Private, "Subrs", []) for fd in fdArray
|
|
87
|
+
]:
|
|
88
|
+
for cs in subrSets:
|
|
89
|
+
cs.program.append("return")
|
|
90
|
+
|
|
91
|
+
# Add (optimal) width to CharStrings that need it.
|
|
92
|
+
widths = defaultdict(list)
|
|
93
|
+
metrics = otFont["hmtx"].metrics
|
|
94
|
+
for glyphName in charStrings.keys():
|
|
95
|
+
cs, fdIndex = charStrings.getItemAndSelector(glyphName)
|
|
96
|
+
if fdIndex == None:
|
|
97
|
+
fdIndex = 0
|
|
98
|
+
widths[fdIndex].append(metrics[glyphName][0])
|
|
99
|
+
for fdIndex, widthList in widths.items():
|
|
100
|
+
bestDefault, bestNominal = optimizeWidths(widthList)
|
|
101
|
+
private = fdArray[fdIndex].Private
|
|
102
|
+
private.defaultWidthX = bestDefault
|
|
103
|
+
private.nominalWidthX = bestNominal
|
|
104
|
+
for glyphName in charStrings.keys():
|
|
105
|
+
cs, fdIndex = charStrings.getItemAndSelector(glyphName)
|
|
106
|
+
if fdIndex == None:
|
|
107
|
+
fdIndex = 0
|
|
108
|
+
private = fdArray[fdIndex].Private
|
|
109
|
+
width = metrics[glyphName][0]
|
|
110
|
+
if width != private.defaultWidthX:
|
|
111
|
+
cs.program.insert(0, width - private.nominalWidthX)
|
|
112
|
+
|
|
113
|
+
# Handle stack use since stack-depth is lower in CFF than in CFF2.
|
|
114
|
+
for glyphName in charStrings.keys():
|
|
115
|
+
cs, fdIndex = charStrings.getItemAndSelector(glyphName)
|
|
116
|
+
if fdIndex is None:
|
|
117
|
+
fdIndex = 0
|
|
118
|
+
private = fdArray[fdIndex].Private
|
|
119
|
+
extractor = T2StackUseExtractor(
|
|
120
|
+
getattr(private, "Subrs", []), cff.GlobalSubrs, private=private
|
|
121
|
+
)
|
|
122
|
+
stackUse = extractor.execute(cs)
|
|
123
|
+
if stackUse > 48: # CFF stack depth is 48
|
|
124
|
+
desubroutinizeCharString(cs)
|
|
125
|
+
cs.program = specializeProgram(cs.program)
|
|
126
|
+
|
|
127
|
+
# Unused subroutines are still in CFF2 (ie. lacking 'return' operator)
|
|
128
|
+
# because they were not decompiled when we added the 'return'.
|
|
129
|
+
# Moreover, some used subroutines may have become unused after the
|
|
130
|
+
# stack-use fixup. So we remove all unused subroutines now.
|
|
131
|
+
cff.remove_unused_subroutines()
|
|
132
|
+
|
|
133
|
+
mapping = {
|
|
134
|
+
name: ("cid" + str(n).zfill(5) if n else ".notdef")
|
|
135
|
+
for n, name in enumerate(topDict.charset)
|
|
136
|
+
}
|
|
137
|
+
topDict.charset = [
|
|
138
|
+
"cid" + str(n).zfill(5) if n else ".notdef" for n in range(len(topDict.charset))
|
|
139
|
+
]
|
|
140
|
+
charStrings.charStrings = {
|
|
141
|
+
mapping[name]: v for name, v in charStrings.charStrings.items()
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
topDict.ROS = ("Adobe", "Identity", 0)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def convertCFF2ToCFF(font, *, updatePostTable=True):
|
|
148
|
+
if "CFF2" not in font:
|
|
149
|
+
raise ValueError("Input font does not contain a CFF2 table.")
|
|
150
|
+
cff = font["CFF2"].cff
|
|
151
|
+
_convertCFF2ToCFF(cff, font)
|
|
152
|
+
del font["CFF2"]
|
|
153
|
+
table = font["CFF "] = newTable("CFF ")
|
|
154
|
+
table.cff = cff
|
|
155
|
+
|
|
156
|
+
if updatePostTable and "post" in font:
|
|
157
|
+
# Only version supported for fonts with CFF table is 0x00030000 not 0x20000
|
|
158
|
+
post = font["post"]
|
|
159
|
+
if post.formatType == 2.0:
|
|
160
|
+
post.formatType = 3.0
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def main(args=None):
|
|
164
|
+
"""Convert CFF2 OTF font to CFF OTF font"""
|
|
165
|
+
if args is None:
|
|
166
|
+
import sys
|
|
167
|
+
|
|
168
|
+
args = sys.argv[1:]
|
|
169
|
+
|
|
170
|
+
import argparse
|
|
171
|
+
|
|
172
|
+
parser = argparse.ArgumentParser(
|
|
173
|
+
"fonttools cffLib.CFF2ToCFF",
|
|
174
|
+
description="Convert a non-variable CFF2 font to CFF.",
|
|
175
|
+
)
|
|
176
|
+
parser.add_argument(
|
|
177
|
+
"input", metavar="INPUT.ttf", help="Input OTF file with CFF table."
|
|
178
|
+
)
|
|
179
|
+
parser.add_argument(
|
|
180
|
+
"-o",
|
|
181
|
+
"--output",
|
|
182
|
+
metavar="OUTPUT.ttf",
|
|
183
|
+
default=None,
|
|
184
|
+
help="Output instance OTF file (default: INPUT-CFF2.ttf).",
|
|
185
|
+
)
|
|
186
|
+
parser.add_argument(
|
|
187
|
+
"--no-recalc-timestamp",
|
|
188
|
+
dest="recalc_timestamp",
|
|
189
|
+
action="store_false",
|
|
190
|
+
help="Don't set the output font's timestamp to the current time.",
|
|
191
|
+
)
|
|
192
|
+
parser.add_argument(
|
|
193
|
+
"--remove-overlaps",
|
|
194
|
+
action="store_true",
|
|
195
|
+
help="Merge overlapping contours and components. Requires skia-pathops",
|
|
196
|
+
)
|
|
197
|
+
parser.add_argument(
|
|
198
|
+
"--ignore-overlap-errors",
|
|
199
|
+
action="store_true",
|
|
200
|
+
help="Don't crash if the remove-overlaps operation fails for some glyphs.",
|
|
201
|
+
)
|
|
202
|
+
loggingGroup = parser.add_mutually_exclusive_group(required=False)
|
|
203
|
+
loggingGroup.add_argument(
|
|
204
|
+
"-v", "--verbose", action="store_true", help="Run more verbosely."
|
|
205
|
+
)
|
|
206
|
+
loggingGroup.add_argument(
|
|
207
|
+
"-q", "--quiet", action="store_true", help="Turn verbosity off."
|
|
208
|
+
)
|
|
209
|
+
options = parser.parse_args(args)
|
|
210
|
+
|
|
211
|
+
from fontTools import configLogger
|
|
212
|
+
|
|
213
|
+
configLogger(
|
|
214
|
+
level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
import os
|
|
218
|
+
|
|
219
|
+
infile = options.input
|
|
220
|
+
if not os.path.isfile(infile):
|
|
221
|
+
parser.error("No such file '{}'".format(infile))
|
|
222
|
+
|
|
223
|
+
outfile = (
|
|
224
|
+
makeOutputFileName(infile, overWrite=True, suffix="-CFF")
|
|
225
|
+
if not options.output
|
|
226
|
+
else options.output
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
font = TTFont(infile, recalcTimestamp=options.recalc_timestamp, recalcBBoxes=False)
|
|
230
|
+
|
|
231
|
+
convertCFF2ToCFF(font)
|
|
232
|
+
|
|
233
|
+
if options.remove_overlaps:
|
|
234
|
+
from fontTools.ttLib.removeOverlaps import removeOverlaps
|
|
235
|
+
from io import BytesIO
|
|
236
|
+
|
|
237
|
+
log.debug("Removing overlaps")
|
|
238
|
+
|
|
239
|
+
stream = BytesIO()
|
|
240
|
+
font.save(stream)
|
|
241
|
+
stream.seek(0)
|
|
242
|
+
font = TTFont(stream, recalcTimestamp=False, recalcBBoxes=False)
|
|
243
|
+
removeOverlaps(
|
|
244
|
+
font,
|
|
245
|
+
ignoreErrors=options.ignore_overlap_errors,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
log.info(
|
|
249
|
+
"Saving %s",
|
|
250
|
+
outfile,
|
|
251
|
+
)
|
|
252
|
+
font.save(outfile)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
if __name__ == "__main__":
|
|
256
|
+
import sys
|
|
257
|
+
|
|
258
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"""CFF to CFF2 converter."""
|
|
2
|
+
|
|
3
|
+
from fontTools.ttLib import TTFont, newTable
|
|
4
|
+
from fontTools.misc.cliTools import makeOutputFileName
|
|
5
|
+
from fontTools.misc.psCharStrings import T2WidthExtractor
|
|
6
|
+
from fontTools.cffLib import (
|
|
7
|
+
TopDictIndex,
|
|
8
|
+
FDArrayIndex,
|
|
9
|
+
FontDict,
|
|
10
|
+
buildOrder,
|
|
11
|
+
topDictOperators,
|
|
12
|
+
privateDictOperators,
|
|
13
|
+
topDictOperators2,
|
|
14
|
+
privateDictOperators2,
|
|
15
|
+
)
|
|
16
|
+
from io import BytesIO
|
|
17
|
+
import logging
|
|
18
|
+
|
|
19
|
+
__all__ = ["convertCFFToCFF2", "main"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
log = logging.getLogger("fontTools.cffLib")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _NominalWidthUsedError(Exception):
|
|
26
|
+
def __add__(self, other):
|
|
27
|
+
raise self
|
|
28
|
+
|
|
29
|
+
def __radd__(self, other):
|
|
30
|
+
raise self
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _convertCFFToCFF2(cff, otFont):
|
|
34
|
+
"""Converts this object from CFF format to CFF2 format. This conversion
|
|
35
|
+
is done 'in-place'. The conversion cannot be reversed.
|
|
36
|
+
|
|
37
|
+
This assumes a decompiled CFF table. (i.e. that the object has been
|
|
38
|
+
filled via :meth:`decompile` and e.g. not loaded from XML.)"""
|
|
39
|
+
|
|
40
|
+
# Clean up T2CharStrings
|
|
41
|
+
|
|
42
|
+
topDict = cff.topDictIndex[0]
|
|
43
|
+
fdArray = topDict.FDArray if hasattr(topDict, "FDArray") else None
|
|
44
|
+
charStrings = topDict.CharStrings
|
|
45
|
+
globalSubrs = cff.GlobalSubrs
|
|
46
|
+
localSubrs = (
|
|
47
|
+
[getattr(fd.Private, "Subrs", []) for fd in fdArray]
|
|
48
|
+
if fdArray
|
|
49
|
+
else (
|
|
50
|
+
[topDict.Private.Subrs]
|
|
51
|
+
if hasattr(topDict, "Private") and hasattr(topDict.Private, "Subrs")
|
|
52
|
+
else []
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
for glyphName in charStrings.keys():
|
|
57
|
+
cs, fdIndex = charStrings.getItemAndSelector(glyphName)
|
|
58
|
+
cs.decompile()
|
|
59
|
+
|
|
60
|
+
# Clean up subroutines first
|
|
61
|
+
for subrs in [globalSubrs] + localSubrs:
|
|
62
|
+
for subr in subrs:
|
|
63
|
+
program = subr.program
|
|
64
|
+
i = j = len(program)
|
|
65
|
+
try:
|
|
66
|
+
i = program.index("return")
|
|
67
|
+
except ValueError:
|
|
68
|
+
pass
|
|
69
|
+
try:
|
|
70
|
+
j = program.index("endchar")
|
|
71
|
+
except ValueError:
|
|
72
|
+
pass
|
|
73
|
+
program[min(i, j) :] = []
|
|
74
|
+
|
|
75
|
+
# Clean up glyph charstrings
|
|
76
|
+
removeUnusedSubrs = False
|
|
77
|
+
nominalWidthXError = _NominalWidthUsedError()
|
|
78
|
+
for glyphName in charStrings.keys():
|
|
79
|
+
cs, fdIndex = charStrings.getItemAndSelector(glyphName)
|
|
80
|
+
program = cs.program
|
|
81
|
+
|
|
82
|
+
thisLocalSubrs = (
|
|
83
|
+
localSubrs[fdIndex]
|
|
84
|
+
if fdIndex is not None
|
|
85
|
+
else (
|
|
86
|
+
getattr(topDict.Private, "Subrs", [])
|
|
87
|
+
if hasattr(topDict, "Private")
|
|
88
|
+
else []
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Intentionally use custom type for nominalWidthX, such that any
|
|
93
|
+
# CharString that has an explicit width encoded will throw back to us.
|
|
94
|
+
extractor = T2WidthExtractor(
|
|
95
|
+
thisLocalSubrs,
|
|
96
|
+
globalSubrs,
|
|
97
|
+
nominalWidthXError,
|
|
98
|
+
0,
|
|
99
|
+
)
|
|
100
|
+
try:
|
|
101
|
+
extractor.execute(cs)
|
|
102
|
+
except _NominalWidthUsedError:
|
|
103
|
+
# Program has explicit width. We want to drop it, but can't
|
|
104
|
+
# just pop the first number since it may be a subroutine call.
|
|
105
|
+
# Instead, when seeing that, we embed the subroutine and recurse.
|
|
106
|
+
# If this ever happened, we later prune unused subroutines.
|
|
107
|
+
while len(program) >= 2 and program[1] in ["callsubr", "callgsubr"]:
|
|
108
|
+
removeUnusedSubrs = True
|
|
109
|
+
subrNumber = program.pop(0)
|
|
110
|
+
assert isinstance(subrNumber, int), subrNumber
|
|
111
|
+
op = program.pop(0)
|
|
112
|
+
bias = extractor.localBias if op == "callsubr" else extractor.globalBias
|
|
113
|
+
subrNumber += bias
|
|
114
|
+
subrSet = thisLocalSubrs if op == "callsubr" else globalSubrs
|
|
115
|
+
subrProgram = subrSet[subrNumber].program
|
|
116
|
+
program[:0] = subrProgram
|
|
117
|
+
# Now pop the actual width
|
|
118
|
+
assert len(program) >= 1, program
|
|
119
|
+
program.pop(0)
|
|
120
|
+
|
|
121
|
+
if program and program[-1] == "endchar":
|
|
122
|
+
program.pop()
|
|
123
|
+
|
|
124
|
+
if removeUnusedSubrs:
|
|
125
|
+
cff.remove_unused_subroutines()
|
|
126
|
+
|
|
127
|
+
# Upconvert TopDict
|
|
128
|
+
|
|
129
|
+
cff.major = 2
|
|
130
|
+
cff2GetGlyphOrder = cff.otFont.getGlyphOrder
|
|
131
|
+
topDictData = TopDictIndex(None, cff2GetGlyphOrder)
|
|
132
|
+
for item in cff.topDictIndex:
|
|
133
|
+
# Iterate over, such that all are decompiled
|
|
134
|
+
topDictData.append(item)
|
|
135
|
+
cff.topDictIndex = topDictData
|
|
136
|
+
topDict = topDictData[0]
|
|
137
|
+
if hasattr(topDict, "Private"):
|
|
138
|
+
privateDict = topDict.Private
|
|
139
|
+
else:
|
|
140
|
+
privateDict = None
|
|
141
|
+
opOrder = buildOrder(topDictOperators2)
|
|
142
|
+
topDict.order = opOrder
|
|
143
|
+
topDict.cff2GetGlyphOrder = cff2GetGlyphOrder
|
|
144
|
+
|
|
145
|
+
if not hasattr(topDict, "FDArray"):
|
|
146
|
+
fdArray = topDict.FDArray = FDArrayIndex()
|
|
147
|
+
fdArray.strings = None
|
|
148
|
+
fdArray.GlobalSubrs = topDict.GlobalSubrs
|
|
149
|
+
topDict.GlobalSubrs.fdArray = fdArray
|
|
150
|
+
charStrings = topDict.CharStrings
|
|
151
|
+
if charStrings.charStringsAreIndexed:
|
|
152
|
+
charStrings.charStringsIndex.fdArray = fdArray
|
|
153
|
+
else:
|
|
154
|
+
charStrings.fdArray = fdArray
|
|
155
|
+
fontDict = FontDict()
|
|
156
|
+
fontDict.setCFF2(True)
|
|
157
|
+
fdArray.append(fontDict)
|
|
158
|
+
fontDict.Private = privateDict
|
|
159
|
+
privateOpOrder = buildOrder(privateDictOperators2)
|
|
160
|
+
if privateDict is not None:
|
|
161
|
+
for entry in privateDictOperators:
|
|
162
|
+
key = entry[1]
|
|
163
|
+
if key not in privateOpOrder:
|
|
164
|
+
if key in privateDict.rawDict:
|
|
165
|
+
# print "Removing private dict", key
|
|
166
|
+
del privateDict.rawDict[key]
|
|
167
|
+
if hasattr(privateDict, key):
|
|
168
|
+
delattr(privateDict, key)
|
|
169
|
+
# print "Removing privateDict attr", key
|
|
170
|
+
else:
|
|
171
|
+
# clean up the PrivateDicts in the fdArray
|
|
172
|
+
fdArray = topDict.FDArray
|
|
173
|
+
privateOpOrder = buildOrder(privateDictOperators2)
|
|
174
|
+
for fontDict in fdArray:
|
|
175
|
+
fontDict.setCFF2(True)
|
|
176
|
+
for key in list(fontDict.rawDict.keys()):
|
|
177
|
+
if key not in fontDict.order:
|
|
178
|
+
del fontDict.rawDict[key]
|
|
179
|
+
if hasattr(fontDict, key):
|
|
180
|
+
delattr(fontDict, key)
|
|
181
|
+
|
|
182
|
+
privateDict = fontDict.Private
|
|
183
|
+
for entry in privateDictOperators:
|
|
184
|
+
key = entry[1]
|
|
185
|
+
if key not in privateOpOrder:
|
|
186
|
+
if key in list(privateDict.rawDict.keys()):
|
|
187
|
+
# print "Removing private dict", key
|
|
188
|
+
del privateDict.rawDict[key]
|
|
189
|
+
if hasattr(privateDict, key):
|
|
190
|
+
delattr(privateDict, key)
|
|
191
|
+
# print "Removing privateDict attr", key
|
|
192
|
+
|
|
193
|
+
# Now delete up the deprecated topDict operators from CFF 1.0
|
|
194
|
+
for entry in topDictOperators:
|
|
195
|
+
key = entry[1]
|
|
196
|
+
# We seem to need to keep the charset operator for now,
|
|
197
|
+
# or we fail to compile with some fonts, like AdditionFont.otf.
|
|
198
|
+
# I don't know which kind of CFF font those are. But keeping
|
|
199
|
+
# charset seems to work. It will be removed when we save and
|
|
200
|
+
# read the font again.
|
|
201
|
+
#
|
|
202
|
+
# AdditionFont.otf has <Encoding name="StandardEncoding"/>.
|
|
203
|
+
if key == "charset":
|
|
204
|
+
continue
|
|
205
|
+
if key not in opOrder:
|
|
206
|
+
if key in topDict.rawDict:
|
|
207
|
+
del topDict.rawDict[key]
|
|
208
|
+
if hasattr(topDict, key):
|
|
209
|
+
delattr(topDict, key)
|
|
210
|
+
|
|
211
|
+
# TODO(behdad): What does the following comment even mean? Both CFF and CFF2
|
|
212
|
+
# use the same T2Charstring class. I *think* what it means is that the CharStrings
|
|
213
|
+
# were loaded for CFF1, and we need to reload them for CFF2 to set varstore, etc
|
|
214
|
+
# on them. At least that's what I understand. It's probably safe to remove this
|
|
215
|
+
# and just set vstore where needed.
|
|
216
|
+
#
|
|
217
|
+
# See comment above about charset as well.
|
|
218
|
+
|
|
219
|
+
# At this point, the Subrs and Charstrings are all still T2Charstring class
|
|
220
|
+
# easiest to fix this by compiling, then decompiling again
|
|
221
|
+
file = BytesIO()
|
|
222
|
+
cff.compile(file, otFont, isCFF2=True)
|
|
223
|
+
file.seek(0)
|
|
224
|
+
cff.decompile(file, otFont, isCFF2=True)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def convertCFFToCFF2(font):
|
|
228
|
+
cff = font["CFF "].cff
|
|
229
|
+
del font["CFF "]
|
|
230
|
+
_convertCFFToCFF2(cff, font)
|
|
231
|
+
table = font["CFF2"] = newTable("CFF2")
|
|
232
|
+
table.cff = cff
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def main(args=None):
|
|
236
|
+
"""Convert CFF OTF font to CFF2 OTF font"""
|
|
237
|
+
if args is None:
|
|
238
|
+
import sys
|
|
239
|
+
|
|
240
|
+
args = sys.argv[1:]
|
|
241
|
+
|
|
242
|
+
import argparse
|
|
243
|
+
|
|
244
|
+
parser = argparse.ArgumentParser(
|
|
245
|
+
"fonttools cffLib.CFFToCFF2",
|
|
246
|
+
description="Upgrade a CFF font to CFF2.",
|
|
247
|
+
)
|
|
248
|
+
parser.add_argument(
|
|
249
|
+
"input", metavar="INPUT.ttf", help="Input OTF file with CFF table."
|
|
250
|
+
)
|
|
251
|
+
parser.add_argument(
|
|
252
|
+
"-o",
|
|
253
|
+
"--output",
|
|
254
|
+
metavar="OUTPUT.ttf",
|
|
255
|
+
default=None,
|
|
256
|
+
help="Output instance OTF file (default: INPUT-CFF2.ttf).",
|
|
257
|
+
)
|
|
258
|
+
parser.add_argument(
|
|
259
|
+
"--no-recalc-timestamp",
|
|
260
|
+
dest="recalc_timestamp",
|
|
261
|
+
action="store_false",
|
|
262
|
+
help="Don't set the output font's timestamp to the current time.",
|
|
263
|
+
)
|
|
264
|
+
loggingGroup = parser.add_mutually_exclusive_group(required=False)
|
|
265
|
+
loggingGroup.add_argument(
|
|
266
|
+
"-v", "--verbose", action="store_true", help="Run more verbosely."
|
|
267
|
+
)
|
|
268
|
+
loggingGroup.add_argument(
|
|
269
|
+
"-q", "--quiet", action="store_true", help="Turn verbosity off."
|
|
270
|
+
)
|
|
271
|
+
options = parser.parse_args(args)
|
|
272
|
+
|
|
273
|
+
from fontTools import configLogger
|
|
274
|
+
|
|
275
|
+
configLogger(
|
|
276
|
+
level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
import os
|
|
280
|
+
|
|
281
|
+
infile = options.input
|
|
282
|
+
if not os.path.isfile(infile):
|
|
283
|
+
parser.error("No such file '{}'".format(infile))
|
|
284
|
+
|
|
285
|
+
outfile = (
|
|
286
|
+
makeOutputFileName(infile, overWrite=True, suffix="-CFF2")
|
|
287
|
+
if not options.output
|
|
288
|
+
else options.output
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
font = TTFont(infile, recalcTimestamp=options.recalc_timestamp, recalcBBoxes=False)
|
|
292
|
+
|
|
293
|
+
convertCFFToCFF2(font)
|
|
294
|
+
|
|
295
|
+
log.info(
|
|
296
|
+
"Saving %s",
|
|
297
|
+
outfile,
|
|
298
|
+
)
|
|
299
|
+
font.save(outfile)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
if __name__ == "__main__":
|
|
303
|
+
import sys
|
|
304
|
+
|
|
305
|
+
sys.exit(main(sys.argv[1:]))
|