Spaces:
Paused
Paused
| 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) | |