You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			573 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			573 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
_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))
 |