5 Commits

Author SHA1 Message Date
Chris Tsang
66f6bd98f4 Feature guard 2023-09-08 13:20:28 +01:00
Chris Tsang
59448884cb Edit RELEASES.md 2023-09-08 13:10:19 +01:00
Chris Tsang
edf1311425 Edit Readme 2023-09-08 13:05:15 +01:00
Chris Tsang
02c844dc7a Move code around 2023-09-08 13:03:43 +01:00
Evan Jones
c3090ac50b Python bindings sep 2023 (#52)
* Added maturin-based Python binding, to be deployed to https://pypi.org/project/vtracer/

* Removed poetry mentions from pyproject.toml, added README_PY.md for use on PYPI

* ->   v0.6.1
-> moved Python bindings to bottom of converter.rs

* - README_PY.md needed to be inside the cmdapp directory to display on PyPi.irg
->  v0.6.3
2023-09-08 19:43:13 +08:00
13 changed files with 355 additions and 24 deletions

117
.github/workflows/CI.yml vendored Normal file
View File

@@ -0,0 +1,117 @@
# This file is autogenerated by maturin v1.2.3
# To update, run
#
# maturin generate-ci github
#
name: CI
on:
push:
tags:
- '*'
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
linux:
runs-on: ubuntu-latest
strategy:
matrix:
target: [x86_64, x86, aarch64, armv7, s390x, ppc64le]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
manylinux: auto
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
windows:
runs-on: windows-latest
strategy:
matrix:
target: [x64, x86]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
architecture: ${{ matrix.target }}
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
macos:
runs-on: macos-latest
strategy:
matrix:
target: [x86_64, aarch64]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --find-interpreter
sccache: 'true'
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
- name: Upload sdist
uses: actions/upload-artifact@v3
with:
name: wheels
path: dist
release:
name: Release
runs-on: ubuntu-latest
if: "startsWith(github.ref, 'refs/tags/')"
needs: [linux, windows, macos, sdist]
steps:
- uses: actions/download-artifact@v3
with:
name: wheels
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:
command: upload
args: --non-interactive --skip-existing *

View File

@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## 0.6.0 - 2023-09-08
* Python Binding
## 0.5.0 - 2022-10-09
* Handle transparent png images (cli) (#23)

View File

@@ -3,4 +3,5 @@
members = [
"cmdapp",
"webapp",
]
]
resolver = "2"

View File

@@ -1,28 +1,27 @@
Version 0.4.0 (2021-07-23)
==========================
# Version 0.6.0 (2023-09-08)
- SVG path string numeric precision
- Python bindings
# Version 0.5.0 (2022-10-09)
Version 0.3.0 (2021-01-24)
==========================
- Handle transparent png images
- Added cutout mode
# Version 0.4.0 (2021-07-23)
- SVG path string numeric precision
Version 0.2.0 (2020-11-15)
==========================
# Version 0.3.0 (2021-01-24)
- Use relative & closed paths
- Added cutout mode
# Version 0.2.0 (2020-11-15)
Version 0.1.1 (2020-11-01)
==========================
- Use relative & closed paths
- SVG namespace
# Version 0.1.1 (2020-11-01)
- SVG namespace
Version 0.1.0 (2020-10-31)
==========================
# Version 0.1.0 (2020-10-31)
- Initial release
- Initial release

View File

@@ -1,8 +1,8 @@
[package]
name = "vtracer"
version = "0.5.0"
authors = ["Chris Tsang <tyt2y7@gmail.com>"]
edition = "2018"
version = "0.6.3"
authors = ["Chris Tsang <chris.2y3@outlook.com>"]
edition = "2021"
description = "A cmd app to convert images into vector graphics."
license = "MIT OR Apache-2.0"
homepage = "http://www.visioncortex.org/vtracer"
@@ -14,4 +14,8 @@ keywords = ["svg", "computer-graphics"]
clap = "2.33.3"
image = "0.23.10"
visioncortex = { version = "0.8.0" }
fastrand = "1.8"
fastrand = "1.8"
pyo3 = { version = "0.19.0", optional = true }
[features]
python-binding = ["pyo3"]

28
cmdapp/pyproject.toml Normal file
View File

@@ -0,0 +1,28 @@
[project]
name = "vtracer"
version = "0.6.3"
description = "Python bindings for the Rust Vtracer raster-to-vector library"
authors = [ { name = "Chris Tsang", email = "chris.2y3@outlook.com" } ]
readme = "vtracer/README.md"
requires-python = ">=3.7"
license = "MIT"
classifiers = [
"Programming Language :: Rust",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
[dependencies]
python = "^3.7"
[dev-dependencies]
maturin = "^1.2"
[build-system]
requires = ["maturin>=1.2,<2.0"]
build-backend = "maturin"
[tool.maturin]
features = ["pyo3/extension-module"]
compatibility = "linux"
sdist-include = ["../LICENSE", "../README.md"]

View File

@@ -11,7 +11,11 @@
mod config;
mod converter;
mod svg;
#[cfg(feature = "python-binding")]
mod python;
pub use config::*;
pub use converter::*;
pub use svg::*;
pub use svg::*;
#[cfg(feature = "python-binding")]
pub use python::*;

81
cmdapp/src/python.rs Normal file
View File

@@ -0,0 +1,81 @@
use pyo3::prelude::*;
use visioncortex::{PathSimplifyMode};
use super::converter::*;
/// Python binding
#[pyfunction]
fn convert_image_to_svg_py( image_path: &str,
out_path: &str,
colormode: Option<&str>, // "color" or "binary"
hierarchical: Option<&str>, // "stacked" or "cutout"
mode: Option<&str>, // "polygon", "spline", "none"
filter_speckle: Option<usize>, // default: 4
color_precision: Option<i32>, // default: 6
layer_difference: Option<i32>, // default: 16
corner_threshold: Option<i32>, // default: 60
length_threshold: Option<f64>, // in [3.5, 10] default: 4.0
max_iterations: Option<usize>, // default: 10
splice_threshold: Option<i32>, // default: 45
path_precision: Option<u32> // default: 8
) -> PyResult<()> {
let input_path = PathBuf::from(image_path);
let output_path = PathBuf::from(out_path);
// TODO: enforce color mode with an enum so that we only
// accept the strings 'color' or 'binary'
let color_mode = match colormode.unwrap_or("color") {
"color" => ColorMode::Color,
"binary" => ColorMode::Binary,
_ => ColorMode::Color,
};
let hierarchical = match hierarchical.unwrap_or("stacked") {
"stacked" => Hierarchical::Stacked,
"cutout" => Hierarchical::Cutout,
_ => Hierarchical::Stacked,
};
let mode = match mode.unwrap_or("spline") {
"spline" => PathSimplifyMode::Spline,
"polygon" => PathSimplifyMode::Polygon,
"none" => PathSimplifyMode::None,
_ => PathSimplifyMode::Spline,
};
let filter_speckle = filter_speckle.unwrap_or(4);
let color_precision = color_precision.unwrap_or(6);
let layer_difference = layer_difference.unwrap_or(16);
let corner_threshold = corner_threshold.unwrap_or(60);
let length_threshold = length_threshold.unwrap_or(4.0);
let splice_threshold = splice_threshold.unwrap_or(45);
let max_iterations = max_iterations.unwrap_or(10);
let config = Config {
input_path,
output_path,
color_mode,
hierarchical,
filter_speckle,
color_precision,
layer_difference,
mode,
corner_threshold,
length_threshold,
max_iterations,
splice_threshold,
path_precision,
..Default::default()
};
convert_image_to_svg(config).unwrap();
Ok(())
}
/// A Python module implemented in Rust.
#[pymodule]
fn vtracer(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(convert_image_to_svg_py, m)?)?;
Ok(())
}

75
cmdapp/vtracer/README.md Normal file
View File

@@ -0,0 +1,75 @@
<div align="center">
<img src="https://github.com/visioncortex/vtracer/raw/master/docs/images/visioncortex-banner.png">
<h1>VTracer: Python Binding</h1>
<p>
<strong>Raster to Vector Graphics Converter built on top of visioncortex</strong>
</p>
<h3>
<a href="//www.visioncortex.org/vtracer-docs">Article</a>
<span> | </span>
<a href="//www.visioncortex.org/vtracer/">Demo</a>
<span> | </span>
<a href="//github.com/visioncortex/vtracer/releases/latest">Download</a>
</h3>
<sub>Built with 🦀 by <a href="//www.visioncortex.org/">The Vision Cortex Research Group</a></sub>
</div>
## Introduction
visioncortex VTracer is an open source software to convert raster images (like jpg & png) into vector graphics (svg). It can vectorize graphics and photographs and trace the curves to output compact vector files.
Comparing to [Potrace](http://potrace.sourceforge.net/) which only accept binarized inputs (Black & White pixmap), VTracer has an image processing pipeline which can handle colored high resolution scans.
Comparing to Adobe Illustrator's [Image Trace](https://helpx.adobe.com/illustrator/using/image-trace.html), VTracer's output is much more compact (less shapes) as we adopt a stacking strategy and avoid producing shapes with holes.
VTracer is originally designed for processing high resolution scans of historic blueprints up to gigapixels. At the same time, VTracer can also handle low resolution pixel art, simulating `image-rendering: pixelated` for retro game artworks.
A technical description of the algorithm is on [visioncortex.org/vtracer-docs](//www.visioncortex.org/vtracer-docs).
## Install (Python)
```shell
pip install vtracer
```
### Usage (Python)
```python
import vtracer
input_path = "/path/to/some_file.jpg"
output_path = "/path/to/some_file.vtracer.jpg"
# Minimal example: use all default values, generate a multicolor SVG
vtracer.convert_image_to_svg_py(inp, out)
# Single-color example. Good for line art, and much faster than full color:
vtracer.convert_image_to_svg_py(inp, out, colormode='binary')
# All the bells & whistles
vtracer.convert_image_to_svg_py(inp,
out,
colormode = 'color', # ["color"] or "binary"
hierarchical = 'stacked', # ["stacked"] or "cutout"
mode = 'spline', # ["spline"] "polygon", or "none"
filter_speckle = 4, # default: 4
color_precision = 6, # default: 6
layer_difference = 16, # default: 16
corner_threshold = 60, # default: 60
length_threshold = 4.0, # in [3.5, 10] default: 4.0
max_iterations = 10, # default: 10
splice_threshold = 45, # default: 45
path_precision = 3 # default: 8
)
```
## Rust Library
The (Rust) library can be found on [crates.io/vtracer](//crates.io/crates/vtracer) and [crates.io/vtracer-webapp](//crates.io/crates/vtracer-webapp).

View File

@@ -0,0 +1 @@
from .vtracer import convert_image_to_svg_py

View File

@@ -0,0 +1,17 @@
from typing import Optional
def convert_image_to_svg_py(image_path: str,
out_path: str,
colormode: Optional[str] = None, # ["color"] or "binary"
hierarchical: Optional[str] = None, # ["stacked"] or "cutout"
mode: Optional[str] = None, # ["spline"], "polygon", "none"
filter_speckle: Optional[int] = None, # default: 4
color_precision: Optional[int] = None, # default: 6
layer_difference: Optional[int] = None, # default: 16
corner_threshold: Optional[int] = None, # default: 60
length_threshold: Optional[float] = None, # in [3.5, 10] default: 4.0
max_iterations: Optional[int] = None, # default: 10
splice_threshold: Optional[int] = None, # default: 45
path_precision: Optional[int] = None, # default: 8
) -> None:
...

View File

@@ -1,8 +1,8 @@
[package]
name = "vtracer-webapp"
version = "0.4.0"
authors = ["Chris Tsang <tyt2y7@gmail.com>"]
edition = "2018"
authors = ["Chris Tsang <chris.2y3@outlook.com>"]
edition = "2021"
description = "A web app to convert images into vector graphics."
license = "MIT OR Apache-2.0"
homepage = "http://www.visioncortex.org/vtracer"

View File

@@ -2,7 +2,7 @@
"name": "vtracer-app",
"version": "0.1.0",
"description": "VTracer Webapp",
"author": "Chris Tsang <tyt2y7@gmail.com>",
"author": "Chris Tsang <chris.2y3@outlook.com>",
"license": "proprietary",
"private": true,
"main": "index.js",