3 from ..
import NVector, Color
4 from ..utils.color
import from_uint8
19 i = self.
verticesvertices.index(NVector(x, y))
20 if len(self.
verticesvertices) > i
and self.
verticesvertices[i+1] == NVector(x, y+1):
22 self.
verticesvertices.insert(i+1, NVector(x+1, y))
23 self.
verticesvertices.insert(i+2, NVector(x+1, y+1))
28 i = self.
verticesvertices.index(NVector(x+1, y))
29 if i > 0
and self.
verticesvertices[i-1] == NVector(x+1, y+1):
31 self.
verticesvertices.insert(i, NVector(x, y))
32 self.
verticesvertices.insert(i, NVector(x, y+1))
37 i = self.
verticesvertices.index(NVector(x, y))
38 if i > 0
and self.
verticesvertices[i-1] == NVector(x+1, y):
40 if i > 1
and self.
verticesvertices[i-2] == NVector(x+1, y+1):
41 self.
verticesvertices[i-1] = NVector(x, y+1)
43 self.
verticesvertices.insert(i, NVector(x, y+1))
44 self.
verticesvertices.insert(i, NVector(x+1, y+1))
48 def _to_rect(self, id1, id2, scale):
49 p1 = self.
verticesvertices[id1] * scale
50 p2 = self.
verticesvertices[id2] * scale
60 if len(bez.vertices) > 1
and (
61 bez.vertices[-1].x == bez.vertices[-2].x == point.x
or
62 bez.vertices[-1].y == bez.vertices[-2].y == point.y
64 bez.vertices[-1] = point
68 if len(bez.vertices) > 2
and bez.vertices[0].x == bez.vertices[-1].x == bez.vertices[-2].x:
70 bez.out_tangents.pop()
79 xneg_candidates = set()
80 if stroke_width
is None:
81 stroke_width = 0.1 * scale
86 x < 0
or x >= raster.width
or y >= raster.height
or
87 rid
in processed
or raster.getpixel(rid) != colort
90 def recurse(gen, x, y, xneg):
93 gen.add_pixel_x(x+1, y)
94 recurse(gen, x+1, y,
False)
96 gen.add_pixel_y(x, y+1)
97 recurse(gen, x, y+1,
True)
98 if xneg
and avail(x-1, y):
99 xneg_candidates.add((x-1, y))
101 for y
in range(raster.height):
102 for x
in range(raster.width):
104 colort = raster.getpixel(pid)
105 if colort[-1] == 0
or pid
in processed:
109 xneg_candidates = set()
110 recurse(gen, x, y,
False)
111 xneg_candidates -= processed
112 while xneg_candidates:
113 p = next(iter(sorted(xneg_candidates, key=
lambda t: (t[1], t[0]))))
114 gen.add_pixel_x_neg(*p)
115 recurse(gen, p[0], p[1],
True)
117 xneg_candidates -= processed
119 g = groups.setdefault(colort, set())
120 g.add(gen.to_shape(scale))
135 for colort, rects
in groups.items():
137 g.shapes = list(rects) + g.shapes
138 g.name =
"".join(
"%02x" % c
for c
in colort)
140 opacity = colort[-1] / 255 * 100
142 fill.color.value = color
143 fill.opacity.value = opacity
146 stroke.opacity.value = opacity
161 if last_rect
and last_rect._start
in last_rects:
162 yrect = last_rects[last_rect._start]
163 if yrect.size.value.x == last_rect.size.value.x
and yrect._color == last_rect._color:
164 groups[last_rect._color].remove(last_rect)
165 yrect.position.value.y += 0.5
166 yrect.size.value.y += 1
167 rects[last_rect._start] = yrect
170 return groups.setdefault(colort, set())
172 for y
in range(raster.height):
176 for x
in range(raster.width):
177 colort = raster.getpixel((x, y))
181 yrect = last_rects.get(x,
None)
182 if colort == last_color:
183 last_rect.position.value.x += 0.5
184 last_rect.size.value.x += 1
185 elif yrect
and colort == yrect._color
and yrect.size.value.x == 1:
186 yrect.position.value.y += 0.5
187 yrect.size.value.y += 1
189 last_color = last_rect = colort =
None
195 last_rect.size.value = NVector(1, 1)
196 last_rect.position.value = NVector(x + 0.5, y + 0.5)
199 last_rect._color = colort
204 for colort, rects
in groups.items():
206 g.shapes = list(rects) + g.shapes
207 g.name =
"".join(
"%02x" % c
for c
in colort)
210 fill.opacity.value = colort[-1] / 255 * 100
212 stroke.opacity.value = fill.opacity.value
216 def _vectorizing_func(filenames, frame_delay, framerate, callback):
217 if not isinstance(filenames, list):
218 filenames = [filenames]
224 for filename
in filenames:
225 if isinstance(filename, Image.Image):
228 raster = Image.open(filename)
231 animation.width = raster.width
232 animation.height = raster.height
234 if not hasattr(raster,
"is_animated"):
236 raster.seek =
lambda x:
None
238 for frame
in range(raster.n_frames):
240 new_im = Image.new(
"RGBA", raster.size)
242 duration = frame_delay
243 image_duration = raster.info.get(
"duration", 0)
245 duration = framerate * image_duration / 1000
246 callback(animation, new_im, nframes + frame, time, duration)
249 nframes += raster.n_frames
251 animation.out_point = time
257 @brief Loads external assets
259 def callback(animation, raster, frame, time, duration):
260 asset = objects.assets.Image.embedded(raster, embed_format)
261 animation.assets.append(asset)
263 layer.in_point = time
264 layer.out_point = layer.in_point + duration
266 return _vectorizing_func(filenames, frame_delay, framerate, callback)
271 @brief Loads external assets
275 for frame, filename
in enumerate(filenames):
276 asset = objects.assets.Image.linked(filename)
277 animation.assets.append(asset)
279 layer.in_point = frame * frame_delay
280 layer.out_point = layer.in_point + frame_delay
287 @brief Converts pixel art to vector
289 def callback(animation, raster, frame, time, duration):
291 layer.in_point = time
292 layer.out_point = layer.in_point + duration
294 return _vectorizing_func(filenames, frame_delay, framerate, callback)
299 @brief Converts pixel art to vector paths
301 Slower and yields larger files compared to pixel_to_animation,
302 but it produces a single shape for each area with the same color.
303 Mostly useful when you want to add your own animations to the loaded image
305 def callback(animation, raster, frame, time, duration):
307 layer.in_point = time
308 layer.out_point = layer.in_point + duration
310 return _vectorizing_func(filenames, frame_delay, framerate, callback)
Top level object, describing the animation.
Layer containing ShapeElement objects.
ShapeElement that can contain other shapes.
A simple rectangle shape.
def _to_rect(self, id1, id2, scale)
def add_pixel_x(self, x, y)
def add_pixel_y(self, x, y)
def to_shape(self, scale)
def add_pixel_x_neg(self, x, y)
def pixel_to_animation_paths(filenames, frame_delay=1, framerate=60)
Converts pixel art to vector paths.
def pixel_to_animation(filenames, frame_delay=1, framerate=60)
Converts pixel art to vector.
def pixel_add_layer_rects(animation, raster)
def raster_to_linked_assets(filenames, frame_delay=1, framerate=60)
Loads external assets.
def pixel_to_layer_paths(raster, scale=1, stroke_width=None)
def raster_to_embedded_assets(filenames, frame_delay=1, framerate=60, embed_format=None)
Loads external assets.
def pixel_add_layer_paths(animation, raster)
def from_uint8(r, g, b, a=255)