Spaces:
Paused
Paused
| _accessstrings = {0: "", 1: "readonly", 2: "executeonly", 3: "noaccess"} | |
| class ps_object(object): | |
| literal = 1 | |
| access = 0 | |
| value = None | |
| def __init__(self, value): | |
| self.value = value | |
| self.type = self.__class__.__name__[3:] + "type" | |
| def __repr__(self): | |
| return "<%s %s>" % (self.__class__.__name__[3:], repr(self.value)) | |
| class ps_operator(ps_object): | |
| literal = 0 | |
| def __init__(self, name, function): | |
| self.name = name | |
| self.function = function | |
| self.type = self.__class__.__name__[3:] + "type" | |
| def __repr__(self): | |
| return "<operator %s>" % self.name | |
| class ps_procedure(ps_object): | |
| literal = 0 | |
| def __repr__(self): | |
| return "<procedure>" | |
| def __str__(self): | |
| psstring = "{" | |
| for i in range(len(self.value)): | |
| if i: | |
| psstring = psstring + " " + str(self.value[i]) | |
| else: | |
| psstring = psstring + str(self.value[i]) | |
| return psstring + "}" | |
| class ps_name(ps_object): | |
| literal = 0 | |
| def __str__(self): | |
| if self.literal: | |
| return "/" + self.value | |
| else: | |
| return self.value | |
| class ps_literal(ps_object): | |
| def __str__(self): | |
| return "/" + self.value | |
| class ps_array(ps_object): | |
| def __str__(self): | |
| psstring = "[" | |
| for i in range(len(self.value)): | |
| item = self.value[i] | |
| access = _accessstrings[item.access] | |
| if access: | |
| access = " " + access | |
| if i: | |
| psstring = psstring + " " + str(item) + access | |
| else: | |
| psstring = psstring + str(item) + access | |
| return psstring + "]" | |
| def __repr__(self): | |
| return "<array>" | |
| _type1_pre_eexec_order = [ | |
| "FontInfo", | |
| "FontName", | |
| "Encoding", | |
| "PaintType", | |
| "FontType", | |
| "FontMatrix", | |
| "FontBBox", | |
| "UniqueID", | |
| "Metrics", | |
| "StrokeWidth", | |
| ] | |
| _type1_fontinfo_order = [ | |
| "version", | |
| "Notice", | |
| "FullName", | |
| "FamilyName", | |
| "Weight", | |
| "ItalicAngle", | |
| "isFixedPitch", | |
| "UnderlinePosition", | |
| "UnderlineThickness", | |
| ] | |
| _type1_post_eexec_order = ["Private", "CharStrings", "FID"] | |
| def _type1_item_repr(key, value): | |
| psstring = "" | |
| access = _accessstrings[value.access] | |
| if access: | |
| access = access + " " | |
| if key == "CharStrings": | |
| psstring = psstring + "/%s %s def\n" % ( | |
| key, | |
| _type1_CharString_repr(value.value), | |
| ) | |
| elif key == "Encoding": | |
| psstring = psstring + _type1_Encoding_repr(value, access) | |
| else: | |
| psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access) | |
| return psstring | |
| def _type1_Encoding_repr(encoding, access): | |
| encoding = encoding.value | |
| psstring = "/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n" | |
| for i in range(256): | |
| name = encoding[i].value | |
| if name != ".notdef": | |
| psstring = psstring + "dup %d /%s put\n" % (i, name) | |
| return psstring + access + "def\n" | |
| def _type1_CharString_repr(charstrings): | |
| items = sorted(charstrings.items()) | |
| return "xxx" | |
| class ps_font(ps_object): | |
| def __str__(self): | |
| psstring = "%d dict dup begin\n" % len(self.value) | |
| for key in _type1_pre_eexec_order: | |
| try: | |
| value = self.value[key] | |
| except KeyError: | |
| pass | |
| else: | |
| psstring = psstring + _type1_item_repr(key, value) | |
| items = sorted(self.value.items()) | |
| for key, value in items: | |
| if key not in _type1_pre_eexec_order + _type1_post_eexec_order: | |
| psstring = psstring + _type1_item_repr(key, value) | |
| psstring = psstring + "currentdict end\ncurrentfile eexec\ndup " | |
| for key in _type1_post_eexec_order: | |
| try: | |
| value = self.value[key] | |
| except KeyError: | |
| pass | |
| else: | |
| psstring = psstring + _type1_item_repr(key, value) | |
| return ( | |
| psstring | |
| + "dup/FontName get exch definefont pop\nmark currentfile closefile\n" | |
| + 8 * (64 * "0" + "\n") | |
| + "cleartomark" | |
| + "\n" | |
| ) | |
| def __repr__(self): | |
| return "<font>" | |
| class ps_file(ps_object): | |
| pass | |
| class ps_dict(ps_object): | |
| def __str__(self): | |
| psstring = "%d dict dup begin\n" % len(self.value) | |
| items = sorted(self.value.items()) | |
| for key, value in items: | |
| access = _accessstrings[value.access] | |
| if access: | |
| access = access + " " | |
| psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access) | |
| return psstring + "end " | |
| def __repr__(self): | |
| return "<dict>" | |
| class ps_mark(ps_object): | |
| def __init__(self): | |
| self.value = "mark" | |
| self.type = self.__class__.__name__[3:] + "type" | |
| class ps_procmark(ps_object): | |
| def __init__(self): | |
| self.value = "procmark" | |
| self.type = self.__class__.__name__[3:] + "type" | |
| class ps_null(ps_object): | |
| def __init__(self): | |
| self.type = self.__class__.__name__[3:] + "type" | |
| class ps_boolean(ps_object): | |
| def __str__(self): | |
| if self.value: | |
| return "true" | |
| else: | |
| return "false" | |
| class ps_string(ps_object): | |
| def __str__(self): | |
| return "(%s)" % repr(self.value)[1:-1] | |
| class ps_integer(ps_object): | |
| def __str__(self): | |
| return repr(self.value) | |
| class ps_real(ps_object): | |
| def __str__(self): | |
| return repr(self.value) | |
| class PSOperators(object): | |
| def ps_def(self): | |
| obj = self.pop() | |
| name = self.pop() | |
| self.dictstack[-1][name.value] = obj | |
| def ps_bind(self): | |
| proc = self.pop("proceduretype") | |
| self.proc_bind(proc) | |
| self.push(proc) | |
| def proc_bind(self, proc): | |
| for i in range(len(proc.value)): | |
| item = proc.value[i] | |
| if item.type == "proceduretype": | |
| self.proc_bind(item) | |
| else: | |
| if not item.literal: | |
| try: | |
| obj = self.resolve_name(item.value) | |
| except: | |
| pass | |
| else: | |
| if obj.type == "operatortype": | |
| proc.value[i] = obj | |
| def ps_exch(self): | |
| if len(self.stack) < 2: | |
| raise RuntimeError("stack underflow") | |
| obj1 = self.pop() | |
| obj2 = self.pop() | |
| self.push(obj1) | |
| self.push(obj2) | |
| def ps_dup(self): | |
| if not self.stack: | |
| raise RuntimeError("stack underflow") | |
| self.push(self.stack[-1]) | |
| def ps_exec(self): | |
| obj = self.pop() | |
| if obj.type == "proceduretype": | |
| self.call_procedure(obj) | |
| else: | |
| self.handle_object(obj) | |
| def ps_count(self): | |
| self.push(ps_integer(len(self.stack))) | |
| def ps_eq(self): | |
| any1 = self.pop() | |
| any2 = self.pop() | |
| self.push(ps_boolean(any1.value == any2.value)) | |
| def ps_ne(self): | |
| any1 = self.pop() | |
| any2 = self.pop() | |
| self.push(ps_boolean(any1.value != any2.value)) | |
| def ps_cvx(self): | |
| obj = self.pop() | |
| obj.literal = 0 | |
| self.push(obj) | |
| def ps_matrix(self): | |
| matrix = [ | |
| ps_real(1.0), | |
| ps_integer(0), | |
| ps_integer(0), | |
| ps_real(1.0), | |
| ps_integer(0), | |
| ps_integer(0), | |
| ] | |
| self.push(ps_array(matrix)) | |
| def ps_string(self): | |
| num = self.pop("integertype").value | |
| self.push(ps_string("\0" * num)) | |
| def ps_type(self): | |
| obj = self.pop() | |
| self.push(ps_string(obj.type)) | |
| def ps_store(self): | |
| value = self.pop() | |
| key = self.pop() | |
| name = key.value | |
| for i in range(len(self.dictstack) - 1, -1, -1): | |
| if name in self.dictstack[i]: | |
| self.dictstack[i][name] = value | |
| break | |
| self.dictstack[-1][name] = value | |
| def ps_where(self): | |
| name = self.pop() | |
| # XXX | |
| self.push(ps_boolean(0)) | |
| def ps_systemdict(self): | |
| self.push(ps_dict(self.dictstack[0])) | |
| def ps_userdict(self): | |
| self.push(ps_dict(self.dictstack[1])) | |
| def ps_currentdict(self): | |
| self.push(ps_dict(self.dictstack[-1])) | |
| def ps_currentfile(self): | |
| self.push(ps_file(self.tokenizer)) | |
| def ps_eexec(self): | |
| f = self.pop("filetype").value | |
| f.starteexec() | |
| def ps_closefile(self): | |
| f = self.pop("filetype").value | |
| f.skipwhite() | |
| f.stopeexec() | |
| def ps_cleartomark(self): | |
| obj = self.pop() | |
| while obj != self.mark: | |
| obj = self.pop() | |
| def ps_readstring(self, ps_boolean=ps_boolean, len=len): | |
| s = self.pop("stringtype") | |
| oldstr = s.value | |
| f = self.pop("filetype") | |
| # pad = file.value.read(1) | |
| # for StringIO, this is faster | |
| f.value.pos = f.value.pos + 1 | |
| newstr = f.value.read(len(oldstr)) | |
| s.value = newstr | |
| self.push(s) | |
| self.push(ps_boolean(len(oldstr) == len(newstr))) | |
| def ps_known(self): | |
| key = self.pop() | |
| d = self.pop("dicttype", "fonttype") | |
| self.push(ps_boolean(key.value in d.value)) | |
| def ps_if(self): | |
| proc = self.pop("proceduretype") | |
| if self.pop("booleantype").value: | |
| self.call_procedure(proc) | |
| def ps_ifelse(self): | |
| proc2 = self.pop("proceduretype") | |
| proc1 = self.pop("proceduretype") | |
| if self.pop("booleantype").value: | |
| self.call_procedure(proc1) | |
| else: | |
| self.call_procedure(proc2) | |
| def ps_readonly(self): | |
| obj = self.pop() | |
| if obj.access < 1: | |
| obj.access = 1 | |
| self.push(obj) | |
| def ps_executeonly(self): | |
| obj = self.pop() | |
| if obj.access < 2: | |
| obj.access = 2 | |
| self.push(obj) | |
| def ps_noaccess(self): | |
| obj = self.pop() | |
| if obj.access < 3: | |
| obj.access = 3 | |
| self.push(obj) | |
| def ps_not(self): | |
| obj = self.pop("booleantype", "integertype") | |
| if obj.type == "booleantype": | |
| self.push(ps_boolean(not obj.value)) | |
| else: | |
| self.push(ps_integer(~obj.value)) | |
| def ps_print(self): | |
| str = self.pop("stringtype") | |
| print("PS output --->", str.value) | |
| def ps_anchorsearch(self): | |
| seek = self.pop("stringtype") | |
| s = self.pop("stringtype") | |
| seeklen = len(seek.value) | |
| if s.value[:seeklen] == seek.value: | |
| self.push(ps_string(s.value[seeklen:])) | |
| self.push(seek) | |
| self.push(ps_boolean(1)) | |
| else: | |
| self.push(s) | |
| self.push(ps_boolean(0)) | |
| def ps_array(self): | |
| num = self.pop("integertype") | |
| array = ps_array([None] * num.value) | |
| self.push(array) | |
| def ps_astore(self): | |
| array = self.pop("arraytype") | |
| for i in range(len(array.value) - 1, -1, -1): | |
| array.value[i] = self.pop() | |
| self.push(array) | |
| def ps_load(self): | |
| name = self.pop() | |
| self.push(self.resolve_name(name.value)) | |
| def ps_put(self): | |
| obj1 = self.pop() | |
| obj2 = self.pop() | |
| obj3 = self.pop("arraytype", "dicttype", "stringtype", "proceduretype") | |
| tp = obj3.type | |
| if tp == "arraytype" or tp == "proceduretype": | |
| obj3.value[obj2.value] = obj1 | |
| elif tp == "dicttype": | |
| obj3.value[obj2.value] = obj1 | |
| elif tp == "stringtype": | |
| index = obj2.value | |
| obj3.value = obj3.value[:index] + chr(obj1.value) + obj3.value[index + 1 :] | |
| def ps_get(self): | |
| obj1 = self.pop() | |
| if obj1.value == "Encoding": | |
| pass | |
| obj2 = self.pop( | |
| "arraytype", "dicttype", "stringtype", "proceduretype", "fonttype" | |
| ) | |
| tp = obj2.type | |
| if tp in ("arraytype", "proceduretype"): | |
| self.push(obj2.value[obj1.value]) | |
| elif tp in ("dicttype", "fonttype"): | |
| self.push(obj2.value[obj1.value]) | |
| elif tp == "stringtype": | |
| self.push(ps_integer(ord(obj2.value[obj1.value]))) | |
| else: | |
| assert False, "shouldn't get here" | |
| def ps_getinterval(self): | |
| obj1 = self.pop("integertype") | |
| obj2 = self.pop("integertype") | |
| obj3 = self.pop("arraytype", "stringtype") | |
| tp = obj3.type | |
| if tp == "arraytype": | |
| self.push(ps_array(obj3.value[obj2.value : obj2.value + obj1.value])) | |
| elif tp == "stringtype": | |
| self.push(ps_string(obj3.value[obj2.value : obj2.value + obj1.value])) | |
| def ps_putinterval(self): | |
| obj1 = self.pop("arraytype", "stringtype") | |
| obj2 = self.pop("integertype") | |
| obj3 = self.pop("arraytype", "stringtype") | |
| tp = obj3.type | |
| if tp == "arraytype": | |
| obj3.value[obj2.value : obj2.value + len(obj1.value)] = obj1.value | |
| elif tp == "stringtype": | |
| newstr = obj3.value[: obj2.value] | |
| newstr = newstr + obj1.value | |
| newstr = newstr + obj3.value[obj2.value + len(obj1.value) :] | |
| obj3.value = newstr | |
| def ps_cvn(self): | |
| self.push(ps_name(self.pop("stringtype").value)) | |
| def ps_index(self): | |
| n = self.pop("integertype").value | |
| if n < 0: | |
| raise RuntimeError("index may not be negative") | |
| self.push(self.stack[-1 - n]) | |
| def ps_for(self): | |
| proc = self.pop("proceduretype") | |
| limit = self.pop("integertype", "realtype").value | |
| increment = self.pop("integertype", "realtype").value | |
| i = self.pop("integertype", "realtype").value | |
| while 1: | |
| if increment > 0: | |
| if i > limit: | |
| break | |
| else: | |
| if i < limit: | |
| break | |
| if type(i) == type(0.0): | |
| self.push(ps_real(i)) | |
| else: | |
| self.push(ps_integer(i)) | |
| self.call_procedure(proc) | |
| i = i + increment | |
| def ps_forall(self): | |
| proc = self.pop("proceduretype") | |
| obj = self.pop("arraytype", "stringtype", "dicttype") | |
| tp = obj.type | |
| if tp == "arraytype": | |
| for item in obj.value: | |
| self.push(item) | |
| self.call_procedure(proc) | |
| elif tp == "stringtype": | |
| for item in obj.value: | |
| self.push(ps_integer(ord(item))) | |
| self.call_procedure(proc) | |
| elif tp == "dicttype": | |
| for key, value in obj.value.items(): | |
| self.push(ps_name(key)) | |
| self.push(value) | |
| self.call_procedure(proc) | |
| def ps_definefont(self): | |
| font = self.pop("dicttype") | |
| name = self.pop() | |
| font = ps_font(font.value) | |
| self.dictstack[0]["FontDirectory"].value[name.value] = font | |
| self.push(font) | |
| def ps_findfont(self): | |
| name = self.pop() | |
| font = self.dictstack[0]["FontDirectory"].value[name.value] | |
| self.push(font) | |
| def ps_pop(self): | |
| self.pop() | |
| def ps_dict(self): | |
| self.pop("integertype") | |
| self.push(ps_dict({})) | |
| def ps_begin(self): | |
| self.dictstack.append(self.pop("dicttype").value) | |
| def ps_end(self): | |
| if len(self.dictstack) > 2: | |
| del self.dictstack[-1] | |
| else: | |
| raise RuntimeError("dictstack underflow") | |
| notdef = ".notdef" | |
| from fontTools.encodings.StandardEncoding import StandardEncoding | |
| ps_StandardEncoding = list(map(ps_name, StandardEncoding)) | |