File size: 3,010 Bytes
c1ce505
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
        }

    @staticmethod
    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)]

    @property
    def filename(self):
        return os.path.join(ROOT_DIR, f"{self.uid}.json")

    @property
    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

    @property
    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)