root/nodebox/branches/try-qt/nodebox/console.py

Revision 284, 5.3 kB (checked in by fdb, 13 months ago)

- Editor code
- No longer export gif files

Line 
1import sys
2from PyQt4.QtGui import QApplication
3
4from nodebox import graphics
5from nodebox import util
6
7class NodeBoxRunner(object):
8   
9    def __init__(self):
10        # Force QApplication initialisation.
11        self.app = QApplication(sys.argv)
12
13        self.namespace = {}
14        self.canvas = graphics.Canvas()
15        self.context = graphics.Context(self.canvas, self.namespace)
16        self.__doc__ = {}
17        self._pageNumber = 1
18        self.frame = 1
19       
20    def _check_animation(self):
21        """Returns False if this is not an animation, True otherwise.
22        Throws an expection if the animation is not correct (missing a draw method)."""
23        if self.canvas.speed is not None:
24            if not self.namespace.has_key('draw'):
25                raise graphics.NodeBoxError('Not a correct animation: No draw() method.')
26            return True
27        return False
28
29    def run(self, source_or_code):
30        self._initNamespace()
31        if isinstance(source_or_code, basestring):
32            source_or_code = compile(source_or_code + "\n\n", "<Untitled>", "exec")
33        exec source_or_code in self.namespace
34        if self._check_animation():
35            if self.namespace.has_key('setup'):
36                self.namespace['setup']()
37            self.namespace['draw']()
38       
39    def run_multiple(self, source_or_code, frames):
40        if isinstance(source_or_code, basestring):
41            source_or_code = compile(source_or_code + "\n\n", "<Untitled>", "exec")
42           
43        # First frame is special:
44        self.run(source_or_code)
45        yield 1
46        animation = self._check_animation()
47           
48        for i in range(frames-1):
49            self.canvas.clear()
50            self.frame = i + 2
51            self.namespace["PAGENUM"] = self.namespace["FRAME"] = self.frame
52            if animation:
53                self.namespace['draw']()
54            else:
55                exec source_or_code in self.namespace
56            yield self.frame
57   
58    def _initNamespace(self, frame=1):
59        self.canvas.clear()
60        self.namespace.clear()
61        # Add everything from the namespace
62        for name in graphics.__all__:
63            self.namespace[name] = getattr(graphics, name)
64        for name in util.__all__:
65            self.namespace[name] = getattr(util, name)
66        # Add everything from the context object
67        self.namespace["_ctx"] = self.context
68        for attrName in dir(self.context):
69            self.namespace[attrName] = getattr(self.context, attrName)
70        # Add the document global
71        self.namespace["__doc__"] = self.__doc__
72        # Add the frame
73        self.frame = frame
74        self.namespace["PAGENUM"] = self.namespace["FRAME"] = self.frame
75       
76def make_image(source_or_code, outputfile):
77   
78    """Given a source string or code object, executes the scripts and saves the result as an image.
79    Supported image extensions: pdf, tiff, png, jpg"""
80   
81    runner = NodeBoxRunner()
82    runner.run(source_or_code)
83    runner.canvas.save(outputfile)
84   
85def make_movie(source_or_code, outputfile, frames, fps=30):
86
87    """Given a source string or code object, executes the scripts and saves the result as a movie.
88    You also have to specify the number of frames to render.
89    Supported movie extension: mov"""
90
91    from nodebox.util import QTSupport
92    runner = NodeBoxRunner()
93    movie = QTSupport.Movie(outputfile, fps)
94    for frame in runner.run_multiple(source_or_code, frames):
95        movie.add(runner.canvas)
96    movie.save()
97
98def usage(err=""):
99    if len(err) > 0:
100        err = '\n\nError: ' + str(err)
101    print """NodeBox console runner
102Usage: console.py sourcefile imagefile
103   or: console.py sourcefile moviefile number_of_frames [fps]
104Supported image extensions: pdf, tiff, png, jpg
105Supported movie extension:  mov""" + err
106
107def main():
108    import sys, os
109    if len(sys.argv) < 2:
110        usage()
111    elif len(sys.argv) == 3: # Should be an image
112        basename, ext = os.path.splitext(sys.argv[2])
113        if ext not in ('.pdf', '.jpg', '.jpeg', '.png', '.tiff'):
114            return usage('This is not a supported image format.')
115        make_image(open(sys.argv[1]).read(), sys.argv[2])
116    elif len(sys.argv) == 4 or len(sys.argv) == 5: # Should be a movie
117        basename, ext = os.path.splitext(sys.argv[2])
118        if ext != '.mov':
119            return usage('This is not a supported movie format.')
120        if len(sys.argv) == 5:
121            try:
122                fps = int(sys.argv[4])
123            except ValueError:
124                return usage()
125        else:
126            fps = 30
127        make_movie(open(sys.argv[1]).read(), sys.argv[2], int(sys.argv[3]), fps)
128
129def test():
130    # Creating the NodeBoxRunner class directly:
131    runner = NodeBoxRunner()
132    runner.run('size(500,500)\nfor i in range(400):\n  oval(random(WIDTH),random(HEIGHT),50,50, fill=(random(), 0,0,random()))')
133    runner.canvas.save('console-test.pdf')
134    runner.canvas.save('console-test.png')
135   
136    # Using the runner for animations:
137    runner = NodeBoxRunner()
138    for frame in runner.run_multiple('size(300, 300)\ntext(FRAME, 100, 100)', 10):
139        runner.canvas.save('console-test-frame%02i.png' % frame)
140
141    # Using the shortcut functions:
142    make_image('size(200,200)\ntext(FRAME, 100, 100)', 'console-test.png')
143    make_movie('size(200,200)\ntext(FRAME, 100, 100)', 'console-test.mov', 10)
144
145if __name__=='__main__':
146    test()
Note: See TracBrowser for help on using the browser.