Files

295 lines
8.0 KiB
Python
Raw Permalink Normal View History

2026-03-01 21:36:54 +08:00
import warnings
from .base import LottieObject, LottieProp, PseudoBool, LottieEnum
from .effects import Effect
from .helpers import Transform, Mask
from .shapes import ShapeElement
from .text import TextAnimatorData
from .properties import Value
## @ingroup Lottie
class BlendMode(LottieEnum):
Normal = 0
Multiply = 1
Screen = 2
Overlay = 3
Darken = 4
Lighten = 5
ColorDodge = 6
ColorBurn = 7
HardLight = 8
SoftLight = 9
Difference = 10
Exclusion = 11
Hue = 12
Saturation = 13
Color = 14
Luminosity = 15
## @ingroup Lottie
## @todo SVG masks
class MatteMode(LottieEnum):
Normal = 0
Alpha = 1
InvertedAlpha = 2
Luma = 3
InvertedLuma = 4
## @ingroup Lottie
class Layer(LottieObject):
_props = [
LottieProp("threedimensional", "ddd", PseudoBool, False),
LottieProp("hidden", "hd", bool, False),
LottieProp("type", "ty", int, False),
LottieProp("name", "nm", str, False),
LottieProp("parent_index", "parent", int, False),
LottieProp("stretch", "sr", float, False),
LottieProp("transform", "ks", Transform, False),
LottieProp("auto_orient", "ao", PseudoBool, False),
LottieProp("in_point", "ip", float, False),
LottieProp("out_point", "op", float, False),
LottieProp("start_time", "st", float, False),
LottieProp("blend_mode", "bm", BlendMode, False),
LottieProp("matte_mode", "tt", MatteMode, False),
LottieProp("index", "ind", int, False),
#LottieProp("css_class", "cl", str, False),
LottieProp("layer_html_id", "ln", str, False),
LottieProp("has_masks", "hasMask", bool, False),
LottieProp("masks", "masksProperties", Mask, True),
LottieProp("effects", "ef", Effect, True),
LottieProp("matte_target", "td", int, False),
]
## %Layer type.
## @see https://github.com/bodymovin/bodymovin-extension/blob/master/bundle/jsx/enums/layerTypes.jsx
type = None
_classses = {}
@property
def has_masks(self):
"""!
Whether the layer has some masks applied
"""
return bool(self.masks) if getattr(self, "masks") is not None else None
def __init__(self):
## Transform properties
self.transform = Transform()
## Auto-Orient along path AE property.
self.auto_orient = False
## 3d layer flag
self.threedimensional = False
## Hidden layer
self.hidden = None
## Layer index in AE. Used for parenting and expressions.
self.index = None
"""
# Parsed layer name used as html class on SVG/HTML renderer
#self.css_class = ""
# Parsed layer name used as html id on SVG/HTML renderer
#self.layer_html_id = ""
"""
## In Point of layer. Sets the initial frame of the layer.
self.in_point = None
## Out Point of layer. Sets the final frame of the layer.
self.out_point = None
## Start Time of layer. Sets the start time of the layer.
self.start_time = 0
## After Effects Layer Name. Used for expressions.
self.name = None
## List of Effects
self.effects = None
## Layer Time Stretching
self.stretch = 1
## Layer Parent. Uses ind of parent.
self.parent_index = None
## List of Masks
self.masks = None
## Blend Mode
self.blend_mode = BlendMode.Normal
## Matte mode, the layer will inherit the transparency from the layer above
self.matte_mode = None
self.matte_target = None
## Composition owning the layer, set by add_layer
self.composition = None
def add_child(self, layer):
if not self.composition or self.index is None:
raise Exception("Must set composition / index first")
self._child_inout_auto(layer)
self.composition.add_layer(layer)
layer.parent_index = self.index
return layer
def _child_inout_auto(self, layer):
if layer.in_point is None:
layer.in_point = self.in_point
if layer.out_point is None:
layer.out_point = self.out_point
@property
def parent(self):
if self.parent_index is None:
return None
return self.composition.layer(self.parent_index)
@parent.setter
def parent(self, layer):
if layer is None:
self.parent_index = None
else:
self.parent_index = layer.index
layer._child_inout_auto(self)
@property
def children(self):
for layer in self.composition.layers:
if layer.parent_index == self.index:
yield layer
@classmethod
def _load_get_class(cls, lottiedict):
if not Layer._classses:
Layer._classses = {
sc.type: sc
for sc in Layer.__subclasses__()
}
type_id = lottiedict["ty"]
if type_id not in Layer._classses:
warnings.warn("Unknown layer type: %s" % type_id)
return Layer
return Layer._classses[type_id]
def __repr__(self):
return "<%s %s %s>" % (type(self).__name__, self.index, self.name)
def __str__(self):
return "%s %s" % (
self.name or super().__str__(),
self.index if self.index is not None else ""
)
def remove(self):
"""!
@brief Removes this layer from the componsitin
"""
self.composition.remove_layer(self)
## @ingroup Lottie
class NullLayer(Layer):
"""!
Layer with no data, useful to group layers together
"""
## %Layer type.
type = 3
def __init__(self):
Layer.__init__(self)
## @ingroup Lottie
class TextLayer(Layer):
_props = [
LottieProp("data", "t", TextAnimatorData, False),
]
## %Layer type.
type = 5
def __init__(self):
Layer.__init__(self)
## Text Data
self.data = TextAnimatorData()
## @ingroup Lottie
class ShapeLayer(Layer):
"""!
Layer containing ShapeElement objects
"""
_props = [
LottieProp("shapes", "shapes", ShapeElement, True),
]
## %Layer type.
type = 4
def __init__(self):
Layer.__init__(self)
## Shape list of items
self.shapes = [] # ShapeElement
def add_shape(self, shape):
self.shapes.append(shape)
return shape
def insert_shape(self, index, shape):
self.shapes.insert(index, shape)
return shape
## @ingroup Lottie
## @todo SIF I/O
class ImageLayer(Layer):
_props = [
LottieProp("image_id", "refId", str, False),
]
## %Layer type.
type = 2
def __init__(self, image_id=""):
Layer.__init__(self)
## id pointing to the source image defined on 'assets' object
self.image_id = image_id
## @ingroup Lottie
class PreCompLayer(Layer):
_props = [
LottieProp("reference_id", "refId", str, False),
LottieProp("time_remapping", "tm", Value, False),
LottieProp("width", "w", int, False),
LottieProp("height", "h", int, False),
]
## %Layer type.
type = 0
def __init__(self, reference_id=""):
Layer.__init__(self)
## id pointing to the source composition defined on 'assets' object
self.reference_id = reference_id
## Comp's Time remapping
self.time_remapping = None
## Width
self.width = 512
## Height
self.height = 512
## @ingroup Lottie
class SolidColorLayer(Layer):
"""!
Layer with a solid color rectangle
"""
_props = [
LottieProp("color", "sc", str, False),
LottieProp("height", "sh", float, False),
LottieProp("width", "sw", float, False),
]
## %Layer type.
type = 1
def __init__(self, color="", width=512, height=512):
Layer.__init__(self)
## Color of the layer as a @c \#rrggbb hex
# @todo Convert NVector to string
self.color = color
## Height of the layer.
self.height = height
## Width of the layer.
self.width = width