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