Check-in [abf02b681a]
Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | prepend existing transform for animotion |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
abf02b681acdfa8864ae559551067262 |
User & Date: | mario 2022-10-02 06:24:42 |
Context
2022-10-02
| ||
19:18 | add basic time mapping check-in: 52564363ae user: mario tags: trunk | |
06:24 | prepend existing transform for animotion check-in: abf02b681a user: mario tags: trunk | |
06:23 | add remove_child option, shorten notebook page options check-in: 157fc9695e user: mario tags: trunk | |
Changes
Changes to inkscape/export_gif.py.
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/env python # encoding: utf-8 # api: inkscape ##type: effect # category: export # title: GIF slideshow # description: Export and combine layers as animation using ImageMagick # id: org.include-once.inkscape.export-gif # license: MITL # version: 0.9 # state: beta | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/bin/env python # encoding: utf-8 # api: inkscape ##type: effect # category: export # title: GIF slideshow # description: Export and combine layers as animation using ImageMagick # id: org.include-once.inkscape.export-gif # license: MITL # version: 0.9 # state: beta # depends: bin:inkscape (>= 1.1), bin:convert, python (>= 3.6), python:svgelements # pylint: disable=line-too-long, missing-module-docstring, bad-whitespace # config: # { name: file, type: file, mode: file, value: "~/anim.gif", description: "Target GIF filename" } # { name: mode, type: select, select: "PNG→ImageMagick (better quality)|SVG→ImageMagick (simple drawings)|PNG→Pillow (builtin - a bit faster)|JavaScript→SVG (embed anim code)", value: PNG+ImageMagick, description: Conversion mode } # { name: delay, type: float, value: 0.35, min: 0.01, max: 20, precision: 2, description: "Delay between slides (seconds)" } # { name: loop, type: int, value: 0, description: "Loop limit (0 for endless)" } # { name: fuzz, type: select, select: "0%|5%|10%|20%|30%|50%", value: "10%", description: "Fuzzing/dither" } |
︙ | ︙ | |||
30 31 32 33 34 35 36 | # pack: export_gif.py, *.inx, pmd2inks, animate_yo.py, LICENSE=/usr/share/doc/inkscape-export-gif/copyright # format: off # author: mario#include-once:org # url: https://inkscape.org/~culturaljuice/★export_gif # orig: Xavi, https://github.com/jespino/inkscape-export-layers # # Generates a GIF slideshow from image layers ☰ (Shift+Ctrl+L). The menu | | > > | > | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | # pack: export_gif.py, *.inx, pmd2inks, animate_yo.py, LICENSE=/usr/share/doc/inkscape-export-gif/copyright # format: off # author: mario#include-once:org # url: https://inkscape.org/~culturaljuice/★export_gif # orig: Xavi, https://github.com/jespino/inkscape-export-layers # # Generates a GIF slideshow from image layers ☰ (Shift+Ctrl+L). The menu # option Extensions➜Export➔GIF-slideshow… iterates over layers to generate # animation slides. They get merged from bottom to top. Depending on shape # overlap or layer transparency, there's different usage modes: # # 🞂 With a solid background in each layer, there's no accumulation to # take care of. # 🞂 Alternatively elect layers` can be labeled as [background] to stick, # or [fixed] as permanent foreground, or [merge] for down-grouping. # 🞂 If the -layers option is composite/coalesce/merge then all lower # layers remain visible until the current frame. # 🞂 Any [animate] layers get interpolated as is, layer transparency # preserved. # # Requires ImageMagick installed; fit for standard Linux setups. But might # work with convert.exe on Windows. And alternatively there's the builtin # Pillow conversion method. The options mostly map to IM flags. # # 🞂 Without the PNG conversion step, SVG interpretation is up to Imagick, # and will not render fancy font/path effects. Just for plain old SVGs. # 🞂 The [PNG→Pillow] option works without ImageMagick, but often generates # rougher GIFs, yet might produce smaller result files. # 🞂 In [JavaScript] mode, no output file will be generated. It just adds a # script for animating slides into the current document (web views). # 🞂 A [fixed] layer label describes a permanent foreground (until overdrawn), # but never constitues a frame. Whereas [background] layers only become # active and permanent when its frame is reached. Additionally [merge] # labels will enjoin partial layers to the preceding full slide. But also # [exclude] to omit layers entirely. # 🞂 There's also a rudimentary [animate=5] option to craft subframes # from embedded <animate*> instructions. Motions require `pip install # svgelements` or a bundled version for accurate paths. # 🞂 Each layer label may also specify ImageMagick flags [--delay=2.5]. # 🞂 The "default background color" is useful for otherwise transparent # layers. Half-transparancy can be useful to gradually fade out lower # frames (only seems to work in SVG/ImageMagick -displace mode). # 🞂 Extra arguments are just a list of sample options, might not be # particularly useful by themselves. Use the second input or [--flag=X] # labels for more refined combinations. |
︙ | ︙ | |||
87 88 89 90 91 92 93 | # v0.7 · introduce combined modes · JavaScript embed option # v0.6 · support file→save-as invocation # v0.5 · revamped layer combination handling # v0.4 · support SVG export by removing nodes # v0.3 · introduced more imagemagick options # v0.2 · migrated to plugin meta data · more robust file handling # v0.1 · prototype | < | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | # v0.7 · introduce combined modes · JavaScript embed option # v0.6 · support file→save-as invocation # v0.5 · revamped layer combination handling # v0.4 · support SVG export by removing nodes # v0.3 · introduced more imagemagick options # v0.2 · migrated to plugin meta data · more robust file handling # v0.1 · prototype import sys import copy import os import tempfile from argparse import Namespace |
︙ | ︙ | |||
130 131 132 133 134 135 136 | def __init__(self): """ init the effect library """ self.tempdir = None self.index = 0 # current slide self.win32 = sys.platform == "win32" super().__init__() | > | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | def __init__(self): """ init the effect library """ self.tempdir = None self.index = 0 # current slide self.win32 = sys.platform == "win32" super().__init__() @staticmethod def add_arguments(pars): """ populate self.options from script args """ pars.add_argument("--file", type=str, dest="file", default="~/anim.gif", help="Target GIF filename") pars.add_argument("--mode", type=str, dest="mode", default="PNG→Pillow", help="Operation mode") pars.add_argument("--delay", type=float, dest="delay", default=0.35, help="Delay between slides (seconds)") pars.add_argument("--loop", type=int, dest="loop", default=0, help="Loop limit (0 for endless)") pars.add_argument("--fuzz", type=str, dest="fuzz", default="5%", help="Fuzzing/dither") pars.add_argument("--layers", type=str, dest="layers", default="optimize-transparency", help="Accumulation/combination of -layers") |
︙ | ︙ | |||
382 383 384 385 386 387 388 | # return modified SVG tree inkex.base.SvgOutputMixin.save(self, self.options.output) class AnimationSteps(): # pylint: disable=invalid-name, unused-argument, import-outside-toplevel """ Try to interpolate some frames from <animate*> interpretations. | | | > | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | # return modified SVG tree inkex.base.SvgOutputMixin.save(self, self.options.output) class AnimationSteps(): # pylint: disable=invalid-name, unused-argument, import-outside-toplevel """ Try to interpolate some frames from <animate*> interpretations. This won't progress beyond the most rudimentary of implementions. Currently color changes, scaling, rotation, some moving (proper path traversal hinges on svgelements). doc: https://edutechwiki.unige.ch/en/Using_Inkscape_for_web_animation, https://wiki.inkscape.org/wiki/index.php/SVG_Animation """ def __init__(self, parent, svg, layer): """ inherit from GifExport, and main layer loop """ import inkex.tween # pylint: disable=unused-import, import-outside-toplevel, redefined-outer-name self.gif = parent self.svg = svg # already a deepcopy self.layer = copy.deepcopy(layer) self.frames = int((layer.animate or [5])[0]) self.delay = float(layer.args.get("delay", self.gif.options.delay)) self.layer.args.update({ "delay": self.delay / self.frames # frame time split between animation steps }) #raise Exception(self.frames) |
︙ | ︙ | |||
461 462 463 464 465 466 467 | self.adapt(target, transform=tween.interpolate(time)) return apply def animate_motion(self, anim, path, **attrib): # pylint: disable=invalid-name """ <animateMotion path="M10,20" /> """ target = self.get_target(anim) | > | | | | 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | self.adapt(target, transform=tween.interpolate(time)) return apply def animate_motion(self, anim, path, **attrib): # pylint: disable=invalid-name """ <animateMotion path="M10,20" /> """ target = self.get_target(anim) orig_transform = str(target.transform) # prepend in adapt #if inkex.paths.Path(path)[0].is_relative: #bbox = target.bounding_box() #origin_xy = [bbox.left, bbox.top] try: import svgelements point = svgelements.Path(path).point except ModuleNotFoundError: point = self.rough_path(path) def apply(time, point=point, prepend=orig_transform): dx, dy = point(time) self.adapt(target, transform=f"{prepend} translate({dx} {dy})") return apply @staticmethod def rough_path(path): """ traverse any points+control in a zig-zag way, length discounted, absolute coordinates, etc. """ pairs = [ |
︙ | ︙ |