Source

yuureinohebi / gsut.py

#/usr/bin/env python3
"""Ghostscript utilities toolkit, like GLut, but better!"""
from functools import partial
import libgs
import gsu

class GhostScriptInterpreter(object):
    """A high level interface for Ghostscript. To push words, you only have
    to call methods on the object"""
    def __init__(self):
        gs = libgs.gsapi_new_instance()
        libgs.gsapi_init_with_args(gs, [
                    # doesn't matter that much, we use the default name
                    'gs',
                    # quiet out copyright messages and stuff
                    '-q'
                ])

        # create references to C functions, we have to keep these references
        # along, otherwise the GC might discard them and the callback fails
        self._stdout_handler_c = libgs.c_stdstream_t(self._stdout_handler)
        self._stderr_handler_c = libgs.c_stdstream_t(self._stderr_handler)
        self._stdin_handler_c = libgs.c_stdstream_t(self._stdin_handler)

        # set up stdio
        libgs.gsapi_set_stdio(gs, self._stdin_handler_c,
                self._stdout_handler_c,
                self._stderr_handler_c)
        # save for later use
        self._instance = gs
        self._stdout = ''

    def _stdout_handler(self, caller_handle, buf, length):
        """Handles the stdout of the Ghostscript interpreter"""
        self._stdout += str(buf, 'utf-8')
        # return length to signalize we handled the data
        return length

    def _stdin_handler(self, caller_handle, buf, length):
        # not yet known how to proceed with stdin
        return length

    _stderr_handler = _stdin_handler

    def number(self, value):
        """Pushes a number on the stack by converting into a string"""
        return self.raw(str(value))

    def raw(self, code):
        """Runs raw PostScript code on the current instance"""
        # prepend space to avoid clashing with stuff that might already
        # be on the stack
        gsu.run_code(self._instance, " {}".format(code))
        # always return self to make sure chainability works
        return self

    def __getattr__(self, name):
        """Returns a function that will push the value once called"""
        return partial(self.raw, code=name)

def main():
    gsi = GhostScriptInterpreter()
    gsi.raw("1 2 add == flush")
    gsi.number(1).number(2).add().raw('==').flush()

if __name__ == '__main__':
    main()