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.
Files changed (353) hide show
  1. fontTools/__init__.py +8 -0
  2. fontTools/__main__.py +35 -0
  3. fontTools/afmLib.py +439 -0
  4. fontTools/agl.py +5233 -0
  5. fontTools/annotations.py +30 -0
  6. fontTools/cffLib/CFF2ToCFF.py +258 -0
  7. fontTools/cffLib/CFFToCFF2.py +305 -0
  8. fontTools/cffLib/__init__.py +3694 -0
  9. fontTools/cffLib/specializer.py +927 -0
  10. fontTools/cffLib/transforms.py +495 -0
  11. fontTools/cffLib/width.py +210 -0
  12. fontTools/colorLib/__init__.py +0 -0
  13. fontTools/colorLib/builder.py +664 -0
  14. fontTools/colorLib/errors.py +2 -0
  15. fontTools/colorLib/geometry.py +143 -0
  16. fontTools/colorLib/table_builder.py +223 -0
  17. fontTools/colorLib/unbuilder.py +81 -0
  18. fontTools/config/__init__.py +90 -0
  19. fontTools/cu2qu/__init__.py +15 -0
  20. fontTools/cu2qu/__main__.py +6 -0
  21. fontTools/cu2qu/benchmark.py +54 -0
  22. fontTools/cu2qu/cli.py +198 -0
  23. fontTools/cu2qu/cu2qu.c +15817 -0
  24. fontTools/cu2qu/cu2qu.cp311-win32.pyd +0 -0
  25. fontTools/cu2qu/cu2qu.py +563 -0
  26. fontTools/cu2qu/errors.py +77 -0
  27. fontTools/cu2qu/ufo.py +363 -0
  28. fontTools/designspaceLib/__init__.py +3343 -0
  29. fontTools/designspaceLib/__main__.py +6 -0
  30. fontTools/designspaceLib/split.py +475 -0
  31. fontTools/designspaceLib/statNames.py +260 -0
  32. fontTools/designspaceLib/types.py +147 -0
  33. fontTools/encodings/MacRoman.py +258 -0
  34. fontTools/encodings/StandardEncoding.py +258 -0
  35. fontTools/encodings/__init__.py +1 -0
  36. fontTools/encodings/codecs.py +135 -0
  37. fontTools/feaLib/__init__.py +4 -0
  38. fontTools/feaLib/__main__.py +78 -0
  39. fontTools/feaLib/ast.py +2143 -0
  40. fontTools/feaLib/builder.py +1814 -0
  41. fontTools/feaLib/error.py +22 -0
  42. fontTools/feaLib/lexer.c +17029 -0
  43. fontTools/feaLib/lexer.cp311-win32.pyd +0 -0
  44. fontTools/feaLib/lexer.py +287 -0
  45. fontTools/feaLib/location.py +12 -0
  46. fontTools/feaLib/lookupDebugInfo.py +12 -0
  47. fontTools/feaLib/parser.py +2394 -0
  48. fontTools/feaLib/variableScalar.py +118 -0
  49. fontTools/fontBuilder.py +1014 -0
  50. fontTools/help.py +36 -0
  51. fontTools/merge/__init__.py +248 -0
  52. fontTools/merge/__main__.py +6 -0
  53. fontTools/merge/base.py +81 -0
  54. fontTools/merge/cmap.py +173 -0
  55. fontTools/merge/layout.py +526 -0
  56. fontTools/merge/options.py +85 -0
  57. fontTools/merge/tables.py +352 -0
  58. fontTools/merge/unicode.py +78 -0
  59. fontTools/merge/util.py +143 -0
  60. fontTools/misc/__init__.py +1 -0
  61. fontTools/misc/arrayTools.py +424 -0
  62. fontTools/misc/bezierTools.c +39731 -0
  63. fontTools/misc/bezierTools.cp311-win32.pyd +0 -0
  64. fontTools/misc/bezierTools.py +1500 -0
  65. fontTools/misc/classifyTools.py +170 -0
  66. fontTools/misc/cliTools.py +53 -0
  67. fontTools/misc/configTools.py +349 -0
  68. fontTools/misc/cython.py +27 -0
  69. fontTools/misc/dictTools.py +83 -0
  70. fontTools/misc/eexec.py +119 -0
  71. fontTools/misc/encodingTools.py +72 -0
  72. fontTools/misc/enumTools.py +23 -0
  73. fontTools/misc/etree.py +456 -0
  74. fontTools/misc/filenames.py +245 -0
  75. fontTools/misc/filesystem/__init__.py +68 -0
  76. fontTools/misc/filesystem/_base.py +134 -0
  77. fontTools/misc/filesystem/_copy.py +45 -0
  78. fontTools/misc/filesystem/_errors.py +54 -0
  79. fontTools/misc/filesystem/_info.py +75 -0
  80. fontTools/misc/filesystem/_osfs.py +164 -0
  81. fontTools/misc/filesystem/_path.py +67 -0
  82. fontTools/misc/filesystem/_subfs.py +92 -0
  83. fontTools/misc/filesystem/_tempfs.py +34 -0
  84. fontTools/misc/filesystem/_tools.py +34 -0
  85. fontTools/misc/filesystem/_walk.py +55 -0
  86. fontTools/misc/filesystem/_zipfs.py +204 -0
  87. fontTools/misc/fixedTools.py +253 -0
  88. fontTools/misc/intTools.py +25 -0
  89. fontTools/misc/iterTools.py +12 -0
  90. fontTools/misc/lazyTools.py +42 -0
  91. fontTools/misc/loggingTools.py +543 -0
  92. fontTools/misc/macCreatorType.py +56 -0
  93. fontTools/misc/macRes.py +261 -0
  94. fontTools/misc/plistlib/__init__.py +681 -0
  95. fontTools/misc/plistlib/py.typed +0 -0
  96. fontTools/misc/psCharStrings.py +1511 -0
  97. fontTools/misc/psLib.py +398 -0
  98. fontTools/misc/psOperators.py +572 -0
  99. fontTools/misc/py23.py +96 -0
  100. fontTools/misc/roundTools.py +110 -0
  101. fontTools/misc/sstruct.py +227 -0
  102. fontTools/misc/symfont.py +242 -0
  103. fontTools/misc/testTools.py +233 -0
  104. fontTools/misc/textTools.py +156 -0
  105. fontTools/misc/timeTools.py +88 -0
  106. fontTools/misc/transform.py +516 -0
  107. fontTools/misc/treeTools.py +45 -0
  108. fontTools/misc/vector.py +147 -0
  109. fontTools/misc/visitor.py +158 -0
  110. fontTools/misc/xmlReader.py +188 -0
  111. fontTools/misc/xmlWriter.py +231 -0
  112. fontTools/mtiLib/__init__.py +1400 -0
  113. fontTools/mtiLib/__main__.py +5 -0
  114. fontTools/otlLib/__init__.py +1 -0
  115. fontTools/otlLib/builder.py +3465 -0
  116. fontTools/otlLib/error.py +11 -0
  117. fontTools/otlLib/maxContextCalc.py +96 -0
  118. fontTools/otlLib/optimize/__init__.py +53 -0
  119. fontTools/otlLib/optimize/__main__.py +6 -0
  120. fontTools/otlLib/optimize/gpos.py +439 -0
  121. fontTools/pens/__init__.py +1 -0
  122. fontTools/pens/areaPen.py +52 -0
  123. fontTools/pens/basePen.py +475 -0
  124. fontTools/pens/boundsPen.py +98 -0
  125. fontTools/pens/cairoPen.py +26 -0
  126. fontTools/pens/cocoaPen.py +26 -0
  127. fontTools/pens/cu2quPen.py +325 -0
  128. fontTools/pens/explicitClosingLinePen.py +101 -0
  129. fontTools/pens/filterPen.py +433 -0
  130. fontTools/pens/freetypePen.py +462 -0
  131. fontTools/pens/hashPointPen.py +89 -0
  132. fontTools/pens/momentsPen.c +13378 -0
  133. fontTools/pens/momentsPen.cp311-win32.pyd +0 -0
  134. fontTools/pens/momentsPen.py +879 -0
  135. fontTools/pens/perimeterPen.py +69 -0
  136. fontTools/pens/pointInsidePen.py +192 -0
  137. fontTools/pens/pointPen.py +643 -0
  138. fontTools/pens/qtPen.py +29 -0
  139. fontTools/pens/qu2cuPen.py +105 -0
  140. fontTools/pens/quartzPen.py +43 -0
  141. fontTools/pens/recordingPen.py +335 -0
  142. fontTools/pens/reportLabPen.py +79 -0
  143. fontTools/pens/reverseContourPen.py +96 -0
  144. fontTools/pens/roundingPen.py +130 -0
  145. fontTools/pens/statisticsPen.py +312 -0
  146. fontTools/pens/svgPathPen.py +310 -0
  147. fontTools/pens/t2CharStringPen.py +88 -0
  148. fontTools/pens/teePen.py +55 -0
  149. fontTools/pens/transformPen.py +115 -0
  150. fontTools/pens/ttGlyphPen.py +335 -0
  151. fontTools/pens/wxPen.py +29 -0
  152. fontTools/qu2cu/__init__.py +15 -0
  153. fontTools/qu2cu/__main__.py +7 -0
  154. fontTools/qu2cu/benchmark.py +56 -0
  155. fontTools/qu2cu/cli.py +125 -0
  156. fontTools/qu2cu/qu2cu.c +16682 -0
  157. fontTools/qu2cu/qu2cu.cp311-win32.pyd +0 -0
  158. fontTools/qu2cu/qu2cu.py +405 -0
  159. fontTools/subset/__init__.py +4096 -0
  160. fontTools/subset/__main__.py +6 -0
  161. fontTools/subset/cff.py +184 -0
  162. fontTools/subset/svg.py +253 -0
  163. fontTools/subset/util.py +25 -0
  164. fontTools/svgLib/__init__.py +3 -0
  165. fontTools/svgLib/path/__init__.py +65 -0
  166. fontTools/svgLib/path/arc.py +154 -0
  167. fontTools/svgLib/path/parser.py +322 -0
  168. fontTools/svgLib/path/shapes.py +183 -0
  169. fontTools/t1Lib/__init__.py +648 -0
  170. fontTools/tfmLib.py +460 -0
  171. fontTools/ttLib/__init__.py +30 -0
  172. fontTools/ttLib/__main__.py +148 -0
  173. fontTools/ttLib/macUtils.py +54 -0
  174. fontTools/ttLib/removeOverlaps.py +395 -0
  175. fontTools/ttLib/reorderGlyphs.py +285 -0
  176. fontTools/ttLib/scaleUpem.py +436 -0
  177. fontTools/ttLib/sfnt.py +661 -0
  178. fontTools/ttLib/standardGlyphOrder.py +271 -0
  179. fontTools/ttLib/tables/B_A_S_E_.py +14 -0
  180. fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
  181. fontTools/ttLib/tables/C_B_D_T_.py +113 -0
  182. fontTools/ttLib/tables/C_B_L_C_.py +19 -0
  183. fontTools/ttLib/tables/C_F_F_.py +61 -0
  184. fontTools/ttLib/tables/C_F_F__2.py +26 -0
  185. fontTools/ttLib/tables/C_O_L_R_.py +165 -0
  186. fontTools/ttLib/tables/C_P_A_L_.py +305 -0
  187. fontTools/ttLib/tables/D_S_I_G_.py +158 -0
  188. fontTools/ttLib/tables/D__e_b_g.py +35 -0
  189. fontTools/ttLib/tables/DefaultTable.py +49 -0
  190. fontTools/ttLib/tables/E_B_D_T_.py +835 -0
  191. fontTools/ttLib/tables/E_B_L_C_.py +718 -0
  192. fontTools/ttLib/tables/F_F_T_M_.py +52 -0
  193. fontTools/ttLib/tables/F__e_a_t.py +149 -0
  194. fontTools/ttLib/tables/G_D_E_F_.py +13 -0
  195. fontTools/ttLib/tables/G_M_A_P_.py +148 -0
  196. fontTools/ttLib/tables/G_P_K_G_.py +133 -0
  197. fontTools/ttLib/tables/G_P_O_S_.py +14 -0
  198. fontTools/ttLib/tables/G_S_U_B_.py +13 -0
  199. fontTools/ttLib/tables/G_V_A_R_.py +5 -0
  200. fontTools/ttLib/tables/G__l_a_t.py +235 -0
  201. fontTools/ttLib/tables/G__l_o_c.py +85 -0
  202. fontTools/ttLib/tables/H_V_A_R_.py +13 -0
  203. fontTools/ttLib/tables/J_S_T_F_.py +13 -0
  204. fontTools/ttLib/tables/L_T_S_H_.py +58 -0
  205. fontTools/ttLib/tables/M_A_T_H_.py +13 -0
  206. fontTools/ttLib/tables/M_E_T_A_.py +352 -0
  207. fontTools/ttLib/tables/M_V_A_R_.py +13 -0
  208. fontTools/ttLib/tables/O_S_2f_2.py +752 -0
  209. fontTools/ttLib/tables/S_I_N_G_.py +99 -0
  210. fontTools/ttLib/tables/S_T_A_T_.py +15 -0
  211. fontTools/ttLib/tables/S_V_G_.py +223 -0
  212. fontTools/ttLib/tables/S__i_l_f.py +1040 -0
  213. fontTools/ttLib/tables/S__i_l_l.py +92 -0
  214. fontTools/ttLib/tables/T_S_I_B_.py +13 -0
  215. fontTools/ttLib/tables/T_S_I_C_.py +14 -0
  216. fontTools/ttLib/tables/T_S_I_D_.py +13 -0
  217. fontTools/ttLib/tables/T_S_I_J_.py +13 -0
  218. fontTools/ttLib/tables/T_S_I_P_.py +13 -0
  219. fontTools/ttLib/tables/T_S_I_S_.py +13 -0
  220. fontTools/ttLib/tables/T_S_I_V_.py +26 -0
  221. fontTools/ttLib/tables/T_S_I__0.py +70 -0
  222. fontTools/ttLib/tables/T_S_I__1.py +163 -0
  223. fontTools/ttLib/tables/T_S_I__2.py +17 -0
  224. fontTools/ttLib/tables/T_S_I__3.py +22 -0
  225. fontTools/ttLib/tables/T_S_I__5.py +60 -0
  226. fontTools/ttLib/tables/T_T_F_A_.py +14 -0
  227. fontTools/ttLib/tables/TupleVariation.py +884 -0
  228. fontTools/ttLib/tables/V_A_R_C_.py +12 -0
  229. fontTools/ttLib/tables/V_D_M_X_.py +249 -0
  230. fontTools/ttLib/tables/V_O_R_G_.py +165 -0
  231. fontTools/ttLib/tables/V_V_A_R_.py +13 -0
  232. fontTools/ttLib/tables/__init__.py +98 -0
  233. fontTools/ttLib/tables/_a_n_k_r.py +15 -0
  234. fontTools/ttLib/tables/_a_v_a_r.py +193 -0
  235. fontTools/ttLib/tables/_b_s_l_n.py +15 -0
  236. fontTools/ttLib/tables/_c_i_d_g.py +24 -0
  237. fontTools/ttLib/tables/_c_m_a_p.py +1591 -0
  238. fontTools/ttLib/tables/_c_v_a_r.py +94 -0
  239. fontTools/ttLib/tables/_c_v_t.py +56 -0
  240. fontTools/ttLib/tables/_f_e_a_t.py +15 -0
  241. fontTools/ttLib/tables/_f_p_g_m.py +62 -0
  242. fontTools/ttLib/tables/_f_v_a_r.py +261 -0
  243. fontTools/ttLib/tables/_g_a_s_p.py +63 -0
  244. fontTools/ttLib/tables/_g_c_i_d.py +13 -0
  245. fontTools/ttLib/tables/_g_l_y_f.py +2311 -0
  246. fontTools/ttLib/tables/_g_v_a_r.py +340 -0
  247. fontTools/ttLib/tables/_h_d_m_x.py +127 -0
  248. fontTools/ttLib/tables/_h_e_a_d.py +130 -0
  249. fontTools/ttLib/tables/_h_h_e_a.py +147 -0
  250. fontTools/ttLib/tables/_h_m_t_x.py +164 -0
  251. fontTools/ttLib/tables/_k_e_r_n.py +289 -0
  252. fontTools/ttLib/tables/_l_c_a_r.py +13 -0
  253. fontTools/ttLib/tables/_l_o_c_a.py +70 -0
  254. fontTools/ttLib/tables/_l_t_a_g.py +72 -0
  255. fontTools/ttLib/tables/_m_a_x_p.py +147 -0
  256. fontTools/ttLib/tables/_m_e_t_a.py +112 -0
  257. fontTools/ttLib/tables/_m_o_r_t.py +14 -0
  258. fontTools/ttLib/tables/_m_o_r_x.py +15 -0
  259. fontTools/ttLib/tables/_n_a_m_e.py +1242 -0
  260. fontTools/ttLib/tables/_o_p_b_d.py +14 -0
  261. fontTools/ttLib/tables/_p_o_s_t.py +319 -0
  262. fontTools/ttLib/tables/_p_r_e_p.py +16 -0
  263. fontTools/ttLib/tables/_p_r_o_p.py +12 -0
  264. fontTools/ttLib/tables/_s_b_i_x.py +129 -0
  265. fontTools/ttLib/tables/_t_r_a_k.py +332 -0
  266. fontTools/ttLib/tables/_v_h_e_a.py +139 -0
  267. fontTools/ttLib/tables/_v_m_t_x.py +19 -0
  268. fontTools/ttLib/tables/asciiTable.py +20 -0
  269. fontTools/ttLib/tables/grUtils.py +92 -0
  270. fontTools/ttLib/tables/otBase.py +1458 -0
  271. fontTools/ttLib/tables/otConverters.py +2068 -0
  272. fontTools/ttLib/tables/otData.py +6400 -0
  273. fontTools/ttLib/tables/otTables.py +2703 -0
  274. fontTools/ttLib/tables/otTraverse.py +163 -0
  275. fontTools/ttLib/tables/sbixGlyph.py +149 -0
  276. fontTools/ttLib/tables/sbixStrike.py +177 -0
  277. fontTools/ttLib/tables/table_API_readme.txt +91 -0
  278. fontTools/ttLib/tables/ttProgram.py +594 -0
  279. fontTools/ttLib/ttCollection.py +125 -0
  280. fontTools/ttLib/ttFont.py +1148 -0
  281. fontTools/ttLib/ttGlyphSet.py +490 -0
  282. fontTools/ttLib/ttVisitor.py +32 -0
  283. fontTools/ttLib/woff2.py +1680 -0
  284. fontTools/ttx.py +479 -0
  285. fontTools/ufoLib/__init__.py +2575 -0
  286. fontTools/ufoLib/converters.py +407 -0
  287. fontTools/ufoLib/errors.py +30 -0
  288. fontTools/ufoLib/etree.py +6 -0
  289. fontTools/ufoLib/filenames.py +356 -0
  290. fontTools/ufoLib/glifLib.py +2120 -0
  291. fontTools/ufoLib/kerning.py +141 -0
  292. fontTools/ufoLib/plistlib.py +47 -0
  293. fontTools/ufoLib/pointPen.py +6 -0
  294. fontTools/ufoLib/utils.py +107 -0
  295. fontTools/ufoLib/validators.py +1208 -0
  296. fontTools/unicode.py +50 -0
  297. fontTools/unicodedata/Blocks.py +817 -0
  298. fontTools/unicodedata/Mirrored.py +446 -0
  299. fontTools/unicodedata/OTTags.py +50 -0
  300. fontTools/unicodedata/ScriptExtensions.py +832 -0
  301. fontTools/unicodedata/Scripts.py +3639 -0
  302. fontTools/unicodedata/__init__.py +306 -0
  303. fontTools/varLib/__init__.py +1600 -0
  304. fontTools/varLib/__main__.py +6 -0
  305. fontTools/varLib/avar/__init__.py +0 -0
  306. fontTools/varLib/avar/__main__.py +72 -0
  307. fontTools/varLib/avar/build.py +79 -0
  308. fontTools/varLib/avar/map.py +108 -0
  309. fontTools/varLib/avar/plan.py +1004 -0
  310. fontTools/varLib/avar/unbuild.py +271 -0
  311. fontTools/varLib/avarPlanner.py +8 -0
  312. fontTools/varLib/builder.py +215 -0
  313. fontTools/varLib/cff.py +631 -0
  314. fontTools/varLib/errors.py +219 -0
  315. fontTools/varLib/featureVars.py +703 -0
  316. fontTools/varLib/hvar.py +113 -0
  317. fontTools/varLib/instancer/__init__.py +2052 -0
  318. fontTools/varLib/instancer/__main__.py +5 -0
  319. fontTools/varLib/instancer/featureVars.py +190 -0
  320. fontTools/varLib/instancer/names.py +388 -0
  321. fontTools/varLib/instancer/solver.py +309 -0
  322. fontTools/varLib/interpolatable.py +1209 -0
  323. fontTools/varLib/interpolatableHelpers.py +399 -0
  324. fontTools/varLib/interpolatablePlot.py +1269 -0
  325. fontTools/varLib/interpolatableTestContourOrder.py +82 -0
  326. fontTools/varLib/interpolatableTestStartingPoint.py +107 -0
  327. fontTools/varLib/interpolate_layout.py +124 -0
  328. fontTools/varLib/iup.c +19815 -0
  329. fontTools/varLib/iup.cp311-win32.pyd +0 -0
  330. fontTools/varLib/iup.py +490 -0
  331. fontTools/varLib/merger.py +1717 -0
  332. fontTools/varLib/models.py +642 -0
  333. fontTools/varLib/multiVarStore.py +253 -0
  334. fontTools/varLib/mutator.py +529 -0
  335. fontTools/varLib/mvar.py +40 -0
  336. fontTools/varLib/plot.py +238 -0
  337. fontTools/varLib/stat.py +149 -0
  338. fontTools/varLib/varStore.py +739 -0
  339. fontTools/voltLib/__init__.py +5 -0
  340. fontTools/voltLib/__main__.py +206 -0
  341. fontTools/voltLib/ast.py +452 -0
  342. fontTools/voltLib/error.py +12 -0
  343. fontTools/voltLib/lexer.py +99 -0
  344. fontTools/voltLib/parser.py +664 -0
  345. fontTools/voltLib/voltToFea.py +911 -0
  346. fonttools-4.60.2.data/data/share/man/man1/ttx.1 +225 -0
  347. fonttools-4.60.2.dist-info/METADATA +2250 -0
  348. fonttools-4.60.2.dist-info/RECORD +353 -0
  349. fonttools-4.60.2.dist-info/WHEEL +5 -0
  350. fonttools-4.60.2.dist-info/entry_points.txt +5 -0
  351. fonttools-4.60.2.dist-info/licenses/LICENSE +21 -0
  352. fonttools-4.60.2.dist-info/licenses/LICENSE.external +388 -0
  353. fonttools-4.60.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,310 @@
