mirror of
https://github.com/OpenVGLab/OmniLottie.git
synced 2026-09-17 15:46:26 +00:00
121 lines
4.1 KiB
Python
121 lines
4.1 KiB
Python
from xml.dom import minidom
|
|
import enum
|
|
from lottie.parsers.sif.sif.core import TypeDescriptor, ObjectRegistry, SifNodeMeta, FrameTime
|
|
from lottie.parsers.sif.xml.utils import xml_child_elements, xml_first_element_child
|
|
|
|
|
|
class SifAstNode:
|
|
_subclasses = None
|
|
_tag = None
|
|
|
|
@staticmethod
|
|
def from_dom(xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
|
if xml.tagName == param.typename:
|
|
return SifValue.from_dom(xml, param, registry)
|
|
|
|
xmltype = xml.getAttribute("type")
|
|
if xmltype != param.typename and xmltype != "weighted_" + param.typename:
|
|
raise ValueError("Invalid type %s (should be %s)" % (xmltype, param.typename))
|
|
|
|
return SifAstNode.ast_node_types()[xml.tagName].from_dom(xml, param, registry)
|
|
|
|
@staticmethod
|
|
def ast_node_types():
|
|
if SifAstNode._subclasses is None:
|
|
from . import nodes
|
|
SifAstNode._subclasses = {}
|
|
SifAstNode._gather_ast_types(SifAstNode)
|
|
return SifAstNode._subclasses
|
|
|
|
@staticmethod
|
|
def _gather_ast_types(cls):
|
|
for subcls in cls.__subclasses__():
|
|
if subcls._tag:
|
|
SifAstNode._subclasses[subcls._tag] = subcls
|
|
SifAstNode._gather_ast_types(subcls)
|
|
|
|
def _prepare_to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
|
element = dom.createElement(self._tag)
|
|
element.setAttribute("type", param.typename)
|
|
return element
|
|
|
|
|
|
class SifValue(SifAstNode):
|
|
def __init__(self, value=None):
|
|
self.value = value
|
|
|
|
def __repr__(self):
|
|
return "<%s %r>" % (self.__class__.__name__, self.value)
|
|
|
|
@classmethod
|
|
def from_dom(cls, xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
|
return SifValue(param.value_from_xml_element(xml, registry))
|
|
|
|
def to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
|
return param.value_to_xml_element(self.value, dom)
|
|
|
|
|
|
class Interpolation(enum.Enum):
|
|
Auto = "auto"
|
|
Linear = "linear"
|
|
Clamped = "clamped"
|
|
Ease = "halt"
|
|
Constant = "constant"
|
|
|
|
|
|
class SifKeyframe:
|
|
def __init__(self, value, time: FrameTime, before=Interpolation.Clamped, after=Interpolation.Clamped):
|
|
self.value = value
|
|
self.time = time
|
|
self.before = before
|
|
self.after = after
|
|
|
|
@classmethod
|
|
def from_dom(cls, xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
|
return cls(
|
|
param.value_from_xml_element(xml_first_element_child(xml), registry),
|
|
FrameTime.parse_string(xml.getAttribute("time"), registry),
|
|
Interpolation(xml.getAttribute("before")),
|
|
Interpolation(xml.getAttribute("after"))
|
|
)
|
|
|
|
def to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
|
element = dom.createElement("waypoint")
|
|
element.setAttribute("time", str(self.time))
|
|
element.setAttribute("before", self.before.value)
|
|
element.setAttribute("after", self.after.value)
|
|
element.appendChild(param.value_to_xml_element(self.value, dom))
|
|
return element
|
|
|
|
def __repr__(self):
|
|
return "<SifKeyframe %s %s>" % (self.time, self.value)
|
|
|
|
|
|
class SifAnimated(SifAstNode):
|
|
_tag = "animated"
|
|
|
|
def __init__(self):
|
|
self.keyframes = []
|
|
|
|
@classmethod
|
|
def from_dom(cls, xml: minidom.Element, param: TypeDescriptor, registry: ObjectRegistry):
|
|
obj = SifAnimated()
|
|
for waypoint in xml_child_elements(xml, "waypoint"):
|
|
obj.keyframes.append(SifKeyframe.from_dom(waypoint, param, registry))
|
|
return obj
|
|
|
|
def to_dom(self, dom: minidom.Document, param: TypeDescriptor):
|
|
element = self._prepare_to_dom(dom, param)
|
|
for kf in self.keyframes:
|
|
element.appendChild(kf.to_dom(dom, param))
|
|
return element
|
|
|
|
def add_keyframe(self, *args, **kwargs):
|
|
if not kwargs and len(args) == 1 and isinstance(args[0], SifKeyframe):
|
|
keyframe = args[0]
|
|
else:
|
|
keyframe = SifKeyframe(*args, **kwargs)
|
|
|
|
self.keyframes.append(keyframe)
|
|
return keyframe
|