File indexing completed on 2025-01-19 03:59:55

0001 from .. import objects
0002 
0003 
0004 class RestructuredLayer:
0005     def __init__(self, lottie):
0006         self.lottie = lottie
0007         self.children_pre = []
0008         self.children_post = []
0009         self.structured = False
0010         self.shapegroup = None
0011         self.matte_target = False
0012         self.matte_source = None
0013         self.matte_id = None
0014 
0015     def add(self, child):
0016         c = self.children_pre if self.structured else self.children_post
0017         c.insert(0, child)
0018 
0019 
0020 class RestructuredShapeGroup:
0021     def __init__(self, lottie):
0022         self.lottie = lottie
0023         self.children = []
0024         self.fill = None
0025         self.stroke = None
0026         self.layer = False
0027         self.paths = None
0028         self.stroke_above = False
0029 
0030     def empty(self):
0031         return not self.children
0032 
0033     def finalize(self, thresh=6):
0034         for g in self.subgroups:
0035             if g.layer:
0036                 self.layer = True
0037                 for gg in self.subgroups:
0038                     gg.layer = True
0039                 return
0040         nchild = len(self.children)
0041         self.layer = nchild > thresh and self.lottie.name
0042 
0043     @property
0044     def subgroups(self):
0045         for g in self.children:
0046             if isinstance(g, RestructuredShapeGroup):
0047                 yield g
0048 
0049     def add(self, child):
0050         self.children.insert(0, child)
0051 
0052 
0053 class RestructuredModifier:
0054     def __init__(self, lottie, child):
0055         self.child = child
0056         self.lottie = lottie
0057 
0058 
0059 class RestructuredPathMerger:
0060     def __init__(self):
0061         self.paths = []
0062 
0063     def append(self, path):
0064         self.paths.append(path)
0065 
0066 
0067 class RestructuredAnimation:
0068     def __init__(self):
0069         self.layers = []
0070         self.precomp = {}
0071 
0072 
0073 class AbstractBuilder:
0074     merge_paths = False
0075 
0076     def _on_animation(self, animation):
0077         raise NotImplementedError()
0078 
0079     def _on_shapegroup(self, shapegroup, out_parent):
0080         raise NotImplementedError()
0081 
0082     def _on_shape(self, shape, shapegroup, out_parent):
0083         raise NotImplementedError()
0084 
0085     def _on_merged_path(self, shape, shapegroup, out_parent):
0086         raise NotImplementedError()
0087 
0088     def _on_shape_modifier(self, shape, shapegroup, out_parent):
0089         raise NotImplementedError()
0090 
0091     def process(self, animation: objects.Animation):
0092         out_parent = self._on_animation(animation)
0093 
0094         restructured = self.restructure_animation(animation, self.merge_paths)
0095         for id, layers in restructured.precomp.items():
0096             self._on_precomp(id, out_parent, layers)
0097 
0098         for asset in animation.assets or []:
0099             self._on_asset(asset)
0100 
0101         for layer_builder in restructured.layers:
0102             self.process_layer(layer_builder, out_parent)
0103 
0104     def _on_layer(self, layer_builder, out_parent):
0105         raise NotImplementedError()
0106 
0107     def _on_precomp(self, id, out_parent, layers):
0108         raise NotImplementedError()
0109 
0110     def _on_asset(self, asset):
0111         pass
0112 
0113     def process_layer(self, layer_builder, out_parent):
0114         out_layer = self._on_layer(layer_builder, out_parent)
0115 
0116         if out_layer is None:
0117             return
0118 
0119         for c in layer_builder.children_pre:
0120             self.process_layer(c, out_layer)
0121 
0122         shapegroup = getattr(layer_builder, "shapegroup", None)
0123         if shapegroup:
0124             self.shapegroup_process_children(shapegroup, out_layer)
0125 
0126         for c in layer_builder.children_post:
0127             self.process_layer(c, out_layer)
0128 
0129         self._on_layer_end(out_layer)
0130 
0131     def _on_layer_end(self, out_layer):
0132         pass
0133 
0134     def shapegroup_process_child(self, shape, shapegroup, out_parent):
0135         if isinstance(shape, RestructuredShapeGroup):
0136             return self._on_shapegroup(shape, out_parent)
0137         elif isinstance(shape, RestructuredPathMerger):
0138             return self._on_merged_path(shape, shapegroup, out_parent)
0139         elif isinstance(shape, RestructuredModifier):
0140             return self._on_shape_modifier(shape, shapegroup, out_parent)
0141         else:
0142             return self._on_shape(shape, shapegroup, out_parent)
0143 
0144     def shapegroup_process_children(self, shapegroup, out_parent):
0145         for shape in shapegroup.children:
0146             self.shapegroup_process_child(shape, shapegroup, out_parent)
0147 
0148     def restructure_animation(self, animation, merge_paths):
0149         restr = RestructuredAnimation()
0150         restr.layers = self.restructure_layer_list(animation.layers, merge_paths)
0151         if animation.assets:
0152             for asset in animation.assets:
0153                 if isinstance(asset, objects.Precomp):
0154                     restr.precomp[asset.id] = self.restructure_layer_list(asset.layers, merge_paths)
0155         return restr
0156 
0157     def restructure_layer_list(self, layer_list, merge_paths):
0158         layers = {}
0159         flat_layers = []
0160         prev = None
0161         for layer in layer_list:
0162             laybuilder = RestructuredLayer(layer)
0163             flat_layers.append(laybuilder)
0164 
0165             if layer.index is not None:
0166                 layers[layer.index] = laybuilder
0167 
0168             if isinstance(layer, objects.ShapeLayer):
0169                 laybuilder.shapegroup = RestructuredShapeGroup(layer)
0170                 laybuilder.layer = True
0171                 for shape in layer.shapes:
0172                     self.restructure_shapegroup(shape, laybuilder.shapegroup, merge_paths)
0173                 laybuilder.shapegroup.finalize()
0174 
0175             if layer.matte_mode not in {None, objects.MatteMode.Normal}:
0176                 laybuilder.matte_source = prev
0177                 if prev:
0178                     prev.matte_target = laybuilder
0179 
0180             prev = laybuilder
0181 
0182         top_layers = []
0183         for layer in flat_layers:
0184             layer.structured = True
0185             if layer.lottie.parent_index is not None:
0186                 layers[layer.lottie.parent_index].add(layer)
0187             else:
0188                 top_layers.insert(0, layer)
0189 
0190         return top_layers
0191 
0192     def restructure_shapegroup(self, shape, shape_group, merge_paths):
0193         if isinstance(shape, (objects.Fill, objects.GradientFill)):
0194             if not shape_group.fill:
0195                 shape_group.fill = shape
0196         elif isinstance(shape, objects.BaseStroke):
0197             if not shape_group.stroke or shape_group.stroke.width.get_value(0) < shape.width.get_value(0):
0198                 shape_group.stroke = shape
0199                 if not shape_group.fill:
0200                     shape_group.stroke_above = True
0201         elif isinstance(shape, (objects.Path)):
0202             if merge_paths:
0203                 if not shape_group.paths:
0204                     shape_group.paths = RestructuredPathMerger()
0205                     shape_group.add(shape_group.paths)
0206                 shape_group.paths.append(shape)
0207             else:
0208                 shape_group.add(shape)
0209         elif isinstance(shape, (objects.Group)):
0210             subgroup = RestructuredShapeGroup(shape)
0211             shape_group.add(subgroup)
0212             merge_paths = self.merge_paths and not any(isinstance(p, objects.Group) for p in shape.shapes)
0213             for subshape in shape.shapes:
0214                 self.restructure_shapegroup(subshape, subgroup, merge_paths)
0215             subgroup.finalize()
0216         elif isinstance(shape, (objects.Modifier)):
0217             if shape_group.children:
0218                 ch = shape_group.children.pop(0)
0219                 shape_group.add(RestructuredModifier(shape, ch))
0220         elif isinstance(shape, (objects.ShapeElement)):
0221             shape_group.add(shape)
0222         elif isinstance(shape, (objects.base.CustomObject)):
0223             if self._custom_object_supported(shape):
0224                 shape_group.add(shape)
0225             else:
0226                 self.restructure_shapegroup(shape.wrapped, shape_group, self.merge_paths)
0227 
0228     def _custom_object_supported(self, shape):
0229         return False