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,648 @@
1
+ """fontTools.t1Lib.py -- Tools for PostScript Type 1 fonts.
2
+
3
+ Functions for reading and writing raw Type 1 data:
4
+
5
+ read(path)
6
+ reads any Type 1 font file, returns the raw data and a type indicator:
7
+ 'LWFN', 'PFB' or 'OTHER', depending on the format of the file pointed
8
+ to by 'path'.
9
+ Raises an error when the file does not contain valid Type 1 data.
10
+
11
+ write(path, data, kind='OTHER', dohex=False)
12
+ writes raw Type 1 data to the file pointed to by 'path'.
13
+ 'kind' can be one of 'LWFN', 'PFB' or 'OTHER'; it defaults to 'OTHER'.
14
+ 'dohex' is a flag which determines whether the eexec encrypted
15
+ part should be written as hexadecimal or binary, but only if kind
16
+ is 'OTHER'.
17
+ """
18
+
19
+ import fontTools
20
+ from fontTools.misc import eexec
21
+ from fontTools.misc.macCreatorType import getMacCreatorAndType
22
+ from fontTools.misc.textTools import bytechr, byteord, bytesjoin, tobytes
23
+ from fontTools.misc.psOperators import (
24
+ _type1_pre_eexec_order,
25
+ _type1_fontinfo_order,
26
+ _type1_post_eexec_order,
27
+ )
28
+ from fontTools.encodings.StandardEncoding import StandardEncoding
29
+ import os
30
+ import re
31
+
32
+ __author__ = "jvr"
33
+ __version__ = "1.0b3"
34
+ DEBUG = 0
35
+
36
+
37
+ try:
38
+ try:
39
+ from Carbon import Res
40
+ except ImportError:
41
+ import Res # MacPython < 2.2
42
+ except ImportError:
43
+ haveMacSupport = 0
44
+ else:
45
+ haveMacSupport = 1
46
+
47
+
48
+ class T1Error(Exception):
49
+ pass
50
+
51
+
52
+ class T1Font(object):
53
+ """Type 1 font class.
54
+
55
+ Uses a minimal interpeter that supports just about enough PS to parse
56
+ Type 1 fonts.
57
+ """
58
+
59
+ def __init__(self, path, encoding="ascii", kind=None):
60
+ if kind is None:
61
+ self.data, _ = read(path)
62
+ elif kind == "LWFN":
63
+ self.data = readLWFN(path)
64
+ elif kind == "PFB":
65
+ self.data = readPFB(path)
66
+ elif kind == "OTHER":
67
+ self.data = readOther(path)
68
+ else:
69
+ raise ValueError(kind)
70
+ self.encoding = encoding
71
+
72
+ def saveAs(self, path, type, dohex=False):
73
+ write(path, self.getData(), type, dohex)
74
+
75
+ def getData(self):
76
+ if not hasattr(self, "data"):
77
+ self.data = self.createData()
78
+ return self.data
79
+
80
+ def getGlyphSet(self):
81
+ """Return a generic GlyphSet, which is a dict-like object
82
+ mapping glyph names to glyph objects. The returned glyph objects
83
+ have a .draw() method that supports the Pen protocol, and will
84
+ have an attribute named 'width', but only *after* the .draw() method
85
+ has been called.
86
+
87
+ In the case of Type 1, the GlyphSet is simply the CharStrings dict.
88
+ """
89
+ return self["CharStrings"]
90
+
91
+ def __getitem__(self, key):
92
+ if not hasattr(self, "font"):
93
+ self.parse()
94
+ return self.font[key]
95
+
96
+ def parse(self):
97
+ from fontTools.misc import psLib
98
+ from fontTools.misc import psCharStrings
99
+
100
+ self.font = psLib.suckfont(self.data, self.encoding)
101
+ charStrings = self.font["CharStrings"]
102
+ lenIV = self.font["Private"].get("lenIV", 4)
103
+ assert lenIV >= 0
104
+ subrs = self.font["Private"]["Subrs"]
105
+ for glyphName, charString in charStrings.items():
106
+ charString, R = eexec.decrypt(charString, 4330)
107
+ charStrings[glyphName] = psCharStrings.T1CharString(
108
+ charString[lenIV:], subrs=subrs
109
+ )
110
+ for i in range(len(subrs)):
111
+ charString, R = eexec.decrypt(subrs[i], 4330)
112
+ subrs[i] = psCharStrings.T1CharString(charString[lenIV:], subrs=subrs)
113
+ del self.data
114
+
115
+ def createData(self):
116
+ sf = self.font
117
+
118
+ eexec_began = False
119
+ eexec_dict = {}
120
+ lines = []
121
+ lines.extend(
122
+ [
123
+ self._tobytes(f"%!FontType1-1.1: {sf['FontName']}"),
124
+ self._tobytes(f"%t1Font: ({fontTools.version})"),
125
+ self._tobytes(f"%%BeginResource: font {sf['FontName']}"),
126
+ ]
127
+ )
128
+ # follow t1write.c:writeRegNameKeyedFont
129
+ size = 3 # Headroom for new key addition
130
+ size += 1 # FontMatrix is always counted
131
+ size += 1 + 1 # Private, CharStings
132
+ for key in font_dictionary_keys:
133
+ size += int(key in sf)
134
+ lines.append(self._tobytes(f"{size} dict dup begin"))
135
+
136
+ for key, value in sf.items():
137
+ if eexec_began:
138
+ eexec_dict[key] = value
139
+ continue
140
+
141
+ if key == "FontInfo":
142
+ fi = sf["FontInfo"]
143
+ # follow t1write.c:writeFontInfoDict
144
+ size = 3 # Headroom for new key addition
145
+ for subkey in FontInfo_dictionary_keys:
146
+ size += int(subkey in fi)
147
+ lines.append(self._tobytes(f"/FontInfo {size} dict dup begin"))
148
+
149
+ for subkey, subvalue in fi.items():
150
+ lines.extend(self._make_lines(subkey, subvalue))
151
+ lines.append(b"end def")
152
+ elif key in _type1_post_eexec_order: # usually 'Private'
153
+ eexec_dict[key] = value
154
+ eexec_began = True
155
+ else:
156
+ lines.extend(self._make_lines(key, value))
157
+ lines.append(b"end")
158
+ eexec_portion = self.encode_eexec(eexec_dict)
159
+ lines.append(bytesjoin([b"currentfile eexec ", eexec_portion]))
160
+
161
+ for _ in range(8):
162
+ lines.append(self._tobytes("0" * 64))
163
+ lines.extend([b"cleartomark", b"%%EndResource", b"%%EOF"])
164
+
165
+ data = bytesjoin(lines, "\n")
166
+ return data
167
+
168
+ def encode_eexec(self, eexec_dict):
169
+ lines = []
170
+
171
+ # '-|', '|-', '|'
172
+ RD_key, ND_key, NP_key = None, None, None
173
+ lenIV = 4
174
+ subrs = std_subrs
175
+
176
+ # Ensure we look at Private first, because we need RD_key, ND_key, NP_key and lenIV
177
+ sortedItems = sorted(eexec_dict.items(), key=lambda item: item[0] != "Private")
178
+
179
+ for key, value in sortedItems:
180
+ if key == "Private":
181
+ pr = eexec_dict["Private"]
182
+ # follow t1write.c:writePrivateDict
183
+ size = 3 # for RD, ND, NP
184
+ for subkey in Private_dictionary_keys:
185
+ size += int(subkey in pr)
186
+ lines.append(b"dup /Private")
187
+ lines.append(self._tobytes(f"{size} dict dup begin"))
188
+ for subkey, subvalue in pr.items():
189
+ if not RD_key and subvalue == RD_value:
190
+ RD_key = subkey
191
+ elif not ND_key and subvalue in ND_values:
192
+ ND_key = subkey
193
+ elif not NP_key and subvalue in PD_values:
194
+ NP_key = subkey
195
+
196
+ if subkey == "lenIV":
197
+ lenIV = subvalue
198
+
199
+ if subkey == "OtherSubrs":
200
+ # XXX: assert that no flex hint is used
201
+ lines.append(self._tobytes(hintothers))
202
+ elif subkey == "Subrs":
203
+ for subr_bin in subvalue:
204
+ subr_bin.compile()
205
+ subrs = [subr_bin.bytecode for subr_bin in subvalue]
206
+ lines.append(f"/Subrs {len(subrs)} array".encode("ascii"))
207
+ for i, subr_bin in enumerate(subrs):
208
+ encrypted_subr, R = eexec.encrypt(
209
+ bytesjoin([char_IV[:lenIV], subr_bin]), 4330
210
+ )
211
+ lines.append(
212
+ bytesjoin(
213
+ [
214
+ self._tobytes(
215
+ f"dup {i} {len(encrypted_subr)} {RD_key} "
216
+ ),
217
+ encrypted_subr,
218
+ self._tobytes(f" {NP_key}"),
219
+ ]
220
+ )
221
+ )
222
+ lines.append(b"def")
223
+
224
+ lines.append(b"put")
225
+ else:
226
+ lines.extend(self._make_lines(subkey, subvalue))
227
+ elif key == "CharStrings":
228
+ lines.append(b"dup /CharStrings")
229
+ lines.append(
230
+ self._tobytes(f"{len(eexec_dict['CharStrings'])} dict dup begin")
231
+ )
232
+ for glyph_name, char_bin in eexec_dict["CharStrings"].items():
233
+ char_bin.compile()
234
+ encrypted_char, R = eexec.encrypt(
235
+ bytesjoin([char_IV[:lenIV], char_bin.bytecode]), 4330
236
+ )
237
+ lines.append(
238
+ bytesjoin(
239
+ [
240
+ self._tobytes(
241
+ f"/{glyph_name} {len(encrypted_char)} {RD_key} "
242
+ ),
243
+ encrypted_char,
244
+ self._tobytes(f" {ND_key}"),
245
+ ]
246
+ )
247
+ )
248
+ lines.append(b"end put")
249
+ else:
250
+ lines.extend(self._make_lines(key, value))
251
+
252
+ lines.extend(
253
+ [
254
+ b"end",
255
+ b"dup /FontName get exch definefont pop",
256
+ b"mark",
257
+ b"currentfile closefile\n",
258
+ ]
259
+ )
260
+
261
+ eexec_portion = bytesjoin(lines, "\n")
262
+ encrypted_eexec, R = eexec.encrypt(bytesjoin([eexec_IV, eexec_portion]), 55665)
263
+
264
+ return encrypted_eexec
265
+
266
+ def _make_lines(self, key, value):
267
+ if key == "FontName":
268
+ return [self._tobytes(f"/{key} /{value} def")]
269
+ if key in ["isFixedPitch", "ForceBold", "RndStemUp"]:
270
+ return [self._tobytes(f"/{key} {'true' if value else 'false'} def")]
271
+ elif key == "Encoding":
272
+ if value == StandardEncoding:
273
+ return [self._tobytes(f"/{key} StandardEncoding def")]
274
+ else:
275
+ # follow fontTools.misc.psOperators._type1_Encoding_repr
276
+ lines = []
277
+ lines.append(b"/Encoding 256 array")
278
+ lines.append(b"0 1 255 {1 index exch /.notdef put} for")
279
+ for i in range(256):
280
+ name = value[i]
281
+ if name != ".notdef":
282
+ lines.append(self._tobytes(f"dup {i} /{name} put"))
283
+ lines.append(b"def")
284
+ return lines
285
+ if isinstance(value, str):
286
+ return [self._tobytes(f"/{key} ({value}) def")]
287
+ elif isinstance(value, bool):
288
+ return [self._tobytes(f"/{key} {'true' if value else 'false'} def")]
289
+ elif isinstance(value, list):
290
+ return [self._tobytes(f"/{key} [{' '.join(str(v) for v in value)}] def")]
291
+ elif isinstance(value, tuple):
292
+ return [self._tobytes(f"/{key} {{{' '.join(str(v) for v in value)}}} def")]
293
+ else:
294
+ return [self._tobytes(f"/{key} {value} def")]
295
+
296
+ def _tobytes(self, s, errors="strict"):
297
+ return tobytes(s, self.encoding, errors)
298
+
299
+
300
+ # low level T1 data read and write functions
301
+
302
+
303
+ def read(path, onlyHeader=False):
304
+ """reads any Type 1 font file, returns raw data"""
305
+ _, ext = os.path.splitext(path)
306
+ ext = ext.lower()
307
+ creator, typ = getMacCreatorAndType(path)
308
+ if typ == "LWFN":
309
+ return readLWFN(path, onlyHeader), "LWFN"
310
+ if ext == ".pfb":
311
+ return readPFB(path, onlyHeader), "PFB"
312
+ else:
313
+ return readOther(path), "OTHER"
314
+
315
+
316
+ def write(path, data, kind="OTHER", dohex=False):
317
+ assertType1(data)
318
+ kind = kind.upper()
319
+ try:
320
+ os.remove(path)
321
+ except os.error:
322
+ pass
323
+ err = 1
324
+ try:
325
+ if kind == "LWFN":
326
+ writeLWFN(path, data)
327
+ elif kind == "PFB":
328
+ writePFB(path, data)
329
+ else:
330
+ writeOther(path, data, dohex)
331
+ err = 0
332
+ finally:
333
+ if err and not DEBUG:
334
+ try:
335
+ os.remove(path)
336
+ except os.error:
337
+ pass
338
+
339
+
340
+ # -- internal --
341
+
342
+ LWFNCHUNKSIZE = 2000
343
+ HEXLINELENGTH = 80
344
+
345
+
346
+ def readLWFN(path, onlyHeader=False):
347
+ """reads an LWFN font file, returns raw data"""
348
+ from fontTools.misc.macRes import ResourceReader
349
+
350
+ reader = ResourceReader(path)
351
+ try:
352
+ data = []
353
+ for res in reader.get("POST", []):
354
+ code = byteord(res.data[0])
355
+ if byteord(res.data[1]) != 0:
356
+ raise T1Error("corrupt LWFN file")
357
+ if code in [1, 2]:
358
+ if onlyHeader and code == 2:
359
+ break
360
+ data.append(res.data[2:])
361
+ elif code in [3, 5]:
362
+ break
363
+ elif code == 4:
364
+ with open(path, "rb") as f:
365
+ data.append(f.read())
366
+ elif code == 0:
367
+ pass # comment, ignore
368
+ else:
369
+ raise T1Error("bad chunk code: " + repr(code))
370
+ finally:
371
+ reader.close()
372
+ data = bytesjoin(data)
373
+ assertType1(data)
374
+ return data
375
+
376
+
377
+ def readPFB(path, onlyHeader=False):
378
+ """reads a PFB font file, returns raw data"""
379
+ data = []
380
+ with open(path, "rb") as f:
381
+ while True:
382
+ if f.read(1) != bytechr(128):
383
+ raise T1Error("corrupt PFB file")
384
+ code = byteord(f.read(1))
385
+ if code in [1, 2]:
386
+ chunklen = stringToLong(f.read(4))
387
+ chunk = f.read(chunklen)
388
+ assert len(chunk) == chunklen
389
+ data.append(chunk)
390
+ elif code == 3:
391
+ break
392
+ else:
393
+ raise T1Error("bad chunk code: " + repr(code))
394
+ if onlyHeader:
395
+ break
396
+ data = bytesjoin(data)
397
+ assertType1(data)
398
+ return data
399
+
400
+
401
+ def readOther(path):
402
+ """reads any (font) file, returns raw data"""
403
+ with open(path, "rb") as f:
404
+ data = f.read()
405
+ assertType1(data)
406
+ chunks = findEncryptedChunks(data)
407
+ data = []
408
+ for isEncrypted, chunk in chunks:
409
+ if isEncrypted and isHex(chunk[:4]):
410
+ data.append(deHexString(chunk))
411
+ else:
412
+ data.append(chunk)
413
+ return bytesjoin(data)
414
+
415
+
416
+ # file writing tools
417
+
418
+
419
+ def writeLWFN(path, data):
420
+ # Res.FSpCreateResFile was deprecated in OS X 10.5
421
+ Res.FSpCreateResFile(path, "just", "LWFN", 0)
422
+ resRef = Res.FSOpenResFile(path, 2) # write-only
423
+ try:
424
+ Res.UseResFile(resRef)
425
+ resID = 501
426
+ chunks = findEncryptedChunks(data)
427
+ for isEncrypted, chunk in chunks:
428
+ if isEncrypted:
429
+ code = 2
430
+ else:
431
+ code = 1
432
+ while chunk:
433
+ res = Res.Resource(bytechr(code) + "\0" + chunk[: LWFNCHUNKSIZE - 2])
434
+ res.AddResource("POST", resID, "")
435
+ chunk = chunk[LWFNCHUNKSIZE - 2 :]
436
+ resID = resID + 1
437
+ res = Res.Resource(bytechr(5) + "\0")
438
+ res.AddResource("POST", resID, "")
439
+ finally:
440
+ Res.CloseResFile(resRef)
441
+
442
+
443
+ def writePFB(path, data):
444
+ chunks = findEncryptedChunks(data)
445
+ with open(path, "wb") as f:
446
+ for isEncrypted, chunk in chunks:
447
+ if isEncrypted:
448
+ code = 2
449
+ else:
450
+ code = 1
451
+ f.write(bytechr(128) + bytechr(code))
452
+ f.write(longToString(len(chunk)))
453
+ f.write(chunk)
454
+ f.write(bytechr(128) + bytechr(3))
455
+
456
+
457
+ def writeOther(path, data, dohex=False):
458
+ chunks = findEncryptedChunks(data)
459
+ with open(path, "wb") as f:
460
+ hexlinelen = HEXLINELENGTH // 2
461
+ for isEncrypted, chunk in chunks:
462
+ if isEncrypted:
463
+ code = 2
464
+ else:
465
+ code = 1
466
+ if code == 2 and dohex:
467
+ while chunk:
468
+ f.write(eexec.hexString(chunk[:hexlinelen]))
469
+ f.write(b"\r")
470
+ chunk = chunk[hexlinelen:]
471
+ else:
472
+ f.write(chunk)
473
+
474
+
475
+ # decryption tools
476
+
477
+ EEXECBEGIN = b"currentfile eexec"
478
+ # The spec allows for 512 ASCII zeros interrupted by arbitrary whitespace to
479
+ # follow eexec
480
+ EEXECEND = re.compile(b"(0[ \t\r\n]*){512}", flags=re.M)
481
+ EEXECINTERNALEND = b"currentfile closefile"
482
+ EEXECBEGINMARKER = b"%-- eexec start\r"
483
+ EEXECENDMARKER = b"%-- eexec end\r"
484
+
485
+ _ishexRE = re.compile(b"[0-9A-Fa-f]*$")
486
+
487
+
488
+ def isHex(text):
489
+ return _ishexRE.match(text) is not None
490
+
491
+
492
+ def decryptType1(data):
493
+ chunks = findEncryptedChunks(data)
494
+ data = []
495
+ for isEncrypted, chunk in chunks:
496
+ if isEncrypted:
497
+ if isHex(chunk[:4]):
498
+ chunk = deHexString(chunk)
499
+ decrypted, R = eexec.decrypt(chunk, 55665)
500
+ decrypted = decrypted[4:]
501
+ if (
502
+ decrypted[-len(EEXECINTERNALEND) - 1 : -1] != EEXECINTERNALEND
503
+ and decrypted[-len(EEXECINTERNALEND) - 2 : -2] != EEXECINTERNALEND
504
+ ):
505
+ raise T1Error("invalid end of eexec part")
506
+ decrypted = decrypted[: -len(EEXECINTERNALEND) - 2] + b"\r"
507
+ data.append(EEXECBEGINMARKER + decrypted + EEXECENDMARKER)
508
+ else:
509
+ if chunk[-len(EEXECBEGIN) - 1 : -1] == EEXECBEGIN:
510
+ data.append(chunk[: -len(EEXECBEGIN) - 1])
511
+ else:
512
+ data.append(chunk)
513
+ return bytesjoin(data)
514
+
515
+
516
+ def findEncryptedChunks(data):
517
+ chunks = []
518
+ while True:
519
+ eBegin = data.find(EEXECBEGIN)
520
+ if eBegin < 0:
521
+ break
522
+ eBegin = eBegin + len(EEXECBEGIN) + 1
523
+ endMatch = EEXECEND.search(data, eBegin)
524
+ if endMatch is None:
525
+ raise T1Error("can't find end of eexec part")
526
+ eEnd = endMatch.start()
527
+ cypherText = data[eBegin : eEnd + 2]
528
+ if isHex(cypherText[:4]):
529
+ cypherText = deHexString(cypherText)
530
+ plainText, R = eexec.decrypt(cypherText, 55665)
531
+ eEndLocal = plainText.find(EEXECINTERNALEND)
532
+ if eEndLocal < 0:
533
+ raise T1Error("can't find end of eexec part")
534
+ chunks.append((0, data[:eBegin]))
535
+ chunks.append((1, cypherText[: eEndLocal + len(EEXECINTERNALEND) + 1]))
536
+ data = data[eEnd:]
537
+ chunks.append((0, data))
538
+ return chunks
539
+
540
+
541
+ def deHexString(hexstring):
542
+ return eexec.deHexString(bytesjoin(hexstring.split()))
543
+
544
+
545
+ # Type 1 assertion
546
+
547
+ _fontType1RE = re.compile(rb"/FontType\s+1\s+def")
548
+
549
+
550
+ def assertType1(data):
551
+ for head in [b"%!PS-AdobeFont", b"%!FontType1"]:
552
+ if data[: len(head)] == head:
553
+ break
554
+ else:
555
+ raise T1Error("not a PostScript font")
556
+ if not _fontType1RE.search(data):
557
+ raise T1Error("not a Type 1 font")
558
+ if data.find(b"currentfile eexec") < 0:
559
+ raise T1Error("not an encrypted Type 1 font")
560
+ # XXX what else?
561
+ return data
562
+
563
+
564
+ # pfb helpers
565
+
566
+
567
+ def longToString(long):
568
+ s = b""
569
+ for i in range(4):
570
+ s += bytechr((long & (0xFF << (i * 8))) >> i * 8)
571
+ return s
572
+
573
+
574
+ def stringToLong(s):
575
+ if len(s) != 4:
576
+ raise ValueError("string must be 4 bytes long")
577
+ l = 0
578
+ for i in range(4):
579
+ l += byteord(s[i]) << (i * 8)
580
+ return l
581
+
582
+
583
+ # PS stream helpers
584
+
585
+ font_dictionary_keys = list(_type1_pre_eexec_order)
586
+ # t1write.c:writeRegNameKeyedFont
587
+ # always counts following keys
588
+ font_dictionary_keys.remove("FontMatrix")
589
+
590
+ FontInfo_dictionary_keys = list(_type1_fontinfo_order)
591
+ # extend because AFDKO tx may use following keys
592
+ FontInfo_dictionary_keys.extend(
593
+ [
594
+ "FSType",
595
+ "Copyright",
596
+ ]
597
+ )
598
+
599
+ Private_dictionary_keys = [
600
+ # We don't know what names will be actually used.
601
+ # "RD",
602
+ # "ND",
603
+ # "NP",
604
+ "Subrs",
605
+ "OtherSubrs",
606
+ "UniqueID",
607
+ "BlueValues",
608
+ "OtherBlues",
609
+ "FamilyBlues",
610
+ "FamilyOtherBlues",
611
+ "BlueScale",
612
+ "BlueShift",
613
+ "BlueFuzz",
614
+ "StdHW",
615
+ "StdVW",
616
+ "StemSnapH",
617
+ "StemSnapV",
618
+ "ForceBold",
619
+ "LanguageGroup",
620
+ "password",
621
+ "lenIV",
622
+ "MinFeature",
623
+ "RndStemUp",
624
+ ]
625
+
626
+ # t1write_hintothers.h
627
+ hintothers = """/OtherSubrs[{}{}{}{systemdict/internaldict known not{pop 3}{1183615869
628
+ systemdict/internaldict get exec dup/startlock known{/startlock get exec}{dup
629
+ /strtlck known{/strtlck get exec}{pop 3}ifelse}ifelse}ifelse}executeonly]def"""
630
+ # t1write.c:saveStdSubrs
631
+ std_subrs = [
632
+ # 3 0 callother pop pop setcurrentpoint return
633
+ b"\x8e\x8b\x0c\x10\x0c\x11\x0c\x11\x0c\x21\x0b",
634
+ # 0 1 callother return
635
+ b"\x8b\x8c\x0c\x10\x0b",
636
+ # 0 2 callother return
637
+ b"\x8b\x8d\x0c\x10\x0b",
638
+ # return
639
+ b"\x0b",
640
+ # 3 1 3 callother pop callsubr return
641
+ b"\x8e\x8c\x8e\x0c\x10\x0c\x11\x0a\x0b",
642
+ ]
643
+ # follow t1write.c:writeRegNameKeyedFont
644
+ eexec_IV = b"cccc"
645
+ char_IV = b"\x0c\x0c\x0c\x0c"
646
+ RD_value = ("string", "currentfile", "exch", "readstring", "pop")
647
+ ND_values = [("def",), ("noaccess", "def")]
648
+ PD_values = [("put",), ("noaccess", "put")]