mirror of
https://github.com/visioncortex/vtracer.git
synced 2025-12-06 17:15:41 -08:00
Python bindings configured correctly for PyPI releases (#54)
* 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 * Move code around * Edit Readme * Edit RELEASES.md * Feature guard * Build wheels with the cmdapp/Cargo.toml rather than top-level Cargo.toml * use cmdapp/Cargo.toml for all Maturin CI actions, which causes Github to build all platforms python wheels and submit a new release to PyPI * Bump to 0.6.4 for new PyPI release with all platforms' wheels included * PyPI didn't accept a 'linux_aarch64' wheel for a release. For the moment, remove the platform until I can convince the action to build 'manylinux_aarch64' or the like * Version bump while I work out CI & PyPI release wrinkles * Maturin authors say `compatibility = "linux"` in pyproject.toml is causing PyPI failure. Replacing with "manylinux2014" * bump to v0.7.0 in preparation for release from original vtracer repo --------- Co-authored-by: Chris Tsang <chris.2y3@outlook.com>
This commit is contained in:
118
.github/workflows/CI.yml
vendored
Normal file
118
.github/workflows/CI.yml
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# 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: -m cmdapp/Cargo.toml --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: -m cmdapp/Cargo.toml --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: -m cmdapp/Cargo.toml --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: -m cmdapp/Cargo.toml --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 *
|
||||||
|
manylinux: auto
|
||||||
@@ -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/)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## 0.6.0 - 2023-09-08
|
||||||
|
|
||||||
|
* Python Binding
|
||||||
|
|
||||||
## 0.5.0 - 2022-10-09
|
## 0.5.0 - 2022-10-09
|
||||||
|
|
||||||
* Handle transparent png images (cli) (#23)
|
* Handle transparent png images (cli) (#23)
|
||||||
|
|||||||
@@ -3,4 +3,5 @@
|
|||||||
members = [
|
members = [
|
||||||
"cmdapp",
|
"cmdapp",
|
||||||
"webapp",
|
"webapp",
|
||||||
]
|
]
|
||||||
|
resolver = "2"
|
||||||
29
RELEASES.md
29
RELEASES.md
@@ -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
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vtracer"
|
name = "vtracer"
|
||||||
version = "0.5.0"
|
version = "0.7.0"
|
||||||
authors = ["Chris Tsang <tyt2y7@gmail.com>"]
|
authors = ["Chris Tsang <chris.2y3@outlook.com>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
description = "A cmd app to convert images into vector graphics."
|
description = "A cmd app to convert images into vector graphics."
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
homepage = "http://www.visioncortex.org/vtracer"
|
homepage = "http://www.visioncortex.org/vtracer"
|
||||||
@@ -14,4 +14,8 @@ keywords = ["svg", "computer-graphics"]
|
|||||||
clap = "2.33.3"
|
clap = "2.33.3"
|
||||||
image = "0.23.10"
|
image = "0.23.10"
|
||||||
visioncortex = { version = "0.8.0" }
|
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
28
cmdapp/pyproject.toml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
[project]
|
||||||
|
name = "vtracer"
|
||||||
|
version = "0.7.0"
|
||||||
|
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 = "manylinux2014"
|
||||||
|
sdist-include = ["LICENSE-MIT", "vtracer/README.md"]
|
||||||
@@ -11,7 +11,11 @@
|
|||||||
mod config;
|
mod config;
|
||||||
mod converter;
|
mod converter;
|
||||||
mod svg;
|
mod svg;
|
||||||
|
#[cfg(feature = "python-binding")]
|
||||||
|
mod python;
|
||||||
|
|
||||||
pub use config::*;
|
pub use config::*;
|
||||||
pub use converter::*;
|
pub use converter::*;
|
||||||
pub use svg::*;
|
pub use svg::*;
|
||||||
|
#[cfg(feature = "python-binding")]
|
||||||
|
pub use python::*;
|
||||||
81
cmdapp/src/python.rs
Normal file
81
cmdapp/src/python.rs
Normal 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
75
cmdapp/vtracer/README.md
Normal 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).
|
||||||
1
cmdapp/vtracer/__init__.py
Normal file
1
cmdapp/vtracer/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .vtracer import convert_image_to_svg_py
|
||||||
17
cmdapp/vtracer/vtracer.pyi
Normal file
17
cmdapp/vtracer/vtracer.pyi
Normal 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:
|
||||||
|
...
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vtracer-webapp"
|
name = "vtracer-webapp"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
authors = ["Chris Tsang <tyt2y7@gmail.com>"]
|
authors = ["Chris Tsang <chris.2y3@outlook.com>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
description = "A web app to convert images into vector graphics."
|
description = "A web app to convert images into vector graphics."
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
homepage = "http://www.visioncortex.org/vtracer"
|
homepage = "http://www.visioncortex.org/vtracer"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "vtracer-app",
|
"name": "vtracer-app",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "VTracer Webapp",
|
"description": "VTracer Webapp",
|
||||||
"author": "Chris Tsang <tyt2y7@gmail.com>",
|
"author": "Chris Tsang <chris.2y3@outlook.com>",
|
||||||
"license": "proprietary",
|
"license": "proprietary",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user