test code
This commit is contained in:
commit
b9e1625425
|
@ -0,0 +1,124 @@
|
||||||
|
import os
|
||||||
|
from PIL import Image
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
|
||||||
|
class Video(object):
|
||||||
|
def __init__(self, framerate, width, height):
|
||||||
|
self.framerate = framerate
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.sprites = []
|
||||||
|
|
||||||
|
def add_sprite(self, sprite):
|
||||||
|
self.sprites.append(sprite)
|
||||||
|
|
||||||
|
def render(self, outpath):
|
||||||
|
"""
|
||||||
|
render the video to a file
|
||||||
|
|
||||||
|
for frame in frames:
|
||||||
|
canvas = image()
|
||||||
|
for sprite in sprites:
|
||||||
|
sprite.next_frame()
|
||||||
|
sprite.draw(canvas)
|
||||||
|
canvas.save(...)
|
||||||
|
|
||||||
|
ffmepeg()
|
||||||
|
"""
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
for framenum in range(0, 30):
|
||||||
|
canvas = Image.new('RGB', (self.width, self.height, ))
|
||||||
|
for sprite in self.sprites:
|
||||||
|
sprite.draw(canvas)
|
||||||
|
|
||||||
|
with open(os.path.join(tmpdir, "frame_{:08d}.png".format(framenum)), "wb") as f:
|
||||||
|
canvas.save(f, "PNG")
|
||||||
|
|
||||||
|
for sprite in self.sprites:
|
||||||
|
sprite.next_frame()
|
||||||
|
|
||||||
|
print("done!")
|
||||||
|
os.system("open {}".format(tmpdir))
|
||||||
|
input()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Source(object):
|
||||||
|
def __init__(self, file_path):
|
||||||
|
self.file_path = file_path
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
"""
|
||||||
|
load the media from disk
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class Sprite(object):
|
||||||
|
def __init__(self, source, position=(0, 0)):
|
||||||
|
self.source = source
|
||||||
|
self.position = position
|
||||||
|
self.visible = False
|
||||||
|
self.animations = []
|
||||||
|
|
||||||
|
def add_animation(self, animation):
|
||||||
|
self.animations.append(animation)
|
||||||
|
|
||||||
|
#TODO transforms that can modify the image e.g. scale it
|
||||||
|
# also, AddTransformAnimation/RemoveTransformAnimation to make modifications on the fly
|
||||||
|
# also, TweenTransformationAnimation
|
||||||
|
# def add_transform(self, transform):
|
||||||
|
# pass
|
||||||
|
|
||||||
|
def get_pending_animations(self):
|
||||||
|
return self.animations#TODO
|
||||||
|
|
||||||
|
def next_frame(self):
|
||||||
|
for animation in self.get_pending_animations():
|
||||||
|
animation.apply()
|
||||||
|
|
||||||
|
def draw(self, canvas):
|
||||||
|
"""
|
||||||
|
Draw the sprite on top of the given canvas
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
def ImageSprite(Sprite):
|
||||||
|
def __init__(self, source, position=(0, 0)):
|
||||||
|
raise Exception("huh")
|
||||||
|
# super().__init__(source, position)
|
||||||
|
|
||||||
|
def draw(self, canvas):
|
||||||
|
"""
|
||||||
|
Draw the sprite on top of the given canvas
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class Animation(object):
|
||||||
|
# def __init__(self, path=None, filters=None, transforms=None, after=None):
|
||||||
|
# pass
|
||||||
|
|
||||||
|
def apply(self, sprite):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class ImageSource(Source):
|
||||||
|
def load(self):
|
||||||
|
self.img = Image.open(self.file_path)
|
||||||
|
|
||||||
|
|
||||||
|
class VideoSource(Source):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ShowAnimation(Animation):
|
||||||
|
def apply(self, sprite):
|
||||||
|
sprite.visible = True
|
||||||
|
|
||||||
|
class HideAnimation(Animation):
|
||||||
|
def apply(self, sprite):
|
||||||
|
sprite.visible = False
|
|
@ -0,0 +1,59 @@
|
||||||
|
# python-based animation software
|
||||||
|
|
||||||
|
# describe an animation using python code then render it to a video, gif, etc
|
||||||
|
|
||||||
|
# tl;dr we draw PNGs and assemble them with ffmpeg
|
||||||
|
|
||||||
|
# data model:
|
||||||
|
# source - input media such as a still image or a video
|
||||||
|
# sprite - an instance of a source's media
|
||||||
|
|
||||||
|
# animation - description of how a source is used in the video
|
||||||
|
|
||||||
|
|
||||||
|
# example video of the dvd bounce logo
|
||||||
|
|
||||||
|
from pyanimate import Video, \
|
||||||
|
Source, ImageSource, \
|
||||||
|
Sprite, ImageSprite, \
|
||||||
|
Animation, ShowAnimation, HideAnimation
|
||||||
|
|
||||||
|
|
||||||
|
# the video is the canvas that we'll animate objects on top of
|
||||||
|
video = Video(framerate=30, width=640, height=480)
|
||||||
|
|
||||||
|
# a Source is a piece of media that we can include in the animation
|
||||||
|
# there should not be any reason to create two Source()s of the same input media.
|
||||||
|
logo_img = ImageSource("dvd_logo.png")
|
||||||
|
|
||||||
|
# a Sprite is an instance of a piece of media. They contain contextual information such as the position of the sprite
|
||||||
|
# on the canvas.
|
||||||
|
logo = ImageSprite(logo_img) #, position=(0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
# now the sprite appears at 0,0
|
||||||
|
video.add_sprite(logo)
|
||||||
|
|
||||||
|
|
||||||
|
# Animations are things that happen to sprites. Sprites are hidden by default so you need a ShowAnimation() to
|
||||||
|
# make them visible
|
||||||
|
logo.add_animation(ShowAnimation())
|
||||||
|
|
||||||
|
# Now lets make the logo move. In this case, we just move it diagonally
|
||||||
|
# logo_bounce_1 = Animation(
|
||||||
|
# # path=xxx,
|
||||||
|
# # filters=xxx,
|
||||||
|
# # transforms=xxx,
|
||||||
|
# # ...
|
||||||
|
# after=None,
|
||||||
|
# )
|
||||||
|
|
||||||
|
# Animations are added to sprites. When the video is rendered, animations are applied to the sprite in each frame.
|
||||||
|
# Animations begin on frame 0 by default, unless they are delayed by setting a start frame=... or after=....
|
||||||
|
# logo.add_animation(logo_bounce_1)
|
||||||
|
|
||||||
|
|
||||||
|
# output the final thing
|
||||||
|
video.render("output.mp4")
|
||||||
|
# video.render("output.gif")
|
||||||
|
|
Loading…
Reference in New Issue