# a Pythonesque Canvas v0.8
# Author : Jerome Alet - <alet@librelogiciel.com>
# License : ReportLab's license
#
# $Id: pycanvas.py 3345 2008-12-12 17:55:22Z damian $
#
__doc__ = """A contributed Canvas class which can also output Python source code to "replay" operations later

pycanvas.Canvas class works exactly like canvas.Canvas, but you can
call str() on pycanvas.Canvas instances. Doing so will return the
Python source code equivalent to your own program, which would, when
run, produce the same PDF document as your original program.

Generated Python source code defines a doIt() function which accepts
a filename or file-like object as its first parameter, and an
optional boolean parameter named "regenerate".

The doIt() function will generate a PDF document and save it in the
file you specified in this argument. If the regenerate parameter is
set then it will also return an automatically generated equivalent
Python source code as a string of text, which you can run again to
produce the very same PDF document and the Python source code, which
you can run again... ad nauseam ! If the regenerate parameter is
unset or not used at all (it then defaults to being unset) then None
is returned and the doIt() function is much much faster, it is also
much faster than the original non-serialized program.

the tests/test_pdfgen_pycanvas.py program is the test suite
for pycanvas, you can do the following to run it :

    First set verbose=1 in reportlab/rl_config.py

    then from the command interpreter :

    $ cd tests
    $ python test_pdfgen_pycanvas.py >n1.py

    this will produce both n1.py and test_pdfgen_pycanvas.pdf

    then :

    $ python n1.py n1.pdf >n2.py
    $ python n2.py n2.pdf >n3.py
    $ ...

    n1.py, n2.py, n3.py and so on will be identical files.
    they eventually may end being a bit different because of
    rounding problems, mostly in the comments, but this
    doesn't matter since the values really are the same
    (e.g. 0 instead of 0.0, or .53 instead of 0.53)

    n1.pdf, n2.pdf, n3.pdf and so on will be PDF files
    similar to test_pdfgen_pycanvas.pdf.

Alternatively you can import n1.py (or n3.py, or n16384.py if you prefer)
in your own program, and then call its doIt function :

    import n1
    pythonsource = n1.doIt("myfile.pdf", regenerate=1)

Or if you don't need the python source code and want a faster result :

    import n1
    n1.doIt("myfile.pdf")

When the generated source code is run directly as an independant program,
then the equivalent python source code is printed to stdout, e.g. :

    python n1.py

    will print the python source code equivalent to n1.py

Why would you want to use such a beast ?

    - To linearize (serialize?) a program : optimizing some complex
      parts for example.

    - To debug : reading the generated Python source code may help you or
      the ReportLab team to diagnose problems. The generated code is now
      clearly commented and shows nesting levels, page numbers, and so
      on. You can use the generated script when asking for support : we
      can see the results you obtain without needing your datas or complete
      application.

    - To create standalone scripts : say your program uses a high level
      environment to generate its output (databases, RML, etc...), using
      this class would give you an equivalent program but with complete
      independance from the high level environment (e.g. if you don't
      have Oracle).

    - To contribute some nice looking PDF documents to the ReportLab website
      without having to send a complete application you don't want to
      distribute.

    - ... Insert your own ideas here ...

    - For fun because you can do it !
"""

import cStringIO
from reportlab.pdfgen import canvas
from reportlab.pdfgen import pathobject
from reportlab.pdfgen import textobject

PyHeader = '''#! /usr/bin/env python

#
# This code was entirely generated by ReportLab (http://www.reportlab.com)
#

import sys
from reportlab.pdfgen import pathobject
from reportlab.pdfgen import textobject
from reportlab.lib.colors import Color

def doIt(file, regenerate=0) :
    """Generates a PDF document, save it into file.

       file : either a filename or a file-like object.

       regenerate : if set then this function returns the Python source
                    code which when run will produce the same result.
                    if unset then this function returns None, and is
                    much faster.
    """
    if regenerate :
        from reportlab.pdfgen.pycanvas import Canvas
    else :
        from reportlab.pdfgen.canvas import Canvas
'''

PyFooter = '''
    # if we want the equivalent Python source code, then send it back
    if regenerate :
        return str(c)

if __name__ == "__main__" :
    if len(sys.argv) != 2 :
        # second argument must be the name of the PDF file to create
        sys.stderr.write("%s needs one and only one argument\\n" % sys.argv[0])
        sys.exit(-1)
    else :
        # we've got a filename, we can proceed.
        print doIt(sys.argv[1], regenerate=1)
        sys.exit(0)'''

def buildargs(*args, **kwargs) :
    """Constructs a printable list of arguments suitable for use in source function calls."""
    arguments = ""
    for arg in args :
        arguments = arguments + ("%s, " % repr(arg))
    for (kw, val) in kwargs.items() :
        arguments = arguments+ ("%s=%s, " % (kw, repr(val)))
    if arguments[-2:] == ", " :