-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 635e5e1
Showing
32 changed files
with
27,984 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
name: Publish to PyPI | ||
|
||
on: | ||
push: | ||
tags: | ||
- '[0-9]+.[0-9]+.[0-9]+*' | ||
|
||
jobs: | ||
publish: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Install Hatch | ||
uses: pypa/hatch@a3c83ab3d481fbc2dc91dd0088628817488dd1d5 | ||
|
||
- name: Build | ||
run: hatch build | ||
|
||
- name: Publish to PyPI | ||
env: | ||
HATCH_INDEX_USER: __token__ | ||
HATCH_INDEX_AUTH: ${{ secrets.PYPI_TOKEN }} | ||
run: hatch publish |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: Tests | ||
|
||
on: | ||
push: | ||
branches: [ "**" ] | ||
pull_request: | ||
branches: [ "**" ] | ||
|
||
jobs: | ||
test: | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, windows-latest, macos-latest] | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Install Hatch | ||
uses: pypa/hatch@a3c83ab3d481fbc2dc91dd0088628817488dd1d5 | ||
|
||
- name: Run tests | ||
run: hatch test -a | ||
|
||
- name: Check formatting and lint | ||
run: hatch fmt --check |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Python-generated files | ||
__pycache__/ | ||
*.py[oc] | ||
build/ | ||
dist/ | ||
wheels/ | ||
*.egg-info | ||
*.spec | ||
.ruff_cache | ||
|
||
# Virtual environments | ||
.venv | ||
|
||
# Testing | ||
.pytest_cache | ||
coverage.xml | ||
.coverage* | ||
|
||
# Misc | ||
dircat.md | ||
test.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2025 Romelium | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
<h1 align="center"> | ||
<img height="250" src="images/framesvg.svg" alt="FrameSVG" /> | ||
</h1> | ||
|
||
<p align="center"> | ||
<strong>Convert animated GIFs to animated SVGs.</strong> | ||
</p> | ||
|
||
<p align="center"> | ||
<a href="https://github.com/romelium/framesvg/actions/workflows/tests.yml"><img alt="Build Status" src="https://img.shields.io/github/actions/workflow/status/romelium/framesvg/main.yml?branch=main"></a> | ||
<a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-blue.svg"></a> | ||
<a href="https://pypi.org/project/framesvg/"><img alt="PyPI" src="https://img.shields.io/pypi/v/framesvg"></a> | ||
<a href="https://pypi.org/project/framesvg/"><img alt="Python Versions" src="https://img.shields.io/pypi/pyversions/framesvg"></a> | ||
</p> | ||
|
||
<!-- Be on the left and right of next paragraph --> | ||
<img align="left" hspace=10 src="images/kyubey.svg"/> | ||
<img align="right" hspace=10 src="images/kyubey.svg"/> | ||
|
||
`framesvg` is a command-line tool and Python library that converts animated GIFs into animated SVGs. It leverages the power of [VTracer](https://www.visioncortex.org/vtracer/) for raster-to-vector conversion, producing smooth, scalable, and *true vector* animations. This is a significant improvement over embedding raster images (like GIFs) directly within SVGs, as `framesvg` generates genuine vector output that plays automatically and scales beautifully. Ideal for readmes, documentation, and web graphics. | ||
|
||
<p align="center"> | ||
Preferred to be viewed on <a href="https://github.com/Romelium/FrameSVG?tab=readme-ov-file">GitHub</a> | ||
</p> | ||
|
||
<br clear="both"/> | ||
|
||
## Why Use framesvg? | ||
|
||
* **True Vector Output:** Unlike simply embedding a GIF within an SVG, `framesvg` creates a true vector animation. This means: | ||
* **Scalability:** The SVG can be resized to any dimensions without losing quality. | ||
* **Smaller File Size (Potentially):** For many GIFs, the resulting SVG will be smaller, especially for graphics with large areas of solid color or simple shapes. Complex, photographic GIFs may be larger, however. | ||
* **Automatic Playback:** The generated SVGs are designed to play automatically in any environment that supports SVG animations (web browsers, github, many image viewers, etc.). | ||
* **Easy to Use:** Simple command-line interface and a clean Python API. | ||
* **Customizable:** Control the frame rate and fine-tune the VTracer conversion process for optimal results. | ||
|
||
## Examples | ||
|
||
The following examples demonstrate the conversion of GIFs (left) to SVGs (right) using `framesvg`. | ||
|
||
<p align="center"> | ||
<img height=200 src="images/Code Coding GIF by EscuelaDevRock Git.gif"/> | ||
<img height=200 src="images/Code Coding GIF by EscuelaDevRock Git.svg"/> | ||
<img height=200 src="images/Code Coding GIF by EscuelaDevRock GitHub.gif"/> | ||
<img height=200 src="images/Code Coding GIF by EscuelaDevRock GitHub.svg"/> | ||
<img height=200 src="images/Code Coding GIF by EscuelaDevRock VSCode.gif"/> | ||
<img height=200 src="images/Code Coding GIF by EscuelaDevRock VSCode.svg"/> | ||
<img height=200 src="images/Code Coding GIF by EscuelaDevRock Sublime.gif"/> | ||
<img height=200 src="images/Code Coding GIF by EscuelaDevRock Sublime.svg"/> | ||
</p> | ||
|
||
### More Examples | ||
|
||
<p align="center"> | ||
<img height=200 src="images/Good_Morning_GIF_by_Hello_All.gif"/> | ||
<img height=200 src="images/Good_Morning_GIF_by_Hello_All.svg"/> | ||
<img height=200 src="images/icon_loading_GIF.gif"/> | ||
<img height=200 src="images/icon_loading_GIF.svg"/> | ||
<img height=200 src="images/voila hands GIF by brontron.gif"/> | ||
<img height=200 src="images/voila hands GIF by brontron.svg"/> | ||
</p> | ||
|
||
### Complex Examples (Transparent Backgrounds) | ||
|
||
These examples demonstrate `binary` color mode. All bright colors in `binary` color mode turns transparent. (If they appear dark, it is due to the transparency. They will look correct on light backgrounds) | ||
|
||
<p align="center"> | ||
<img height=200 src="images/black and white loop GIF by Sculpture.gif"/> | ||
<img height=200 src="images/black and white loop GIF by Sculpture.svg"/> | ||
<img height=200 src="images/Black And White Loop GIF by Pi-Slices.gif"/> | ||
<img height=200 src="images/Black And White Loop GIF by Pi-Slices.svg"/> | ||
</p> | ||
|
||
## Installation | ||
|
||
### Using pip (Recommended) | ||
|
||
The easiest way to install `framesvg` is via pip: | ||
|
||
```bash | ||
pip install framesvg | ||
``` | ||
|
||
This installs both the command-line tool and the Python library. | ||
|
||
### From Source | ||
|
||
1. **Clone the repository:** | ||
|
||
```bash | ||
git clone https://github.com/romelium/framesvg | ||
cd framesvg | ||
``` | ||
|
||
2. **Install:** | ||
|
||
```bash | ||
pip install . | ||
``` | ||
|
||
## Usage | ||
|
||
### Command-Line Interface | ||
|
||
```bash | ||
framesvg input.gif [output.svg] [options] | ||
``` | ||
|
||
* **`input.gif`:** (Required) Path to the input GIF file. | ||
* **`output.svg`:** (Optional) Path to save the output SVG file. If omitted, the output file will have the same name as the input, but with a `.svg` extension. | ||
|
||
**Options:** | ||
|
||
* **`-f`, `--fps <value>`:** Sets the frames per second (FPS) for the animation. (Default: 10). Lower values can reduce file size. | ||
* **`-l`, `--log-level <level>`:** Sets the logging level. (Default: INFO). Choices: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`, `NONE`. `DEBUG` provides detailed output for troubleshooting. | ||
|
||
* **VTracer Options:** These options control the raster-to-vector conversion process performed by VTracer. Refer to the [VTracer Documentation](https://www.visioncortex.org/vtracer-docs) and [Online Demo](https://www.visioncortex.org/vtracer/) for detailed explanations. | ||
|
||
* `-c`, `--colormode <mode>`: Color mode. (Default: `color`). Choices: `color`, `binary`. | ||
* `-i`, `--hierarchical <mode>`: Hierarchy mode. (Default: `stacked`). Choices: `stacked`, `cutout`. | ||
* `-m`, `--mode <mode>`: Conversion mode. (Default: `polygon`). Choices: `spline`, `polygon`, `none`. `spline` creates smoother curves, but `polygon` often results in smaller files. | ||
* `-s`, `--filter-speckle <value>`: Reduces noise and small details. (Default: 4). *This is a key parameter for controlling file size.* Higher values = smaller files, but less detail. | ||
* `-p`, `--color-precision <value>`: Number of significant bits for color quantization. (Default: 8). Lower values = smaller files, but fewer colors. | ||
* `-d`, `--layer-difference <value>`: Controls the number of layers. (Default: 16). Higher values can reduce file size. | ||
* `--corner-threshold <value>`: Angle threshold for corner detection. (Default: 60). | ||
* `--length-threshold <value>`: Minimum path length. (Default: 4.0). | ||
* `--max-iterations <value>`: Maximum number of optimization iterations. (Default: 10). | ||
* `--splice-threshold <value>`: Angle threshold for splitting splines. (Default: 45). | ||
* `--path-precision <value>`: Number of decimal places for path coordinates. (Default: 8). | ||
|
||
**Command-Line Examples:** | ||
|
||
```bash | ||
# Basic conversion with default settings | ||
framesvg input.gif | ||
# Specify output file and set FPS to 24 | ||
framesvg input.gif output.svg -f 24 | ||
# Optimize for smaller file size (less detail) | ||
framesvg input.gif -s 8 -p 3 -d 128 | ||
# Enable debug logging | ||
framesvg input.gif -l DEBUG | ||
``` | ||
|
||
### Python API | ||
|
||
```python | ||
from framesvg import gif_to_animated_svg_write, gif_to_animated_svg | ||
# Example 1: Convert and save to a file | ||
gif_to_animated_svg_write("input.gif", "output.svg", fps=30) | ||
# Example 2: Get the SVG as a string | ||
animated_svg_string = gif_to_animated_svg("input.gif", fps=12) | ||
print(f"Generated SVG length: {len(animated_svg_string)}") | ||
# ... do something with the string (e.g., save to file, display in a web app) | ||
# Example 3: Customize VTracer options | ||
custom_options = { | ||
"mode": "spline", | ||
"filter_speckle": 2, | ||
} | ||
gif_to_animated_svg_write("input.gif", "output_custom.svg", vtracer_options=custom_options) | ||
``` | ||
|
||
### API Reference | ||
|
||
* **`gif_to_animated_svg_write(gif_path, output_svg_path, vtracer_options=None, fps=10.0, image_loader=None, vtracer_instance=None)`:** | ||
* `gif_path` (str): Path to the input GIF file. | ||
* `output_svg_path` (str): Path to save the output SVG file. | ||
* `vtracer_options` (dict, optional): A dictionary of VTracer options. If `None`, uses `DEFAULT_VTRACER_OPTIONS`. | ||
* `fps` (float, optional): Frames per second. Defaults to 10.0. | ||
* `image_loader` (ImageLoader, optional): Custom image loader. | ||
* `vtracer_instance` (VTracer, optional): Custom VTracer instance. | ||
* Raises: `FileNotFoundError`, `NotAnimatedGifError`, `NoValidFramesError`, `DimensionError`, `ExtractionError`, `FramesvgError`, `IsADirectoryError`. | ||
|
||
* **`gif_to_animated_svg(gif_path, vtracer_options=None, fps=10.0, image_loader=None, vtracer_instance=None)`:** | ||
* `gif_path` (str): Path to the input GIF file. | ||
* `vtracer_options` (dict, optional): A dictionary of VTracer options. If `None`, uses `DEFAULT_VTRACER_OPTIONS`. | ||
* `fps` (float, optional): Frames per second. Defaults to 10.0. | ||
* `image_loader` (ImageLoader, optional): Custom image loader. | ||
* `vtracer_instance` (VTracer, optional): Custom VTracer instance. | ||
* Returns: The animated SVG as a string. | ||
* Raises: `FileNotFoundError`, `NotAnimatedGifError`, `NoValidFramesError`, `DimensionError`, `ExtractionError`, `FramesvgError`. | ||
|
||
## Tips for Optimizing Large File Size (> 1MB) | ||
|
||
* **[Online Demo](https://www.visioncortex.org/vtracer/):** Use this to visualize tweaking values. Experiment to find the best balance between size and quality. | ||
* **`filter-speckle`:** *This is the most impactful setting for reducing file size, especially on complex images.* Increasing it removes small details. | ||
* **`--mode polygon`:** Use the default polygon mode unless smooth curves (spline mode) are absolutely necessary. Polygon mode can significantly reduce file size by a factor of 5 or more. | ||
* **`layer-difference`:** Increase this to reduce the number of layers. | ||
* **`color-precision`:** Reduce the number of colors by lowering this value. | ||
|
||
## Dev | ||
|
||
### Install Hatch (Recommended) | ||
|
||
follow [this](https://hatch.pypa.io/latest/install) | ||
|
||
or just | ||
|
||
```bash | ||
pip install hatch | ||
``` | ||
|
||
### Format and lint | ||
|
||
```bash | ||
hatch fmt | ||
``` | ||
|
||
### Testing | ||
```bash | ||
hatch test | ||
``` | ||
|
||
### Other Hatch Commands | ||
|
||
```bash | ||
hatch -h | ||
``` | ||
|
||
## Contributing | ||
|
||
Contributions are welcome! Please submit pull requests or open issues on the [GitHub repository](https://github.com/romelium/framesvg). |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.