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.