Spaces:
Running
on
L4
Running
on
L4
import os | |
import uuid | |
import json | |
import numpy as np | |
from moviepy.editor import ImageClip, concatenate_videoclips | |
import shutil | |
from deepsvg.svglib.svg import SVG | |
from deepsvg.svglib.geom import Bbox | |
from ..config import ROOT_DIR | |
class Frame: | |
def __init__(self, index, keyframe=False, svg=None): | |
self.index = index | |
self.keyframe = keyframe | |
if svg is None: | |
svg = SVG([], viewbox=Bbox(256)) | |
self.svg = svg | |
self.kivy_bezierpaths = None | |
def to_dict(self): | |
return { | |
"index": self.index, | |
"keyframe": self.keyframe | |
} | |
def load_dict(frame): | |
f = Frame(frame["index"], frame["keyframe"]) | |
return f | |
class DeepSVGProject: | |
def __init__(self, name="Title"): | |
self.name = name | |
self.uid = str(uuid.uuid4()) | |
self.frames = [Frame(index=0)] | |
def filename(self): | |
return os.path.join(ROOT_DIR, f"{self.uid}.json") | |
def base_dir(self): | |
base_dir = os.path.join(ROOT_DIR, self.uid) | |
if not os.path.exists(base_dir): | |
os.makedirs(base_dir) | |
return base_dir | |
def cache_dir(self): | |
cache_dir = os.path.join(self.base_dir, "cache") | |
if not os.path.exists(cache_dir): | |
os.makedirs(cache_dir) | |
return cache_dir | |
def load_project(self, file_path): | |
with open(file_path, "r") as f: | |
data = json.load(f) | |
self.name = data["name"] | |
self.uid = data["uid"] | |
self.load_frames(data["frames"]) | |
shutil.rmtree(self.cache_dir) | |
def load_frames(self, frames): | |
self.frames = [Frame.load_dict(frame) for frame in frames] | |
for frame in self.frames: | |
frame.svg = SVG.load_svg(os.path.join(self.base_dir, f"{frame.index}.svg")) | |
def save_project(self): | |
with open(self.filename, "w") as f: | |
data = { | |
"name": self.name, | |
"uid": self.uid, | |
"frames": [frame.to_dict() for frame in self.frames] | |
} | |
json.dump(data, f) | |
self.save_frames() | |
def save_frames(self): | |
for frame in self.frames: | |
frame.svg.save_svg(os.path.join(self.base_dir, f"{frame.index}.svg")) | |
def export_to_gif(self, frame_duration=0.1, loop_mode=0): | |
from .state import LoopMode | |
imgs = [frame.svg.copy().normalize().draw(do_display=False, return_png=True) for frame in self.frames] | |
if loop_mode == LoopMode.REVERSE: | |
imgs = imgs[::-1] | |
elif loop_mode == LoopMode.PINGPONG: | |
imgs = imgs + imgs[::-1] | |
clips = [ImageClip(np.array(img)).set_duration(frame_duration) for img in imgs] | |
clip = concatenate_videoclips(clips, method="compose", bg_color=(255, 255, 255)) | |
file_path = os.path.join(ROOT_DIR, f"{self.uid}.gif") | |
clip.write_gif(file_path, fps=24, verbose=False, logger=None) | |