psOperators.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. _accessstrings = {0: "", 1: "readonly", 2: "executeonly", 3: "noaccess"}
  2. class ps_object(object):
  3. literal = 1
  4. access = 0
  5. value = None
  6. def __init__(self, value):
  7. self.value = value
  8. self.type = self.__class__.__name__[3:] + "type"
  9. def __repr__(self):
  10. return "<%s %s>" % (self.__class__.__name__[3:], repr(self.value))
  11. class ps_operator(ps_object):
  12. literal = 0
  13. def __init__(self, name, function):
  14. self.name = name
  15. self.function = function
  16. self.type = self.__class__.__name__[3:] + "type"
  17. def __repr__(self):
  18. return "<operator %s>" % self.name
  19. class ps_procedure(ps_object):
  20. literal = 0
  21. def __repr__(self):
  22. return "<procedure>"
  23. def __str__(self):
  24. psstring = "{"
  25. for i in range(len(self.value)):
  26. if i:
  27. psstring = psstring + " " + str(self.value[i])
  28. else:
  29. psstring = psstring + str(self.value[i])
  30. return psstring + "}"
  31. class ps_name(ps_object):
  32. literal = 0
  33. def __str__(self):
  34. if self.literal:
  35. return "/" + self.value
  36. else:
  37. return self.value
  38. class ps_literal(ps_object):
  39. def __str__(self):
  40. return "/" + self.value
  41. class ps_array(ps_object):
  42. def __str__(self):
  43. psstring = "["
  44. for i in range(len(self.value)):
  45. item = self.value[i]
  46. access = _accessstrings[item.access]
  47. if access:
  48. access = " " + access
  49. if i:
  50. psstring = psstring + " " + str(item) + access
  51. else:
  52. psstring = psstring + str(item) + access
  53. return psstring + "]"
  54. def __repr__(self):
  55. return "<array>"
  56. _type1_pre_eexec_order = [
  57. "FontInfo",
  58. "FontName",
  59. "Encoding",
  60. "PaintType",
  61. "FontType",
  62. "FontMatrix",
  63. "FontBBox",
  64. "UniqueID",
  65. "Metrics",
  66. "StrokeWidth",
  67. ]
  68. _type1_fontinfo_order = [
  69. "version",
  70. "Notice",
  71. "FullName",
  72. "FamilyName",
  73. "Weight",
  74. "ItalicAngle",
  75. "isFixedPitch",
  76. "UnderlinePosition",
  77. "UnderlineThickness",
  78. ]
  79. _type1_post_eexec_order = ["Private", "CharStrings", "FID"]
  80. def _type1_item_repr(key, value):
  81. psstring = ""
  82. access = _accessstrings[value.access]
  83. if access:
  84. access = access + " "
  85. if key == "CharStrings":
  86. psstring = psstring + "/%s %s def\n" % (
  87. key,
  88. _type1_CharString_repr(value.value),
  89. )
  90. elif key == "Encoding":
  91. psstring = psstring + _type1_Encoding_repr(value, access)
  92. else:
  93. psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access)
  94. return psstring
  95. def _type1_Encoding_repr(encoding, access):
  96. encoding = encoding.value
  97. psstring = "/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n"
  98. for i in range(256):
  99. name = encoding[i].value
  100. if name != ".notdef":
  101. psstring = psstring + "dup %d /%s put\n" % (i, name)
  102. return psstring + access + "def\n"
  103. def _type1_CharString_repr(charstrings):
  104. items = sorted(charstrings.items())
  105. return "xxx"
  106. class ps_font(ps_object):
  107. def __str__(self):
  108. psstring = "%d dict dup begin\n" % len(self.value)
  109. for key in _type1_pre_eexec_order:
  110. try:
  111. value = self.value[key]
  112. except KeyError:
  113. pass
  114. else:
  115. psstring = psstring + _type1_item_repr(key, value)
  116. items = sorted(self.value.items())
  117. for key, value in items:
  118. if key not in _type1_pre_eexec_order + _type1_post_eexec_order:
  119. psstring = psstring + _type1_item_repr(key, value)
  120. psstring = psstring + "currentdict end\ncurrentfile eexec\ndup "
  121. for key in _type1_post_eexec_order:
  122. try:
  123. value = self.value[key]
  124. except KeyError:
  125. pass
  126. else:
  127. psstring = psstring + _type1_item_repr(key, value)
  128. return (
  129. psstring
  130. + "dup/FontName get exch definefont pop\nmark currentfile closefile\n"
  131. + 8 * (64 * "0" + "\n")
  132. + "cleartomark"
  133. + "\n"
  134. )
  135. def __repr__(self):
  136. return "<font>"
  137. class ps_file(ps_object):
  138. pass
  139. class ps_dict(ps_object):
  140. def __str__(self):
  141. psstring = "%d dict dup begin\n" % len(self.value)
  142. items = sorted(self.value.items())
  143. for key, value in items:
  144. access = _accessstrings[value.access]
  145. if access:
  146. access = access + " "
  147. psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access)
  148. return psstring + "end "
  149. def __repr__(self):
  150. return "<dict>"
  151. class ps_mark(ps_object):
  152. def __init__(self):
  153. self.value = "mark"
  154. self.type = self.__class__.__name__[3:] + "type"
  155. class ps_procmark(ps_object):
  156. def __init__(self):
  157. self.value = "procmark"
  158. self.type = self.__class__.__name__[3:] + "type"
  159. class ps_null(ps_object):
  160. def __init__(self):
  161. self.type = self.__class__.__name__[3:] + "type"
  162. class ps_boolean(ps_object):
  163. def __str__(self):
  164. if self.value:
  165. return "true"
  166. else:
  167. return "false"
  168. class ps_string(ps_object):
  169. def __str__(self):
  170. return "(%s)" % repr(self.value)[1:-1]
  171. class ps_integer(ps_object):
  172. def __str__(self):
  173. return repr(self.value)
  174. class ps_real(ps_object):
  175. def __str__(self):
  176. return repr(self.value)
  177. class PSOperators(object):
  178. def ps_def(self):
  179. obj = self.pop()
  180. name = self.pop()
  181. self.dictstack[-1][name.value] = obj
  182. def ps_bind(self):
  183. proc = self.pop("proceduretype")
  184. self.proc_bind(proc)
  185. self.push(proc)
  186. def proc_bind(self, proc):
  187. for i in range(len(proc.value)):
  188. item = proc.value[i]
  189. if item.type == "proceduretype":
  190. self.proc_bind(item)
  191. else:
  192. if not item.literal:
  193. try:
  194. obj = self.resolve_name(item.value)
  195. except:
  196. pass
  197. else:
  198. if obj.type == "operatortype":
  199. proc.value[i] = obj
  200. def ps_exch(self):
  201. if len(self.stack) < 2:
  202. raise RuntimeError("stack underflow")
  203. obj1 = self.pop()
  204. obj2 = self.pop()
  205. self.push(obj1)
  206. self.push(obj2)
  207. def ps_dup(self):
  208. if not self.stack:
  209. raise RuntimeError("stack underflow")
  210. self.push(self.stack[-1])
  211. def ps_exec(self):
  212. obj = self.pop()
  213. if obj.type == "proceduretype":
  214. self.call_procedure(obj)
  215. else:
  216. self.handle_object(obj)
  217. def ps_count(self):
  218. self.push(ps_integer(len(self.stack)))
  219. def ps_eq(self):
  220. any1 = self.pop()
  221. any2 = self.pop()
  222. self.push(ps_boolean(any1.value == any2.value))
  223. def ps_ne(self):
  224. any1 = self.pop()
  225. any2 = self.pop()
  226. self.push(ps_boolean(any1.value != any2.value))
  227. def ps_cvx(self):
  228. obj = self.pop()
  229. obj.literal = 0
  230. self.push(obj)
  231. def ps_matrix(self):
  232. matrix = [
  233. ps_real(1.0),
  234. ps_integer(0),
  235. ps_integer(0),
  236. ps_real(1.0),
  237. ps_integer(0),
  238. ps_integer(0),
  239. ]
  240. self.push(ps_array(matrix))
  241. def ps_string(self):
  242. num = self.pop("integertype").value
  243. self.push(ps_string("\0" * num))
  244. def ps_type(self):
  245. obj = self.pop()
  246. self.push(ps_string(obj.type))
  247. def ps_store(self):
  248. value = self.pop()
  249. key = self.pop()
  250. name = key.value
  251. for i in range(len(self.dictstack) - 1, -1, -1):
  252. if name in self.dictstack[i]:
  253. self.dictstack[i][name] = value
  254. break
  255. self.dictstack[-1][name] = value
  256. def ps_where(self):
  257. name = self.pop()
  258. # XXX
  259. self.push(ps_boolean(0))
  260. def ps_systemdict(self):
  261. self.push(ps_dict(self.dictstack[0]))
  262. def ps_userdict(self):
  263. self.push(ps_dict(self.dictstack[1]))
  264. def ps_currentdict(self):
  265. self.push(ps_dict(self.dictstack[-1]))
  266. def ps_currentfile(self):
  267. self.push(ps_file(self.tokenizer))
  268. def ps_eexec(self):
  269. f = self.pop("filetype").value
  270. f.starteexec()
  271. def ps_closefile(self):
  272. f = self.pop("filetype").value
  273. f.skipwhite()
  274. f.stopeexec()
  275. def ps_cleartomark(self):
  276. obj = self.pop()
  277. while obj != self.mark:
  278. obj = self.pop()
  279. def ps_readstring(self, ps_boolean=ps_boolean, len=len):
  280. s = self.pop("stringtype")
  281. oldstr = s.value
  282. f = self.pop("filetype")
  283. # pad = file.value.read(1)
  284. # for StringIO, this is faster
  285. f.value.pos = f.value.pos + 1
  286. newstr = f.value.read(len(oldstr))
  287. s.value = newstr
  288. self.push(s)
  289. self.push(ps_boolean(len(oldstr) == len(newstr)))
  290. def ps_known(self):
  291. key = self.pop()
  292. d = self.pop("dicttype", "fonttype")
  293. self.push(ps_boolean(key.value in d.value))
  294. def ps_if(self):
  295. proc = self.pop("proceduretype")
  296. if self.pop("booleantype").value:
  297. self.call_procedure(proc)
  298. def ps_ifelse(self):
  299. proc2 = self.pop("proceduretype")
  300. proc1 = self.pop("proceduretype")
  301. if self.pop("booleantype").value:
  302. self.call_procedure(proc1)
  303. else:
  304. self.call_procedure(proc2)
  305. def ps_readonly(self):
  306. obj = self.pop()
  307. if obj.access < 1:
  308. obj.access = 1
  309. self.push(obj)
  310. def ps_executeonly(self):
  311. obj = self.pop()
  312. if obj.access < 2:
  313. obj.access = 2
  314. self.push(obj)
  315. def ps_noaccess(self):
  316. obj = self.pop()
  317. if obj.access < 3:
  318. obj.access = 3
  319. self.push(obj)
  320. def ps_not(self):
  321. obj = self.pop("booleantype", "integertype")
  322. if obj.type == "booleantype":
  323. self.push(ps_boolean(not obj.value))
  324. else:
  325. self.push(ps_integer(~obj.value))
  326. def ps_print(self):
  327. str = self.pop("stringtype")
  328. print("PS output --->", str.value)
  329. def ps_anchorsearch(self):
  330. seek = self.pop("stringtype")
  331. s = self.pop("stringtype")
  332. seeklen = len(seek.value)
  333. if s.value[:seeklen] == seek.value:
  334. self.push(ps_string(s.value[seeklen:]))
  335. self.push(seek)
  336. self.push(ps_boolean(1))
  337. else:
  338. self.push(s)
  339. self.push(ps_boolean(0))
  340. def ps_array(self):
  341. num = self.pop("integertype")
  342. array = ps_array([None] * num.value)
  343. self.push(array)
  344. def ps_astore(self):
  345. array = self.pop("arraytype")
  346. for i in range(len(array.value) - 1, -1, -1):
  347. array.value[i] = self.pop()
  348. self.push(array)
  349. def ps_load(self):
  350. name = self.pop()
  351. self.push(self.resolve_name(name.value))
  352. def ps_put(self):
  353. obj1 = self.pop()
  354. obj2 = self.pop()
  355. obj3 = self.pop("arraytype", "dicttype", "stringtype", "proceduretype")
  356. tp = obj3.type
  357. if tp == "arraytype" or tp == "proceduretype":
  358. obj3.value[obj2.value] = obj1
  359. elif tp == "dicttype":
  360. obj3.value[obj2.value] = obj1
  361. elif tp == "stringtype":
  362. index = obj2.value
  363. obj3.value = obj3.value[:index] + chr(obj1.value) + obj3.value[index + 1 :]
  364. def ps_get(self):
  365. obj1 = self.pop()
  366. if obj1.value == "Encoding":
  367. pass
  368. obj2 = self.pop(
  369. "arraytype", "dicttype", "stringtype", "proceduretype", "fonttype"
  370. )
  371. tp = obj2.type
  372. if tp in ("arraytype", "proceduretype"):
  373. self.push(obj2.value[obj1.value])
  374. elif tp in ("dicttype", "fonttype"):
  375. self.push(obj2.value[obj1.value])
  376. elif tp == "stringtype":
  377. self.push(ps_integer(ord(obj2.value[obj1.value])))
  378. else:
  379. assert False, "shouldn't get here"
  380. def ps_getinterval(self):
  381. obj1 = self.pop("integertype")
  382. obj2 = self.pop("integertype")
  383. obj3 = self.pop("arraytype", "stringtype")
  384. tp = obj3.type
  385. if tp == "arraytype":
  386. self.push(ps_array(obj3.value[obj2.value : obj2.value + obj1.value]))
  387. elif tp == "stringtype":
  388. self.push(ps_string(obj3.value[obj2.value : obj2.value + obj1.value]))
  389. def ps_putinterval(self):
  390. obj1 = self.pop("arraytype", "stringtype")
  391. obj2 = self.pop("integertype")
  392. obj3 = self.pop("arraytype", "stringtype")
  393. tp = obj3.type
  394. if tp == "arraytype":
  395. obj3.value[obj2.value : obj2.value + len(obj1.value)] = obj1.value
  396. elif tp == "stringtype":
  397. newstr = obj3.value[: obj2.value]
  398. newstr = newstr + obj1.value
  399. newstr = newstr + obj3.value[obj2.value + len(obj1.value) :]
  400. obj3.value = newstr
  401. def ps_cvn(self):
  402. self.push(ps_name(self.pop("stringtype").value))
  403. def ps_index(self):
  404. n = self.pop("integertype").value
  405. if n < 0:
  406. raise RuntimeError("index may not be negative")
  407. self.push(self.stack[-1 - n])
  408. def ps_for(self):
  409. proc = self.pop("proceduretype")
  410. limit = self.pop("integertype", "realtype").value
  411. increment = self.pop("integertype", "realtype").value
  412. i = self.pop("integertype", "realtype").value
  413. while 1:
  414. if increment > 0:
  415. if i > limit:
  416. break
  417. else:
  418. if i < limit:
  419. break
  420. if type(i) == type(0.0):
  421. self.push(ps_real(i))
  422. else:
  423. self.push(ps_integer(i))
  424. self.call_procedure(proc)
  425. i = i + increment
  426. def ps_forall(self):
  427. proc = self.pop("proceduretype")
  428. obj = self.pop("arraytype", "stringtype", "dicttype")
  429. tp = obj.type
  430. if tp == "arraytype":
  431. for item in obj.value:
  432. self.push(item)
  433. self.call_procedure(proc)
  434. elif tp == "stringtype":
  435. for item in obj.value:
  436. self.push(ps_integer(ord(item)))
  437. self.call_procedure(proc)
  438. elif tp == "dicttype":
  439. for key, value in obj.value.items():
  440. self.push(ps_name(key))
  441. self.push(value)
  442. self.call_procedure(proc)
  443. def ps_definefont(self):
  444. font = self.pop("dicttype")
  445. name = self.pop()
  446. font = ps_font(font.value)
  447. self.dictstack[0]["FontDirectory"].value[name.value] = font
  448. self.push(font)
  449. def ps_findfont(self):
  450. name = self.pop()
  451. font = self.dictstack[0]["FontDirectory"].value[name.value]
  452. self.push(font)
  453. def ps_pop(self):
  454. self.pop()
  455. def ps_dict(self):
  456. self.pop("integertype")
  457. self.push(ps_dict({}))
  458. def ps_begin(self):
  459. self.dictstack.append(self.pop("dicttype").value)
  460. def ps_end(self):
  461. if len(self.dictstack) > 2:
  462. del self.dictstack[-1]
  463. else:
  464. raise RuntimeError("dictstack underflow")
  465. notdef = ".notdef"
  466. from fontTools.encodings.StandardEncoding import StandardEncoding
  467. ps_StandardEncoding = list(map(ps_name, StandardEncoding))