Defining & Registering Custom Backends
bewegung
allows to add new, custom backends. It is a two-step process. First, a backend class must be derived from bewegung.BackendBase
. Second, an instance / object of this class must be added to the bewegung.backends
dictionary.
The BackendBase
API
Derive from this class when implementing a new backend.
- class bewegung.BackendBase
Base class for backends. Do not instantiate this class - derive and inherit from it instead.
Backend objects are mutable.
If the orginal cunstructor method is overridden, it must be called from the child class.
- __repr__()
Interactive string representation of backend object
Do not override!
- Return type
str
- _isinstance(obj)
Internal method: Checks whether or not a certain object is an allowed return type within the backend
Can be reimplemented.
- Parameters
obj (
Any
) – The objects which is supposed to be checked- Return type
bool
- _load()
Internal method: Orders the backend to import its dependencies (libraries)
Must be reimplemented!
- _prototype(video, **kwargs)
Internal method: Returns a factory function which produces a new canvas once per call
Must be reimplemented!
- Parameters
video (
VideoABC
) – A video objectkwargs – Keyword arguments for the backend library
- Return type
Callable
- _to_pil(obj)
Internal method: Converts canvas to Pillow Image object
Must be reimplemented!
- Parameters
obj (
Any
) – Backend canvas object- Return type
Image
- isinstance(obj, hard=True)
Checks whether or not a certain object is an allowed return type within the backend
Do not override!
- Parameters
obj (
Any
) – The objects which is supposed to be checkedhard (
bool
) – If set toTrue
when the backend is not loaded, the backend will not be loaded for the check and the test will therefore always fail (returnFalse
).
- Return type
bool
- load()
Orders the backend to import its dependencies (libraries)
Do not override!
- property loaded: bool
Has the backend imported its dependencies?
Do not override!
- Type
Status
- Return type
bool
- prototype(video, **kwargs)
Returns a factory function which produces a new canvas once per call
Do not override!
- Parameters
video (
VideoABC
) – A video objectkwargs – Keyword arguments for the backend library
- Return type
Callable
- to_pil(obj)
Converts canvas to Pillow Image object
Do not override!
- Parameters
obj (
Any
) – Backend canvas object- Return type
Image
- property type: Type
Exposes backends canvas class
Do not override!
- Return type
Type
A Minimal Backend based on numpy
The following example illustrates how to build a custom backend around the numpy
library. numpy.ndarray
objects are used as a canvas.
from typing import Any, Callable
from PIL.Image import Image, fromarray
from bewegung import (
Video,
BackendBase,
backends,
)
class NumpyBackend(BackendBase):
def __init__(self):
super().__init__() # call BackendBase constructor!
self._np = None # lazy import of numpy
def _prototype(self, video: Video, **kwargs) -> Callable:
width = kwargs.get('width', video.width)
height = kwargs.get('height', video.height)
def factory():
canvas = self._np.zeros(
(width, height, 4),
dtype = 'u1', # uint8
) # black canvas, RGBA
canvas[:, :, 3] = 255 # opaque
return canvas
return factory
def _load(self):
import numpy as np # lazy import of numpy
self._np = np # lazy import of numpy
self._type = np.ndarray # set type so it can be recognized
def _to_pil(self, obj: Any) -> Image:
if obj.dtype != self._np.uint8:
raise TypeError('unhandled datatype')
if obj.ndim != 3:
raise TypeError('unhandled color configuration')
if obj.shape[2] != 4:
raise TypeError('unhandled color configuration')
return fromarray(obj, mode = 'RGBA') # convert to Pillow Image and return
backends['numpy'] = NumpyBackend() # register backend
v = Video(width = 480, height = 270, seconds = 1.0)
@v.sequence()
class Foo:
@v.layer(canvas = v.canvas(backend = 'numpy'))
def bar(self, canvas): # a numpy ndarray
canvas[30:50, 40:60, 0] = 255 # red square
return canvas
v.reset()
v.render_frame(v.time(0))

The _prototype
method should return a factory function without parameters. It also processes keyword arguments, fixes them if required and sets defaults. The _load
method is responsible for “lazy” loading of the underlying library, numpy
in this case. The eventually returned canvas datatype must be assigned to _type
. The _to_pil
method is responsible for converting the backend’s canvas type to a Pillow Image object. It may also perform consistency checks.