# svgasm
**Repository Path**: tidyfriday/svgasm
## Basic Information
- **Project Name**: svgasm
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-03-01
- **Last Updated**: 2021-03-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# *svgasm*
[![Sponsor][img_sponsor]][sponsor] [![Build status][img_build_status]][build_status] [![Language grade: C/C++][img_lgtm]][lgtm] [![License][img_license]][license]
[img_build_status]: https://github.com/tomkwok/svgasm/workflows/svgasm/badge.svg
[build_status]: https://github.com/tomkwok/svgasm/actions?query=branch%3Amaster
[img_lgtm]: https://img.shields.io/lgtm/grade/cpp/g/tomkwok/svgasm.svg?logo=lgtm&logoWidth=18
[lgtm]: https://lgtm.com/projects/g/tomkwok/svgasm/latest/files/
[img_license]: https://img.shields.io/github/license/tomkwok/svgasm?color=green&cacheSeconds=3600
[license]: LICENSE.md
[img_sponsor]: readme/badge_sponsor_animation.svg
[sponsor]: https://github.com/sponsors/tomkwok
[***svgasm***](https://github.com/tomkwok/svgasm) is a proof-of-concept SVG assembler to generate a self-contained animated SVG file from multiple still SVG files with CSS keyframes animation to play frames in sequence. Steps listed in reverse order of execution:
- Produces single animated SVG file that is viewable in Chrome, Safari, Firefox, Edge and IE 10+.
- Executes SVG cleaner [*svgcleaner*](https://github.com/RazrFalcon/svgcleaner) (by default) or [*svgo*](https://github.com/svg/svgo) to minify each SVG file.
- Executes bitmap tracer [*potrace*](http://potrace.sourceforge.net/) (by default) or [*autotrace*](https://github.com/autotrace/autotrace), or [*primitive*](https://github.com/fogleman/primitive) to convert raster image input to SVG.
- Executes image processor [*graphicsmagick*](http://www.graphicsmagick.org) (by default) or [*imagemagick*](https://imagemagick.org/) to convert GIF animation to frames.

## Examples
### SVG animation from single GIF using tracer
If the two versions of animation below are out of sync, try reloading this page without refreshing by clicking [here](https://github.com/tomkwok/svgasm).
Show evolution of life GIF example
Note that colors are inverted with gm convert -negate to obtain black-on-white images before tracing with potrace. The SVG output is hence black-on-transparent but restyled to white-on-black to match the input GIF.
Note that *potrace* [only natively handles two-valued images](http://potrace.sourceforge.net/faq.html#features). The color values in the SVG output can be specified with extra CSS styles definitions in the `-s` argument to the ***svgasm*** tool as in the command for the evolution of life GIF example. The colors do not have to be black or white or colors in grayscale used in the above examples.
All of the above examples traced with *potrace* can also be traced with *autotrace* with less configuration but also less accurate (sometimes funky) shapes in results, which can be viewed in [examples/autotrace\_results.ipynb](examples/autotrace_results.ipynb).
Use of multiple colors in SVG output is supported natively in *autotrace* but gradients are hard for any tracer.
Show Spongebob GIF example
While the above two examples can be created with CSS animation with some effort without the help of svgasm, the following example is not so easy. The following example is a 30-fps 41-frame animated contour plot of Fβ score from a sequence of 41 plots pre-generated using matplotlib animated with svgasm.
Notably, ***svgasm*** does not use JavaScript in SVG output. (An alternative approach would be to re-program plot generation with a JavaScript library like [D3.js](https://github.com/d3/d3-contour) to have the browser generate the values of text, paths, gradients, etc.)
## Usage
```
svgasm [options] infilepath...
Options:
-d animation time delay in seconds (default: 0.1)
-o path to SVG animation output file or - for stdout (default: -)
-p prefix added to element IDs (default: _)
-i animation iteration count (default: infinite)
-e index of frame to stop at in last iteration if not infinite (default: -1)
-l loading text in output or '' to turn off (default: 'Loading ...')
-s extra CSS styles definition in output (default: '')
-c command for SVG cleaner with "%s" (default: 'svgcleaner --multipass -c "%s"')
-t command for tracer for non-SVG still image with "%s" (default: 'gm convert +matte "%s" ppm:- | potrace --svg -o -')
-m command for magick program for GIF animation with %s (default: 'gm %s')
-q silence verbose standard error output
-h print help information
```
## Usage examples
- `svgasm -d 2 -i 5 -e 0 -o animation.svg input1.svg input2.svg input3.svg`
Generates output *animation.svg* from *input1.svg*, *input2.svg* and *input3.svg* that animates with a delay of 2 seconds per frame, iterates 5 times, and stops at the first frame in the last iteration.
- `svgasm -d 1/30 -l '' intro.jpg frame*.png > animation.svg`
Generates output *animation.svg* from *intro.jpg* and wild card *frame\*.png* that animates with 30 frames per second, iterates infinitely, and with loading text turned off.
- `svgasm animation1.gif animation2.gif > animation.svg`
Generates output *animation.svg* from *animation1.gif* and *animation2.gif* that animates with the same time delay and iteration count as the first GIF file.
## Installing on macOS
To install and run a pre-compiled binary of ***svgasm*** on macOS with [Homebrew](https://brew.sh/) installed, run the following commands, which would also install dependencies *svgcleaner*, *potrace* and *graphicsmagick*:
```sh
brew install tomkwok/tap/svgasm
svgasm
```
## Building on macOS or Linux
To clone this repository and build ***svgasm*** with a C++98 complier installed, run the following commands:
```sh
git clone https://github.com/tomkwok/svgasm
cd svgasm/
make
./svgasm
```
***svgasm*** can be executed as a standalone program. However, the only working feature without dependencies is `svgasm [options] input*.svg > output.svg` (with automatic fallback to `cat` as dummy cleaner program).
For more features, install runtime dependencies. An example instruction is provided for [Arch Linux](https://archlinux.org/) as follows:
```sh
sudo pacman -S svgcleaner potrace graphicsmagick
```
To download the example files in this repository with `git-lfs` installed, run the following commands:
```sh
git lfs install
git lfs pull
```
## Installing optional runtime dependencies
- [*svgo*](https://github.com/svg/svgo): running the command `npm install -g svgo` or `yarn global add svgo`
- [*autotrace*](https://github.com/autotrace/autotrace): downloading a release binary from the [release page of autotrace](https://github.com/autotrace/autotrace/releases) or install with a package manager
- [*primitive*](https://github.com/fogleman/primitive): running the command `go get -u github.com/fogleman/primitive`
## Benchmark with different SVG cleaners
***svgasm*** has been tested to work with the following cleaners:
- ***cat*** can be specified as a dummy cleaner program for most SVG files. (In particular, ensure that there are no unnecessary white-spaces in tags.) *cat* is the fallback program if *svgcleaner* is not installed on the system.
- ***svgcleaner*** is the default cleaner program. *svgcleaner* is chosen as the default cleaner because it is generally very fast and produces small output.
- ***svgo*** can be specified as the cleaner program. *svgo* is typically over an order of magnitude slower than *svgcleaner*. Nonetheless, *svgo* can sometimes produce smaller files than *svgcleaner* does.
The following are the results of using ***svgasm*** to produce the 41-frame contour plot animation example above on an Intel Core i5 processor with different cleaners. The size of output after compression with [gzip](https://www.gzip.org/) at the best level `-9` is provided in brackets for reference since SVG files are usually served via HTTP which supports compression.
| Command executed | Output SVG size (gzip) | Real elapsed time |
|:------------------------------------------------- | --------------------------- | -----------------:|
| `svgasm -c 'cat "%s"' [...]` | 3,143 KiB (1,145 KiB) | **0.265 s ± 0.006 s** |
| `svgasm -c 'svgcleaner --multipass -c "%s"' [...]` | 2,232 KiB (992 KiB) | 0.844 s ± 0.041 s |
| `svgasm -c 'svgo --multipass -o - "%s"' [...]` | **2,054 KiB (884 KiB)** | 34.839 s ± 0.292 s |
## Benchmark with GraphicsMagick and ImageMagick
GraphicsMagick is a fork of ImageMagick, and it is reportedly faster in [benchmarks](http://www.graphicsmagick.org/benchmarks.html). The following are the results of using ***svgasm*** to produce the 60-frame rotating cross animation example above on an Intel Core i5 processor with GraphicsMagick and ImageMagick specified as the magick command. Note that the magick program is also present in the default tracer command for *potrace*. Identical output is obtained with the two utility programs.
| | Command executed | Real elapsed time |
| --------------- | :----------------------------------------------------------- | -----------------:|
| GraphicsMagick | `svgasm -c 'cat "%s"' -m 'gm %s' -t 'gm convert "%s" [...]'` | **3.205 s ± 0.037 s** |
| ImageMagick | `svgasm -c 'cat "%s"' -m '%s' -t 'convert "%s" [...]'` | 5.493 s ± 0.041 s |
## How ***svgasm*** is implemented
- Refer to an [example](https://stackoverflow.com/questions/48893587/simple-animate-multiple-svgs-in-sequence-like-a-looping-gif) on Stack Overflow of animating a sequence of hand-drawn vector graphics. The principal method employed in the ***svgasm*** tool of playing SVGs in sequence with CSS animation is credited to its author.
- Implementation is fine-tuned in the ***svgasm*** tool to better accommodate browser behavior. In particular, since Chrome renders elements on the fly and starts timing animations on elements as SVG file loads, attention was given to styles placement to prevent flickering in Chrome due to mismatching animation start times for different group elements for frames. See inline comments in [src/svgasm.cpp](src/svgasm.cpp) for details. Note that such flickering is only apparent in an animation with a high fps value. (It is not clear in the [CSS Animations specification](https://www.w3.org/TR/css-animations-1/#animations) whether a style rule is considered resolved or not when the styles are parsed but the elements referenced are not yet in the DOM. The answer is apparently no in Chrome, so CSS animations need to be moved to the end for animation of frames to start at the same time.)
- An SVG file cleaner is executed to pre-process SVG files to ensure that ***svgasm*** can successfully parse input SVG files. For simplicity, ***svgasm*** uses string operations in standard library instead of an XML parser. The animated SVG file output generated does not seem to be further minifiable using *svgcleaner* or *svgo*. Currently, *svgo* gives an empty SVG when given the output of ***svgasm***.
- The `