Files
OmniLottie/lottie/objects/layers.py
T
2026-03-01 21:36:54 +08:00

295 lines
8.0 KiB
Python

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