1
+ from typing import Callable
2
+ from fontTools.pens.basePen import BasePen
3
+
4
+
5
+ def pointToString(pt, ntos=str):
6
+ return " ".join(ntos(i) for i in pt)
7
+
8
+
9
+ class SVGPathPen(BasePen):
10
+ """Pen to draw SVG path d commands.
11
+
12
+ Args:
13
+ glyphSet: a dictionary of drawable glyph objects keyed by name
14
+ used to resolve component references in composite glyphs.
15
+ ntos: a callable that takes a number and returns a string, to
16
+ customize how numbers are formatted (default: str).
17
+
18
+ :Example:
19
+ .. code-block::
20
+
21
+ >>> pen = SVGPathPen(None)
22
+ >>> pen.moveTo((0, 0))
23
+ >>> pen.lineTo((1, 1))
24
+ >>> pen.curveTo((2, 2), (3, 3), (4, 4))
25
+ >>> pen.closePath()
26
+ >>> pen.getCommands()
27
+ 'M0 0 1 1C2 2 3 3 4 4Z'
28
+
29
+ Note:
30
+ Fonts have a coordinate system where Y grows up, whereas in SVG,
31
+ Y grows down. As such, rendering path data from this pen in
32
+ SVG typically results in upside-down glyphs. You can fix this
33
+ by wrapping the data from this pen in an SVG group element with
34
+ transform, or wrap this pen in a transform pen. For example:
35
+ .. code-block:: python
36
+
37
+ spen = svgPathPen.SVGPathPen(glyphset)
38
+ pen= TransformPen(spen , (1, 0, 0, -1, 0, 0))
39
+ glyphset[glyphname].draw(pen)
40
+ print(tpen.getCommands())
41
+ """
42
+
43
+ def __init__(self, glyphSet, ntos: Callable[[float], str] = str):
44
+ BasePen.__init__(self, glyphSet)
45
+ self._commands = []
46
+ self._lastCommand = None
47
+ self._lastX = None
48
+ self._lastY = None
49
+ self._ntos = ntos
50
+
51
+ def _handleAnchor(self):
52
+ """
53
+ >>> pen = SVGPathPen(None)
54
+ >>> pen.moveTo((0, 0))
55
+ >>> pen.moveTo((10, 10))
56
+ >>> pen._commands
57
+ ['M10 10']
58
+ """
59
+ if self._lastCommand == "M":
60
+ self._commands.pop(-1)
61
+
62
+ def _moveTo(self, pt):
63
+ """
64
+ >>> pen = SVGPathPen(None)
65
+ >>> pen.moveTo((0, 0))
66
+ >>> pen._commands
67
+ ['M0 0']
68
+
69
+ >>> pen = SVGPathPen(None)
70
+ >>> pen.moveTo((10, 0))
71
+ >>> pen._commands
72
+ ['M10 0']
73
+
74
+ >>> pen = SVGPathPen(None)
75
+ >>> pen.moveTo((0, 10))
76
+ >>> pen._commands
77
+ ['M0 10']
78
+ """
79
+ self._handleAnchor()
80
+ t = "M%s" % (pointToString(pt, self._ntos))
81
+ self._commands.append(t)
82
+ self._lastCommand = "M"
83
+ self._lastX, self._lastY = pt
84
+
85
+ def _lineTo(self, pt):
86
+ """
87
+ # duplicate point
88
+ >>> pen = SVGPathPen(None)
89
+ >>> pen.moveTo((10, 10))
90
+ >>> pen.lineTo((10, 10))
91
+ >>> pen._commands
92
+ ['M10 10']
93
+
94
+ # vertical line
95
+ >>> pen = SVGPathPen(None)
96
+ >>> pen.moveTo((10, 10))
97
+ >>> pen.lineTo((10, 0))
98
+ >>> pen._commands
99
+ ['M10 10', 'V0']
100
+
101
+ # horizontal line
102
+ >>> pen = SVGPathPen(None)
103
+ >>> pen.moveTo((10, 10))
104
+ >>> pen.lineTo((0, 10))
105
+ >>> pen._commands
106
+ ['M10 10', 'H0']
107
+
108
+ # basic
109
+ >>> pen = SVGPathPen(None)
110
+ >>> pen.lineTo((70, 80))
111
+ >>> pen._commands
112
+ ['L70 80']
113
+
114
+ # basic following a moveto
115
+ >>> pen = SVGPathPen(None)
116
+ >>> pen.moveTo((0, 0))
117
+ >>> pen.lineTo((10, 10))
118
+ >>> pen._commands
119
+ ['M0 0', ' 10 10']
120
+ """
121
+ x, y = pt
122
+ # duplicate point
123
+ if x == self._lastX and y == self._lastY:
124
+ return
125
+ # vertical line
126
+ elif x == self._lastX:
127
+ cmd = "V"
128
+ pts = self._ntos(y)
129
+ # horizontal line
130
+ elif y == self._lastY:
131
+ cmd = "H"
132
+ pts = self._ntos(x)
133
+ # previous was a moveto
134
+ elif self._lastCommand == "M":
135
+ cmd = None
136
+ pts = " " + pointToString(pt, self._ntos)
137
+ # basic
138
+ else:
139
+ cmd = "L"
140
+ pts = pointToString(pt, self._ntos)
141
+ # write the string
142
+ t = ""
143
+ if cmd:
144
+ t += cmd
145
+ self._lastCommand = cmd
146
+ t += pts
147
+ self._commands.append(t)
148
+ # store for future reference
149
+ self._lastX, self._lastY = pt
150
+
151
+ def _curveToOne(self, pt1, pt2, pt3):
152
+ """
153
+ >>> pen = SVGPathPen(None)
154
+ >>> pen.curveTo((10, 20), (30, 40), (50, 60))
155
+ >>> pen._commands
156
+ ['C10 20 30 40 50 60']
157
+ """
158
+ t = "C"
159
+ t += pointToString(pt1, self._ntos) + " "
160
+ t += pointToString(pt2, self._ntos) + " "
161
+ t += pointToString(pt3, self._ntos)
162
+ self._commands.append(t)
163
+ self._lastCommand = "C"
164
+ self._lastX, self._lastY = pt3
165
+
166
+ def _qCurveToOne(self, pt1, pt2):
167
+ """
168
+ >>> pen = SVGPathPen(None)
169
+ >>> pen.qCurveTo((10, 20), (30, 40))
170
+ >>> pen._commands
171
+ ['Q10 20 30 40']
172
+ >>> from fontTools.misc.roundTools import otRound
173
+ >>> pen = SVGPathPen(None, ntos=lambda v: str(otRound(v)))
174
+ >>> pen.qCurveTo((3, 3), (7, 5), (11, 4))
175
+ >>> pen._commands
176
+ ['Q3 3 5 4', 'Q7 5 11 4']
177
+ """
178
+ assert pt2 is not None
179
+ t = "Q"
180
+ t += pointToString(pt1, self._ntos) + " "
181
+ t += pointToString(pt2, self._ntos)
182
+ self._commands.append(t)
183
+ self._lastCommand = "Q"
184
+ self._lastX, self._lastY = pt2
185
+
186
+ def _closePath(self):
187
+ """
188
+ >>> pen = SVGPathPen(None)
189
+ >>> pen.closePath()
190
+ >>> pen._commands
191
+ ['Z']
192
+ """
193
+ self._commands.append("Z")
194
+ self._lastCommand = "Z"
195
+ self._lastX = self._lastY = None
196
+
197
+ def _endPath(self):
198
+ """
199
+ >>> pen = SVGPathPen(None)
200
+ >>> pen.endPath()
201
+ >>> pen._commands
202
+ []
203
+ """
204
+ self._lastCommand = None
205
+ self._lastX = self._lastY = None
206
+
207
+ def getCommands(self):
208
+ return "".join(self._commands)
209
+
210
+
211
+ def main(args=None):
212
+ """Generate per-character SVG from font and text"""
213
+
214
+ if args is None:
215
+ import sys
216
+
217
+ args = sys.argv[1:]
218
+
219
+ from fontTools.ttLib import TTFont
220
+ import argparse
221
+
222
+ parser = argparse.ArgumentParser(
223
+ "fonttools pens.svgPathPen", description="Generate SVG from text"
224
+ )
225
+ parser.add_argument("font", metavar="font.ttf", help="Font file.")
226
+ parser.add_argument("text", metavar="text", nargs="?", help="Text string.")
227
+ parser.add_argument(
228
+ "-y",
229
+ metavar="<number>",
230
+ help="Face index into a collection to open. Zero based.",
231
+ )
232
+ parser.add_argument(
233
+ "--glyphs",
234
+ metavar="whitespace-separated list of glyph names",
235
+ type=str,
236
+ help="Glyphs to show. Exclusive with text option",
237
+ )
238
+ parser.add_argument(
239
+ "--variations",
240
+ metavar="AXIS=LOC",
241
+ default="",
242
+ help="List of space separated locations. A location consist in "
243
+ "the name of a variation axis, followed by '=' and a number. E.g.: "
244
+ "wght=700 wdth=80. The default is the location of the base master.",
245
+ )
246
+
247
+ options = parser.parse_args(args)
248
+
249
+ fontNumber = int(options.y) if options.y is not None else 0
250
+
251
+ font = TTFont(options.font, fontNumber=fontNumber)
252
+ text = options.text
253
+ glyphs = options.glyphs
254
+
255
+ location = {}
256
+ for tag_v in options.variations.split():
257
+ fields = tag_v.split("=")
258
+ tag = fields[0].strip()
259
+ v = float(fields[1])
260
+ location[tag] = v
261
+
262
+ hhea = font["hhea"]
263
+ ascent, descent = hhea.ascent, hhea.descent
264
+
265
+ glyphset = font.getGlyphSet(location=location)
266
+ cmap = font["cmap"].getBestCmap()
267
+
268
+ if glyphs is not None and text is not None:
269
+ raise ValueError("Options --glyphs and --text are exclusive")
270
+
271
+ if glyphs is None:
272
+ glyphs = " ".join(cmap[ord(u)] for u in text)
273
+
274
+ glyphs = glyphs.split()
275
+
276
+ s = ""
277
+ width = 0
278
+ for g in glyphs:
279
+ glyph = glyphset[g]
280
+
281
+ pen = SVGPathPen(glyphset)
282
+ glyph.draw(pen)
283
+ commands = pen.getCommands()
284
+
285
+ s += '<g transform="translate(%d %d) scale(1 -1)"><path d="%s"/></g>\n' % (
286
+ width,
287
+ ascent,
288
+ commands,
289
+ )
290
+
291
+ width += glyph.width
292
+
293
+ print('<?xml version="1.0" encoding="UTF-8"?>')
294
+ print(
295
+ '<svg width="%d" height="%d" xmlns="http://www.w3.org/2000/svg">'
296
+ % (width, ascent - descent)
297
+ )
298
+ print(s, end="")
299
+ print("</svg>")
300
+
301
+
302
+ if __name__ == "__main__":
303
+ import sys
304
+
305
+ if len(sys.argv) == 1:
306
+ import doctest
307
+
308
+ sys.exit(doctest.testmod().failed)
309
+
310
+ sys.exit(main())
@@ -0,0 +1,88 @@
1
+ # Copyright (c) 2009 Type Supply LLC
2
+ # Author: Tal Leming
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import Any, Dict, List, Tuple
7
+
8
+ from fontTools.cffLib.specializer import commandsToProgram, specializeCommands
9
+ from fontTools.misc.psCharStrings import T2CharString
10
+ from fontTools.misc.roundTools import otRound, roundFunc
11
+ from fontTools.pens.basePen import BasePen
12
+
13
+
14
+ class T2CharStringPen(BasePen):
15
+ """Pen to draw Type 2 CharStrings.
16
+
17
+ The 'roundTolerance' argument controls the rounding of point coordinates.
18
+ It is defined as the maximum absolute difference between the original
19
+ float and the rounded integer value.
20
+ The default tolerance of 0.5 means that all floats are rounded to integer;
21
+ a value of 0 disables rounding; values in between will only round floats
22
+ which are close to their integral part within the tolerated range.
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ width: float | None,
28
+ glyphSet: Dict[str, Any] | None,
29
+ roundTolerance: float = 0.5,
30
+ CFF2: bool = False,
31
+ ) -> None:
32
+ super(T2CharStringPen, self).__init__(glyphSet)
33
+ self.round = roundFunc(roundTolerance)
34
+ self._CFF2 = CFF2
35
+ self._width = width
36
+ self._commands: List[Tuple[str | bytes, List[float]]] = []
37
+ self._p0 = (0, 0)
38
+
39
+ def _p(self, pt: Tuple[float, float]) -> List[float]:
40
+ p0 = self._p0
41
+ pt = self._p0 = (self.round(pt[0]), self.round(pt[1]))
42
+ return [pt[0] - p0[0], pt[1] - p0[1]]
43
+
44
+ def _moveTo(self, pt: Tuple[float, float]) -> None:
45
+ self._commands.append(("rmoveto", self._p(pt)))
46
+
47
+ def _lineTo(self, pt: Tuple[float, float]) -> None:
48
+ self._commands.append(("rlineto", self._p(pt)))
49
+
50
+ def _curveToOne(
51
+ self,
52
+ pt1: Tuple[float, float],
53
+ pt2: Tuple[float, float],
54
+ pt3: Tuple[float, float],
55
+ ) -> None:
56
+ _p = self._p
57
+ self._commands.append(("rrcurveto", _p(pt1) + _p(pt2) + _p(pt3)))
58
+
59
+ def _closePath(self) -> None:
60
+ pass
61
+
62
+ def _endPath(self) -> None:
63
+ pass
64
+
65
+ def getCharString(
66
+ self,
67
+ private: Dict | None = None,
68
+ globalSubrs: List | None = None,
69
+ optimize: bool = True,
70
+ ) -> T2CharString:
71
+ commands = self._commands
72
+ if optimize:
73
+ maxstack = 48 if not self._CFF2 else 513
74
+ commands = specializeCommands(
75
+ commands, generalizeFirst=False, maxstack=maxstack
76
+ )
77
+ program = commandsToProgram(commands)
78
+ if self._width is not None:
79
+ assert (
80
+ not self._CFF2
81
+ ), "CFF2 does not allow encoding glyph width in CharString."
82
+ program.insert(0, otRound(self._width))
83
+ if not self._CFF2:
84
+ program.append("endchar")
85
+ charString = T2CharString(
86
+ program=program, private=private, globalSubrs=globalSubrs
87
+ )
88
+ return charString
@@ -0,0 +1,55 @@
1
+ """Pen multiplexing drawing to one or more pens."""
2
+
3
+ from fontTools.pens.basePen import AbstractPen
4
+
5
+
6
+ __all__ = ["TeePen"]
7
+
8
+
9
+ class TeePen(AbstractPen):
10
+ """Pen multiplexing drawing to one or more pens.
11
+
12
+ Use either as TeePen(pen1, pen2, ...) or TeePen(iterableOfPens)."""
13
+
14
+ def __init__(self, *pens):
15
+ if len(pens) == 1:
16
+ pens = pens[0]
17
+ self.pens = pens
18
+
19
+ def moveTo(self, p0):
20
+ for pen in self.pens:
21
+ pen.moveTo(p0)
22
+
23
+ def lineTo(self, p1):
24
+ for pen in self.pens:
25
+ pen.lineTo(p1)
26
+
27
+ def qCurveTo(self, *points):
28
+ for pen in self.pens:
29
+ pen.qCurveTo(*points)
30
+
31
+ def curveTo(self, *points):
32
+ for pen in self.pens:
33
+ pen.curveTo(*points)
34
+
35
+ def closePath(self):
36
+ for pen in self.pens:
37
+ pen.closePath()
38
+
39
+ def endPath(self):
40
+ for pen in self.pens:
41
+ pen.endPath()
42
+
43
+ def addComponent(self, glyphName, transformation):
44
+ for pen in self.pens:
45
+ pen.addComponent(glyphName, transformation)
46
+
47
+
48
+ if __name__ == "__main__":
49
+ from fontTools.pens.basePen import _TestPen
50
+
51
+ pen = TeePen(_TestPen(), _TestPen())
52
+ pen.moveTo((0, 0))
53
+ pen.lineTo((0, 100))
54
+ pen.curveTo((50, 75), (60, 50), (50, 25))
55
+ pen.closePath()
@@ -0,0 +1,115 @@
1
+ from fontTools.pens.filterPen import FilterPen, FilterPointPen
2
+
3
+
4
+ __all__ = ["TransformPen", "TransformPointPen"]
5
+
6
+
7
+ class TransformPen(FilterPen):
8
+ """Pen that transforms all coordinates using a Affine transformation,
9
+ and passes them to another pen.
10
+ """
11
+
12
+ def __init__(self, outPen, transformation):
13
+ """The 'outPen' argument is another pen object. It will receive the
14
+ transformed coordinates. The 'transformation' argument can either
15
+ be a six-tuple, or a fontTools.misc.transform.Transform object.
16
+ """
17
+ super(TransformPen, self).__init__(outPen)
18
+ if not hasattr(transformation, "transformPoint"):
19
+ from fontTools.misc.transform import Transform
20
+
21
+ transformation = Transform(*transformation)
22
+ self._transformation = transformation
23
+ self._transformPoint = transformation.transformPoint
24
+ self._stack = []
25
+
26
+ def moveTo(self, pt):
27
+ self._outPen.moveTo(self._transformPoint(pt))
28
+
29
+ def lineTo(self, pt):
30
+ self._outPen.lineTo(self._transformPoint(pt))
31
+
32
+ def curveTo(self, *points):
33
+ self._outPen.curveTo(*self._transformPoints(points))
34
+
35
+ def qCurveTo(self, *points):
36
+ if points[-1] is None:
37
+ points = self._transformPoints(points[:-1]) + [None]
38
+ else:
39
+ points = self._transformPoints(points)
40
+ self._outPen.qCurveTo(*points)
41
+
42
+ def _transformPoints(self, points):
43
+ transformPoint = self._transformPoint
44
+ return [transformPoint(pt) for pt in points]
45
+
46
+ def closePath(self):
47
+ self._outPen.closePath()
48
+
49
+ def endPath(self):
50
+ self._outPen.endPath()
51
+
52
+ def addComponent(self, glyphName, transformation):
53
+ transformation = self._transformation.transform(transformation)
54
+ self._outPen.addComponent(glyphName, transformation)
55
+
56
+
57
+ class TransformPointPen(FilterPointPen):
58
+ """PointPen that transforms all coordinates using a Affine transformation,
59
+ and passes them to another PointPen.
60
+
61
+ For example::
62
+
63
+ >>> from fontTools.pens.recordingPen import RecordingPointPen
64
+ >>> rec = RecordingPointPen()
65
+ >>> pen = TransformPointPen(rec, (2, 0, 0, 2, -10, 5))
66
+ >>> v = iter(rec.value)
67
+ >>> pen.beginPath(identifier="contour-0")
68
+ >>> next(v)
69
+ ('beginPath', (), {'identifier': 'contour-0'})
70
+
71
+ >>> pen.addPoint((100, 100), "line")
72
+ >>> next(v)
73
+ ('addPoint', ((190, 205), 'line', False, None), {})
74
+
75
+ >>> pen.endPath()
76
+ >>> next(v)
77
+ ('endPath', (), {})
78
+
79
+ >>> pen.addComponent("a", (1, 0, 0, 1, -10, 5), identifier="component-0")
80
+ >>> next(v)
81
+ ('addComponent', ('a', <Transform [2 0 0 2 -30 15]>), {'identifier': 'component-0'})
82
+ """
83
+
84
+ def __init__(self, outPointPen, transformation):
85
+ """The 'outPointPen' argument is another point pen object.
86
+ It will receive the transformed coordinates.
87
+ The 'transformation' argument can either be a six-tuple, or a
88
+ fontTools.misc.transform.Transform object.
89
+ """
90
+ super().__init__(outPointPen)
91
+ if not hasattr(transformation, "transformPoint"):
92
+ from fontTools.misc.transform import Transform
93
+
94
+ transformation = Transform(*transformation)
95
+ self._transformation = transformation
96
+ self._transformPoint = transformation.transformPoint
97
+
98
+ def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
99
+ self._outPen.addPoint(
100
+ self._transformPoint(pt), segmentType, smooth, name, **kwargs
101
+ )
102
+
103
+ def addComponent(self, baseGlyphName, transformation, **kwargs):
104
+ transformation = self._transformation.transform(transformation)
105
+ self._outPen.addComponent(baseGlyphName, transformation, **kwargs)
106
+
107
+
108
+ if __name__ == "__main__":
109
+ from fontTools.pens.basePen import _TestPen
110
+
111
+ pen = TransformPen(_TestPen(None), (2, 0, 0.5, 2, -10, 0))
112
+ pen.moveTo((0, 0))
113
+ pen.lineTo((0, 100))
114
+ pen.curveTo((50, 75), (60, 50), (50, 25), (0, 0))
115
+ pen.closePath()