python-lottie  0.6.11+deva0e77a1
A framework to work with lottie files and telegram animated stickers (tgs)
restructure.py
Go to the documentation of this file.
1 from .. import objects
2 
3 
5  def __init__(self, lottie):
6  self.lottielottie = lottie
7  self.children_prechildren_pre = []
8  self.children_postchildren_post = []
9  self.structuredstructured = False
10  self.shapegroupshapegroup = None
11  self.matte_targetmatte_target = False
12  self.matte_sourcematte_source = None
13  self.matte_idmatte_id = None
14 
15  def add(self, child):
16  c = self.children_prechildren_pre if self.structuredstructured else self.children_postchildren_post
17  c.insert(0, child)
18 
19 
21  def __init__(self, lottie):
22  self.lottielottie = lottie
23  self.childrenchildren = []
24  self.fillfill = None
25  self.strokestroke = None
26  self.layerlayer = False
27  self.pathspaths = None
28  self.stroke_abovestroke_above = False
29 
30  def empty(self):
31  return not self.childrenchildren
32 
33  def finalize(self, thresh=6):
34  for g in self.subgroupssubgroups:
35  if g.layer:
36  self.layerlayer = True
37  for gg in self.subgroupssubgroups:
38  gg.layer = True
39  return
40  nchild = len(self.childrenchildren)
41  self.layerlayer = nchild > thresh and self.lottielottie.name
42 
43  @property
44  def subgroups(self):
45  for g in self.childrenchildren:
46  if isinstance(g, RestructuredShapeGroup):
47  yield g
48 
49  def add(self, child):
50  self.childrenchildren.insert(0, child)
51 
52 
54  def __init__(self, lottie, child):
55  self.childchild = child
56  self.lottielottie = lottie
57 
58 
60  def __init__(self):
61  self.pathspaths = []
62 
63  def append(self, path):
64  self.pathspaths.append(path)
65 
66 
68  def __init__(self):
69  self.layerslayers = []
70  self.precompprecomp = {}
71 
72 
74  merge_paths = False
75 
76  def _on_animation(self, animation):
77  raise NotImplementedError()
78 
79  def _on_shapegroup(self, shapegroup, out_parent):
80  raise NotImplementedError()
81 
82  def _on_shape(self, shape, shapegroup, out_parent):
83  raise NotImplementedError()
84 
85  def _on_merged_path(self, shape, shapegroup, out_parent):
86  raise NotImplementedError()
87 
88  def _on_shape_modifier(self, shape, shapegroup, out_parent):
89  raise NotImplementedError()
90 
91  def process(self, animation: objects.Animation):
92  out_parent = self._on_animation_on_animation(animation)
93 
94  restructured = self.restructure_animationrestructure_animation(animation, self.merge_pathsmerge_paths)
95  for id, layers in restructured.precomp.items():
96  self._on_precomp_on_precomp(id, out_parent, layers)
97 
98  for asset in animation.assets or []:
99  self._on_asset_on_asset(asset)
100 
101  if animation.fonts and animation.fonts.list:
102  for font in animation.fonts.list:
103  self._on_font_on_font(font)
104 
105  for layer_builder in restructured.layers:
106  self.process_layerprocess_layer(layer_builder, out_parent)
107 
108  def _on_layer(self, layer_builder, out_parent):
109  raise NotImplementedError()
110 
111  def _on_precomp(self, id, out_parent, layers):
112  raise NotImplementedError()
113 
114  def _on_asset(self, asset):
115  pass
116 
117  def _on_font(self, font):
118  pass
119 
120  def process_layer(self, layer_builder, out_parent):
121  out_layer = self._on_layer(layer_builder, out_parent)
122 
123  if out_layer is None:
124  return
125 
126  for c in layer_builder.children_pre:
127  self.process_layer(c, out_layer)
128 
129  shapegroup = getattr(layer_builder, "shapegroup", None)
130  if shapegroup:
131  self.shapegroup_process_children(shapegroup, out_layer)
132 
133  for c in layer_builder.children_post:
134  self.process_layer(c, out_layer)
135 
136  self._on_layer_end(out_layer)
137 
138  def _on_layer_end(self, out_layer):
139  pass
140 
141  def shapegroup_process_child(self, shape, shapegroup, out_parent):
142  if isinstance(shape, RestructuredShapeGroup):
143  return self._on_shapegroup(shape, out_parent)
144  elif isinstance(shape, RestructuredPathMerger):
145  return self._on_merged_path(shape, shapegroup, out_parent)
146  elif isinstance(shape, RestructuredModifier):
147  return self._on_shape_modifier(shape, shapegroup, out_parent)
148  else:
149  return self._on_shape(shape, shapegroup, out_parent)
150 
151  def shapegroup_process_children(self, shapegroup, out_parent):
152  for shape in shapegroup.children:
153  self.shapegroup_process_childshapegroup_process_child(shape, shapegroup, out_parent)
154 
155  def restructure_animation(self, animation, merge_paths):
156  restr = RestructuredAnimation()
157  restr.layers = self.restructure_layer_listrestructure_layer_list(animation.layers, merge_paths)
158  if animation.assets:
159  for asset in animation.assets:
160  if isinstance(asset, objects.Precomp):
161  restr.precomp[asset.id] = self.restructure_layer_listrestructure_layer_list(asset.layers, merge_paths)
162  return restr
163 
164  def restructure_layer_list(self, layer_list, merge_paths):
165  layers = {}
166  flat_layers = []
167  prev = None
168  for layer in layer_list:
169  laybuilder = RestructuredLayer(layer)
170  flat_layers.append(laybuilder)
171 
172  if layer.index is not None:
173  layers[layer.index] = laybuilder
174 
175  if isinstance(layer, objects.ShapeLayer):
176  laybuilder.shapegroup = RestructuredShapeGroup(layer)
177  laybuilder.layer = True
178  for shape in layer.shapes:
179  self.restructure_shapegrouprestructure_shapegroup(shape, laybuilder.shapegroup, merge_paths)
180  laybuilder.shapegroup.finalize()
181 
182  if layer.matte_mode not in {None, objects.MatteMode.Normal}:
183  laybuilder.matte_source = prev
184  if prev:
185  prev.matte_target = laybuilder
186 
187  prev = laybuilder
188 
189  top_layers = []
190  for layer in flat_layers:
191  layer.structured = True
192  if layer.lottie.parent_index is not None:
193  layers[layer.lottie.parent_index].add(layer)
194  else:
195  top_layers.insert(0, layer)
196 
197  return top_layers
198 
199  def restructure_shapegroup(self, shape, shape_group, merge_paths):
200  if isinstance(shape, (objects.Fill, objects.GradientFill)):
201  if not shape_group.fill:
202  shape_group.fill = shape
203  elif isinstance(shape, objects.BaseStroke):
204  if not shape_group.stroke or shape_group.stroke.width.get_value(0) < shape.width.get_value(0):
205  shape_group.stroke = shape
206  if not shape_group.fill:
207  shape_group.stroke_above = True
208  elif isinstance(shape, (objects.Path)):
209  if merge_paths:
210  if not shape_group.paths:
211  shape_group.paths = RestructuredPathMerger()
212  shape_group.add(shape_group.paths)
213  shape_group.paths.append(shape)
214  else:
215  shape_group.add(shape)
216  elif isinstance(shape, (objects.Group)):
217  subgroup = RestructuredShapeGroup(shape)
218  shape_group.add(subgroup)
219  merge_paths = self.merge_pathsmerge_paths and not any(isinstance(p, objects.Group) for p in shape.shapes)
220  for subshape in shape.shapes:
221  self.restructure_shapegrouprestructure_shapegroup(subshape, subgroup, merge_paths)
222  subgroup.finalize()
223  elif isinstance(shape, (objects.Modifier)):
224  if shape_group.children:
225  ch = shape_group.children.pop(0)
226  shape_group.add(RestructuredModifier(shape, ch))
227  elif isinstance(shape, (objects.ShapeElement)):
228  shape_group.add(shape)
229  elif isinstance(shape, (objects.base.CustomObject)):
230  if self._custom_object_supported_custom_object_supported(shape):
231  shape_group.add(shape)
232  else:
233  self.restructure_shapegrouprestructure_shapegroup(shape.wrapped, shape_group, self.merge_pathsmerge_paths)
234 
235  def _custom_object_supported(self, shape):
236  return False
Allows extending the Lottie shapes with custom Python classes.
Definition: base.py:327
Layer containing ShapeElement objects.
Definition: layers.py:193
Solid fill color.
Definition: shapes.py:509
ShapeElement that can contain other shapes.
Definition: shapes.py:433
Animatable Bezier curve.
Definition: shapes.py:399
Base class for all elements of ShapeLayer and Group.
Definition: shapes.py:72
def restructure_animation(self, animation, merge_paths)
Definition: restructure.py:155
def shapegroup_process_child(self, shape, shapegroup, out_parent)
Definition: restructure.py:141
def restructure_layer_list(self, layer_list, merge_paths)
Definition: restructure.py:164
def process_layer(self, layer_builder, out_parent)
Definition: restructure.py:120
def _on_precomp(self, id, out_parent, layers)
Definition: restructure.py:111
def restructure_shapegroup(self, shape, shape_group, merge_paths)
Definition: restructure.py:199
def process(self, objects.Animation animation)
Definition: restructure.py:91
def shapegroup_process_children(self, shapegroup, out_parent)
Definition: restructure.py:151