Python scripting#
Splash has the ability to be scripted using Python. It allows for the same level of control as the GUI, meaning that all objects types can be modified, created and deleted, except for Scenes due to a current internal limitation. This can be used for adding any kind of control to Splash: a new GUI, a HTTP, Websocket or OSC server, some automation…
You can specify a script for Splash to run from the command line. Any
argument after the --
will be sent to the script as parameters:
splash -P script.py config.json -- --pyArg1 value --pyArg2 ...
The script can define three different callbacks: - splash_init(): called once, initializes the script - splash_loop(): called at each frame - splash_stop(): called once, terminates the script
Two examples are included with Splash sources, in the addons/python
subdirectory: httpServer.py
and repl.py
. The second one is of
particular interest as it creates a Python console which can be queried
at runtime like any other Python console. Load it with Splash, and type
the following command to have more information about the Python Splash
API:
help(splash)
For now, Splash’s scripting does not support virtual environement, so you will need to do global installation for all librairies used in your script.
Modifying Splash’s graph#
It is possible to modify Splash’s graph (add or remove an object, link two
objects…) by accessing world
object’s attribute with the method
set_world_attribute
.
For instance to add an object of type camera:
splash.set_world_attribute("addObject","camera")
Attributes callbacks#
It is possible to set callbacks on Splash objects attributes, which are
called whenever the value of this attribute is changed. This is done
through two methods: splash.register_attribute_callback
and
splash.unregister_attribute_callback
. The following script gives a
glimpse at how to use them:
def callback(object, attribute):
print("Modified attribute {} of object {}".format(attribute, object))
# Set the callback and get its id, for the attribute "flip" of object "image"
attribute_id = splash.register_attribute_callback("image", "flip", callback)
# Modify the "flip" attribute of the "image" object. You should see the following:
# Modified attribute flip of object image
# Unregister the attribute
splash.unregister_attribute_callback(attribute_id)
A callback is called after the attribute is set to its new value in Splash’s
tree, but changes are actually applied in Splash only after all the callbacks
are called.
For instance, if you define a callback on the attribute flip
of the object
image
, the callback will be called after the flip attribute is set its new
value, but before the texture is actually flipped. This is due to the way attribute changes
are propagated across Splash processes and objects instances.
So if you want to call a function once changes are applied, you might want to do it in the main loop after toggling a trigger in the callback.
For instance:
trigger = False
def callback(object, attribute):
global trigger
trigger = True
def splash_loop():
global trigger
if trigger:
trigger = False
# Do whatever you want in here
It might be useful to wait a bit (using time.sleep for example) to be sure changes have been applied.
Grabbing rendered images#
If you want to grab rendered images from your script, it is possible to add and link a
sink with the class Sink
.
sink = splash.Sink() # Creates an instance of type Sink and a object in the graph
sink.link_to("window_1_cam1_warp")
sink.open() # Open the sink, which will start reading the input image
frame = sink.grab() # Grab the latest image from the sink
By default sink size is set to 512x512
, you might want to resize it with
the set_size
method before grabbing the output.
The grab
method returns the last frame as a bytearray
.