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