An image and video dithering library for art applications, including tools for pixel-by-pixel manipulation.
See INSTALL.md.
API documentation is generated from the library's docstrings. See docs/README.md to build and view it in a browser.
Examples for library usage:
from dithertools import composite, composite_color, load
# Load an image or video from disk (type is inferred from the file extension)
layer = load("photo.jpg") # returns Image
clip = load("clip.mp4") # returns Video
# Composite two images and save the result
result = composite(top=load("a.png"), bottom=load("b.png"))
result.save("output.png")
# Composite with per-channel colour masking
result = composite_color(top=load("a.png"), bottom=load("b.png"))
result.save("output.png")
# Composite an image over a video and save the result
result = composite(top=load("watermark.png"), bottom=load("clip.mp4"))
result.save("output.mp4")Operator examples:
from dithertools import load
img = load("photo.jpg") # Image
clip = load("clip.mp4") # Video
# Concatenate layers into a Video with +
seq = img + clip # Image followed by all video frames
seq = clip + img # video frames followed by the image
# Scale a Video's length with * (relative multiplier)
slow = clip * 2 # twice as many frames (lazy, mutates clip)
fast = clip * 0.5 # half as many frames
# Turn an Image into a Video with * (absolute frame count)
still = img * 30 # 30 identical frames at 24 fps
still = 30 * img # same — both orders work
# Mix operators freely
intro = img * 24 # 1-second hold
result = intro + clip # hold, then the clipDatamoshing examples:
from dithertools import load
from dithertools.datamosh import iframe_delete, pframe_dup
# Simulate I-frame deletion across a scene cut (two-source mode):
# scene_a's last frame is warped forward by scene_b's motion vectors.
# Only the warped frames are returned — scene_a's frames are not included.
result = iframe_delete(load("scene_a.mp4"), load("scene_b.mp4"))
result.save("moshed.mp4")
# Same effect on a single clip: delete the keyframe at frame 60.
# Frames before 60 pass through unchanged; frames from 60 onward are warped.
result = iframe_delete(load("clip.mp4"), transition_frame=60)
result.save("moshed.mp4")
# Simulate P-frame duplication: freeze a reference frame at frame 30 and
# accumulate motion on it. bloom_scale > 1 causes the drift to accelerate.
result = pframe_dup(load("clip.mp4"), transition_frame=30, bloom_scale=1.05)
result.save("bloomed.mp4")MIT License can be found within the LICENSE file.