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,462 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """Pen to rasterize paths with FreeType."""
4
+
5
+ __all__ = ["FreeTypePen"]
6
+
7
+ import os
8
+ import ctypes
9
+ import platform
10
+ import subprocess
11
+ import collections
12
+ import math
13
+
14
+ import freetype
15
+ from freetype.raw import FT_Outline_Get_Bitmap, FT_Outline_Get_BBox, FT_Outline_Get_CBox
16
+ from freetype.ft_types import FT_Pos
17
+ from freetype.ft_structs import FT_Vector, FT_BBox, FT_Bitmap, FT_Outline
18
+ from freetype.ft_enums import (
19
+ FT_OUTLINE_NONE,
20
+ FT_OUTLINE_EVEN_ODD_FILL,
21
+ FT_PIXEL_MODE_GRAY,
22
+ FT_CURVE_TAG_ON,
23
+ FT_CURVE_TAG_CONIC,
24
+ FT_CURVE_TAG_CUBIC,
25
+ )
26
+ from freetype.ft_errors import FT_Exception
27
+
28
+ from fontTools.pens.basePen import BasePen, PenError
29
+ from fontTools.misc.roundTools import otRound
30
+ from fontTools.misc.transform import Transform
31
+
32
+ Contour = collections.namedtuple("Contour", ("points", "tags"))
33
+
34
+
35
+ class FreeTypePen(BasePen):
36
+ """Pen to rasterize paths with FreeType. Requires `freetype-py` module.
37
+
38
+ Constructs ``FT_Outline`` from the paths, and renders it within a bitmap
39
+ buffer.
40
+
41
+ For ``array()`` and ``show()``, `numpy` and `matplotlib` must be installed.
42
+ For ``image()``, `Pillow` is required. Each module is lazily loaded when the
43
+ corresponding method is called.
44
+
45
+ Args:
46
+ glyphSet: a dictionary of drawable glyph objects keyed by name
47
+ used to resolve component references in composite glyphs.
48
+
49
+ Examples:
50
+ If `numpy` and `matplotlib` is available, the following code will
51
+ show the glyph image of `fi` in a new window::
52
+
53
+ from fontTools.ttLib import TTFont
54
+ from fontTools.pens.freetypePen import FreeTypePen
55
+ from fontTools.misc.transform import Offset
56
+ pen = FreeTypePen(None)
57
+ font = TTFont('SourceSansPro-Regular.otf')
58
+ glyph = font.getGlyphSet()['fi']
59
+ glyph.draw(pen)
60
+ width, ascender, descender = glyph.width, font['OS/2'].usWinAscent, -font['OS/2'].usWinDescent
61
+ height = ascender - descender
62
+ pen.show(width=width, height=height, transform=Offset(0, -descender))
63
+
64
+ Combining with `uharfbuzz`, you can typeset a chunk of glyphs in a pen::
65
+
66
+ import uharfbuzz as hb
67
+ from fontTools.pens.freetypePen import FreeTypePen
68
+ from fontTools.pens.transformPen import TransformPen
69
+ from fontTools.misc.transform import Offset
70
+
71
+ en1, en2, ar, ja = 'Typesetting', 'Jeff', 'صف الحروف', 'たいぷせっと'
72
+ for text, font_path, direction, typo_ascender, typo_descender, vhea_ascender, vhea_descender, contain, features in (
73
+ (en1, 'NotoSans-Regular.ttf', 'ltr', 2189, -600, None, None, False, {"kern": True, "liga": True}),
74
+ (en2, 'NotoSans-Regular.ttf', 'ltr', 2189, -600, None, None, True, {"kern": True, "liga": True}),
75
+ (ar, 'NotoSansArabic-Regular.ttf', 'rtl', 1374, -738, None, None, False, {"kern": True, "liga": True}),
76
+ (ja, 'NotoSansJP-Regular.otf', 'ltr', 880, -120, 500, -500, False, {"palt": True, "kern": True}),
77
+ (ja, 'NotoSansJP-Regular.otf', 'ttb', 880, -120, 500, -500, False, {"vert": True, "vpal": True, "vkrn": True})
78
+ ):
79
+ blob = hb.Blob.from_file_path(font_path)
80
+ face = hb.Face(blob)
81
+ font = hb.Font(face)
82
+ buf = hb.Buffer()
83
+ buf.direction = direction
84
+ buf.add_str(text)
85
+ buf.guess_segment_properties()
86
+ hb.shape(font, buf, features)
87
+
88
+ x, y = 0, 0
89
+ pen = FreeTypePen(None)
90
+ for info, pos in zip(buf.glyph_infos, buf.glyph_positions):
91
+ gid = info.codepoint
92
+ transformed = TransformPen(pen, Offset(x + pos.x_offset, y + pos.y_offset))
93
+ font.draw_glyph_with_pen(gid, transformed)
94
+ x += pos.x_advance
95
+ y += pos.y_advance
96
+
97
+ offset, width, height = None, None, None
98
+ if direction in ('ltr', 'rtl'):
99
+ offset = (0, -typo_descender)
100
+ width = x
101
+ height = typo_ascender - typo_descender
102
+ else:
103
+ offset = (-vhea_descender, -y)
104
+ width = vhea_ascender - vhea_descender
105
+ height = -y
106
+ pen.show(width=width, height=height, transform=Offset(*offset), contain=contain)
107
+
108
+ For Jupyter Notebook, the rendered image will be displayed in a cell if
109
+ you replace ``show()`` with ``image()`` in the examples.
110
+ """
111
+
112
+ def __init__(self, glyphSet):
113
+ BasePen.__init__(self, glyphSet)
114
+ self.contours = []
115
+
116
+ def outline(self, transform=None, evenOdd=False):
117
+ """Converts the current contours to ``FT_Outline``.
118
+
119
+ Args:
120
+ transform: An optional 6-tuple containing an affine transformation,
121
+ or a ``Transform`` object from the ``fontTools.misc.transform``
122
+ module.
123
+ evenOdd: Pass ``True`` for even-odd fill instead of non-zero.
124
+ """
125
+ transform = transform or Transform()
126
+ if not hasattr(transform, "transformPoint"):
127
+ transform = Transform(*transform)
128
+ n_contours = len(self.contours)
129
+ n_points = sum((len(contour.points) for contour in self.contours))
130
+ points = []
131
+ for contour in self.contours:
132
+ for point in contour.points:
133
+ point = transform.transformPoint(point)
134
+ points.append(
135
+ FT_Vector(
136
+ FT_Pos(otRound(point[0] * 64)), FT_Pos(otRound(point[1] * 64))
137
+ )
138
+ )
139
+ tags = []
140
+ for contour in self.contours:
141
+ for tag in contour.tags:
142
+ tags.append(tag)
143
+ contours = []
144
+ contours_sum = 0
145
+ for contour in self.contours:
146
+ contours_sum += len(contour.points)
147
+ contours.append(contours_sum - 1)
148
+ flags = FT_OUTLINE_EVEN_ODD_FILL if evenOdd else FT_OUTLINE_NONE
149
+ return FT_Outline(
150
+ (ctypes.c_short)(n_contours),
151
+ (ctypes.c_short)(n_points),
152
+ (FT_Vector * n_points)(*points),
153
+ (ctypes.c_ubyte * n_points)(*tags),
154
+ (ctypes.c_short * n_contours)(*contours),
155
+ (ctypes.c_int)(flags),
156
+ )
157
+
158
+ def buffer(
159
+ self, width=None, height=None, transform=None, contain=False, evenOdd=False
160
+ ):
161
+ """Renders the current contours within a bitmap buffer.
162
+
163
+ Args:
164
+ width: Image width of the bitmap in pixels. If omitted, it
165
+ automatically fits to the bounding box of the contours.
166
+ height: Image height of the bitmap in pixels. If omitted, it
167
+ automatically fits to the bounding box of the contours.
168
+ transform: An optional 6-tuple containing an affine transformation,
169
+ or a ``Transform`` object from the ``fontTools.misc.transform``
170
+ module. The bitmap size is not affected by this matrix.
171
+ contain: If ``True``, the image size will be automatically expanded
172
+ so that it fits to the bounding box of the paths. Useful for
173
+ rendering glyphs with negative sidebearings without clipping.
174
+ evenOdd: Pass ``True`` for even-odd fill instead of non-zero.
175
+
176
+ Returns:
177
+ A tuple of ``(buffer, size)``, where ``buffer`` is a ``bytes``
178
+ object of the resulted bitmap and ``size`` is a 2-tuple of its
179
+ dimension.
180
+
181
+ Notes:
182
+ The image size should always be given explicitly if you need to get
183
+ a proper glyph image. When ``width`` and ``height`` are omitted, it
184
+ forcifully fits to the bounding box and the side bearings get
185
+ cropped. If you pass ``0`` to both ``width`` and ``height`` and set
186
+ ``contain`` to ``True``, it expands to the bounding box while
187
+ maintaining the origin of the contours, meaning that LSB will be
188
+ maintained but RSB won’t. The difference between the two becomes
189
+ more obvious when rotate or skew transformation is applied.
190
+
191
+ Example:
192
+ .. code-block:: pycon
193
+
194
+ >>>
195
+ >> pen = FreeTypePen(None)
196
+ >> glyph.draw(pen)
197
+ >> buf, size = pen.buffer(width=500, height=1000)
198
+ >> type(buf), len(buf), size
199
+ (<class 'bytes'>, 500000, (500, 1000))
200
+ """
201
+ transform = transform or Transform()
202
+ if not hasattr(transform, "transformPoint"):
203
+ transform = Transform(*transform)
204
+ contain_x, contain_y = contain or width is None, contain or height is None
205
+ if contain_x or contain_y:
206
+ dx, dy = transform.dx, transform.dy
207
+ bbox = self.bbox
208
+ p1, p2, p3, p4 = (
209
+ transform.transformPoint((bbox[0], bbox[1])),
210
+ transform.transformPoint((bbox[2], bbox[1])),
211
+ transform.transformPoint((bbox[0], bbox[3])),
212
+ transform.transformPoint((bbox[2], bbox[3])),
213
+ )
214
+ px, py = (p1[0], p2[0], p3[0], p4[0]), (p1[1], p2[1], p3[1], p4[1])
215
+ if contain_x:
216
+ if width is None:
217
+ dx = dx - min(*px)
218
+ width = max(*px) - min(*px)
219
+ else:
220
+ dx = dx - min(min(*px), 0.0)
221
+ width = max(width, max(*px) - min(min(*px), 0.0))
222
+ if contain_y:
223
+ if height is None:
224
+ dy = dy - min(*py)
225
+ height = max(*py) - min(*py)
226
+ else:
227
+ dy = dy - min(min(*py), 0.0)
228
+ height = max(height, max(*py) - min(min(*py), 0.0))
229
+ transform = Transform(*transform[:4], dx, dy)
230
+ width, height = math.ceil(width), math.ceil(height)
231
+ buf = ctypes.create_string_buffer(width * height)
232
+ bitmap = FT_Bitmap(
233
+ (ctypes.c_int)(height),
234
+ (ctypes.c_int)(width),
235
+ (ctypes.c_int)(width),
236
+ (ctypes.POINTER(ctypes.c_ubyte))(buf),
237
+ (ctypes.c_short)(256),
238
+ (ctypes.c_ubyte)(FT_PIXEL_MODE_GRAY),
239
+ (ctypes.c_char)(0),
240
+ (ctypes.c_void_p)(None),
241
+ )
242
+ outline = self.outline(transform=transform, evenOdd=evenOdd)
243
+ err = FT_Outline_Get_Bitmap(
244
+ freetype.get_handle(), ctypes.byref(outline), ctypes.byref(bitmap)
245
+ )
246
+ if err != 0:
247
+ raise FT_Exception(err)
248
+ return buf.raw, (width, height)
249
+
250
+ def array(
251
+ self, width=None, height=None, transform=None, contain=False, evenOdd=False
252
+ ):
253
+ """Returns the rendered contours as a numpy array. Requires `numpy`.
254
+
255
+ Args:
256
+ width: Image width of the bitmap in pixels. If omitted, it
257
+ automatically fits to the bounding box of the contours.
258
+ height: Image height of the bitmap in pixels. If omitted, it
259
+ automatically fits to the bounding box of the contours.
260
+ transform: An optional 6-tuple containing an affine transformation,
261
+ or a ``Transform`` object from the ``fontTools.misc.transform``
262
+ module. The bitmap size is not affected by this matrix.
263
+ contain: If ``True``, the image size will be automatically expanded
264
+ so that it fits to the bounding box of the paths. Useful for
265
+ rendering glyphs with negative sidebearings without clipping.
266
+ evenOdd: Pass ``True`` for even-odd fill instead of non-zero.
267
+
268
+ Returns:
269
+ A ``numpy.ndarray`` object with a shape of ``(height, width)``.
270
+ Each element takes a value in the range of ``[0.0, 1.0]``.
271
+
272
+ Notes:
273
+ The image size should always be given explicitly if you need to get
274
+ a proper glyph image. When ``width`` and ``height`` are omitted, it
275
+ forcifully fits to the bounding box and the side bearings get
276
+ cropped. If you pass ``0`` to both ``width`` and ``height`` and set
277
+ ``contain`` to ``True``, it expands to the bounding box while
278
+ maintaining the origin of the contours, meaning that LSB will be
279
+ maintained but RSB won’t. The difference between the two becomes
280
+ more obvious when rotate or skew transformation is applied.
281
+
282
+ Example:
283
+ .. code-block:: pycon
284
+
285
+ >>>
286
+ >> pen = FreeTypePen(None)
287
+ >> glyph.draw(pen)
288
+ >> arr = pen.array(width=500, height=1000)
289
+ >> type(a), a.shape
290
+ (<class 'numpy.ndarray'>, (1000, 500))
291
+ """
292
+
293
+ import numpy as np
294
+
295
+ buf, size = self.buffer(
296
+ width=width,
297
+ height=height,
298
+ transform=transform,
299
+ contain=contain,
300
+ evenOdd=evenOdd,
301
+ )
302
+ return np.frombuffer(buf, "B").reshape((size[1], size[0])) / 255.0
303
+
304
+ def show(
305
+ self, width=None, height=None, transform=None, contain=False, evenOdd=False
306
+ ):
307
+ """Plots the rendered contours with `pyplot`. Requires `numpy` and
308
+ `matplotlib`.
309
+
310
+ Args:
311
+ width: Image width of the bitmap in pixels. If omitted, it
312
+ automatically fits to the bounding box of the contours.
313
+ height: Image height of the bitmap in pixels. If omitted, it
314
+ automatically fits to the bounding box of the contours.
315
+ transform: An optional 6-tuple containing an affine transformation,
316
+ or a ``Transform`` object from the ``fontTools.misc.transform``
317
+ module. The bitmap size is not affected by this matrix.
318
+ contain: If ``True``, the image size will be automatically expanded
319
+ so that it fits to the bounding box of the paths. Useful for
320
+ rendering glyphs with negative sidebearings without clipping.
321
+ evenOdd: Pass ``True`` for even-odd fill instead of non-zero.
322
+
323
+ Notes:
324
+ The image size should always be given explicitly if you need to get
325
+ a proper glyph image. When ``width`` and ``height`` are omitted, it
326
+ forcifully fits to the bounding box and the side bearings get
327
+ cropped. If you pass ``0`` to both ``width`` and ``height`` and set
328
+ ``contain`` to ``True``, it expands to the bounding box while
329
+ maintaining the origin of the contours, meaning that LSB will be
330
+ maintained but RSB won’t. The difference between the two becomes
331
+ more obvious when rotate or skew transformation is applied.
332
+
333
+ Example:
334
+ .. code-block:: pycon
335
+
336
+ >>>
337
+ >> pen = FreeTypePen(None)
338
+ >> glyph.draw(pen)
339
+ >> pen.show(width=500, height=1000)
340
+ """
341
+ from matplotlib import pyplot as plt
342
+
343
+ a = self.array(
344
+ width=width,
345
+ height=height,
346
+ transform=transform,
347
+ contain=contain,
348
+ evenOdd=evenOdd,
349
+ )
350
+ plt.imshow(a, cmap="gray_r", vmin=0, vmax=1)
351
+ plt.show()
352
+
353
+ def image(
354
+ self, width=None, height=None, transform=None, contain=False, evenOdd=False
355
+ ):
356
+ """Returns the rendered contours as a PIL image. Requires `Pillow`.
357
+ Can be used to display a glyph image in Jupyter Notebook.
358
+
359
+ Args:
360
+ width: Image width of the bitmap in pixels. If omitted, it
361
+ automatically fits to the bounding box of the contours.
362
+ height: Image height of the bitmap in pixels. If omitted, it
363
+ automatically fits to the bounding box of the contours.
364
+ transform: An optional 6-tuple containing an affine transformation,
365
+ or a ``Transform`` object from the ``fontTools.misc.transform``
366
+ module. The bitmap size is not affected by this matrix.
367
+ contain: If ``True``, the image size will be automatically expanded
368
+ so that it fits to the bounding box of the paths. Useful for
369
+ rendering glyphs with negative sidebearings without clipping.
370
+ evenOdd: Pass ``True`` for even-odd fill instead of non-zero.
371
+
372
+ Returns:
373
+ A ``PIL.image`` object. The image is filled in black with alpha
374
+ channel obtained from the rendered bitmap.
375
+
376
+ Notes:
377
+ The image size should always be given explicitly if you need to get
378
+ a proper glyph image. When ``width`` and ``height`` are omitted, it
379
+ forcifully fits to the bounding box and the side bearings get
380
+ cropped. If you pass ``0`` to both ``width`` and ``height`` and set
381
+ ``contain`` to ``True``, it expands to the bounding box while
382
+ maintaining the origin of the contours, meaning that LSB will be
383
+ maintained but RSB won’t. The difference between the two becomes
384
+ more obvious when rotate or skew transformation is applied.
385
+
386
+ Example:
387
+ .. code-block:: pycon
388
+
389
+ >>>
390
+ >> pen = FreeTypePen(None)
391
+ >> glyph.draw(pen)
392
+ >> img = pen.image(width=500, height=1000)
393
+ >> type(img), img.size
394
+ (<class 'PIL.Image.Image'>, (500, 1000))
395
+ """
396
+ from PIL import Image
397
+
398
+ buf, size = self.buffer(
399
+ width=width,
400
+ height=height,
401
+ transform=transform,
402
+ contain=contain,
403
+ evenOdd=evenOdd,
404
+ )
405
+ img = Image.new("L", size, 0)
406
+ img.putalpha(Image.frombuffer("L", size, buf))
407
+ return img
408
+
409
+ @property
410
+ def bbox(self):
411
+ """Computes the exact bounding box of an outline.
412
+
413
+ Returns:
414
+ A tuple of ``(xMin, yMin, xMax, yMax)``.
415
+ """
416
+ bbox = FT_BBox()
417
+ outline = self.outline()
418
+ FT_Outline_Get_BBox(ctypes.byref(outline), ctypes.byref(bbox))
419
+ return (bbox.xMin / 64.0, bbox.yMin / 64.0, bbox.xMax / 64.0, bbox.yMax / 64.0)
420
+
421
+ @property
422
+ def cbox(self):
423
+ """Returns an outline's ‘control box’.
424
+
425
+ Returns:
426
+ A tuple of ``(xMin, yMin, xMax, yMax)``.
427
+ """
428
+ cbox = FT_BBox()
429
+ outline = self.outline()
430
+ FT_Outline_Get_CBox(ctypes.byref(outline), ctypes.byref(cbox))
431
+ return (cbox.xMin / 64.0, cbox.yMin / 64.0, cbox.xMax / 64.0, cbox.yMax / 64.0)
432
+
433
+ def _moveTo(self, pt):
434
+ contour = Contour([], [])
435
+ self.contours.append(contour)
436
+ contour.points.append(pt)
437
+ contour.tags.append(FT_CURVE_TAG_ON)
438
+
439
+ def _lineTo(self, pt):
440
+ if not (self.contours and len(self.contours[-1].points) > 0):
441
+ raise PenError("Contour missing required initial moveTo")
442
+ contour = self.contours[-1]
443
+ contour.points.append(pt)
444
+ contour.tags.append(FT_CURVE_TAG_ON)
445
+
446
+ def _curveToOne(self, p1, p2, p3):
447
+ if not (self.contours and len(self.contours[-1].points) > 0):
448
+ raise PenError("Contour missing required initial moveTo")
449
+ t1, t2, t3 = FT_CURVE_TAG_CUBIC, FT_CURVE_TAG_CUBIC, FT_CURVE_TAG_ON
450
+ contour = self.contours[-1]
451
+ for p, t in ((p1, t1), (p2, t2), (p3, t3)):
452
+ contour.points.append(p)
453
+ contour.tags.append(t)
454
+
455
+ def _qCurveToOne(self, p1, p2):
456
+ if not (self.contours and len(self.contours[-1].points) > 0):
457
+ raise PenError("Contour missing required initial moveTo")
458
+ t1, t2 = FT_CURVE_TAG_CONIC, FT_CURVE_TAG_ON
459
+ contour = self.contours[-1]
460
+ for p, t in ((p1, t1), (p2, t2)):
461
+ contour.points.append(p)
462
+ contour.tags.append(t)
@@ -0,0 +1,89 @@
1
+ # Modified from https://github.com/adobe-type-tools/psautohint/blob/08b346865710ed3c172f1eb581d6ef243b203f99/python/psautohint/ufoFont.py#L800-L838
2
+ import hashlib
3
+
4
+ from fontTools.pens.basePen import MissingComponentError
5
+ from fontTools.pens.pointPen import AbstractPointPen
6
+
7
+
8
+ class HashPointPen(AbstractPointPen):
9
+ """
10
+ This pen can be used to check if a glyph's contents (outlines plus
11
+ components) have changed.
12
+
13
+ Components are added as the original outline plus each composite's
14
+ transformation.
15
+
16
+ Example: You have some TrueType hinting code for a glyph which you want to
17
+ compile. The hinting code specifies a hash value computed with HashPointPen
18
+ that was valid for the glyph's outlines at the time the hinting code was
19
+ written. Now you can calculate the hash for the glyph's current outlines to
20
+ check if the outlines have changed, which would probably make the hinting
21
+ code invalid.
22
+
23
+ > glyph = ufo[name]
24
+ > hash_pen = HashPointPen(glyph.width, ufo)
25
+ > glyph.drawPoints(hash_pen)
26
+ > ttdata = glyph.lib.get("public.truetype.instructions", None)
27
+ > stored_hash = ttdata.get("id", None) # The hash is stored in the "id" key
28
+ > if stored_hash is None or stored_hash != hash_pen.hash:
29
+ > logger.error(f"Glyph hash mismatch, glyph '{name}' will have no instructions in font.")
30
+ > else:
31
+ > # The hash values are identical, the outline has not changed.
32
+ > # Compile the hinting code ...
33
+ > pass
34
+
35
+ If you want to compare a glyph from a source format which supports floating point
36
+ coordinates and transformations against a glyph from a format which has restrictions
37
+ on the precision of floats, e.g. UFO vs. TTF, you must use an appropriate rounding
38
+ function to make the values comparable. For TTF fonts with composites, this
39
+ construct can be used to make the transform values conform to F2Dot14:
40
+
41
+ > ttf_hash_pen = HashPointPen(ttf_glyph_width, ttFont.getGlyphSet())
42
+ > ttf_round_pen = RoundingPointPen(ttf_hash_pen, transformRoundFunc=partial(floatToFixedToFloat, precisionBits=14))
43
+ > ufo_hash_pen = HashPointPen(ufo_glyph.width, ufo)
44
+ > ttf_glyph.drawPoints(ttf_round_pen, ttFont["glyf"])
45
+ > ufo_round_pen = RoundingPointPen(ufo_hash_pen, transformRoundFunc=partial(floatToFixedToFloat, precisionBits=14))
46
+ > ufo_glyph.drawPoints(ufo_round_pen)
47
+ > assert ttf_hash_pen.hash == ufo_hash_pen.hash
48
+ """
49
+
50
+ def __init__(self, glyphWidth=0, glyphSet=None):
51
+ self.glyphset = glyphSet
52
+ self.data = ["w%s" % round(glyphWidth, 9)]
53
+
54
+ @property
55
+ def hash(self):
56
+ data = "".join(self.data)
57
+ if len(data) >= 128:
58
+ data = hashlib.sha512(data.encode("ascii")).hexdigest()
59
+ return data
60
+
61
+ def beginPath(self, identifier=None, **kwargs):
62
+ pass
63
+
64
+ def endPath(self):
65
+ self.data.append("|")
66
+
67
+ def addPoint(
68
+ self,
69
+ pt,
70
+ segmentType=None,
71
+ smooth=False,
72
+ name=None,
73
+ identifier=None,
74
+ **kwargs,
75
+ ):
76
+ if segmentType is None:
77
+ pt_type = "o" # offcurve
78
+ else:
79
+ pt_type = segmentType[0]
80
+ self.data.append(f"{pt_type}{pt[0]:g}{pt[1]:+g}")
81
+
82
+ def addComponent(self, baseGlyphName, transformation, identifier=None, **kwargs):
83
+ tr = "".join([f"{t:+}" for t in transformation])
84
+ self.data.append("[")
85
+ try:
86
+ self.glyphset[baseGlyphName].drawPoints(self)
87
+ except KeyError:
88
+ raise MissingComponentError(baseGlyphName)
89
+ self.data.append(f"({tr})]")