mirror of
https://github.com/visioncortex/vtracer.git
synced 2026-09-25 13:31:27 -07:00
Expose simplify in the Python and Node bindings
Config(simplify=...) / property in Python; simplify option in Node, with the tolerance documented in .pyi, index.d.ts, and both READMEs. The Node README's option list also catches up with the clustering rename and the binary/watershed options, and test.js drops the stale colorMode key (silently ignored since the rename, so its bw assertion was testing the default path) and asserts simplify shrinks output.
This commit is contained in:
@@ -51,10 +51,11 @@ properties, plus the presets `Config.bw()`, `Config.poster()`, `Config.photo()`:
|
|||||||
| `length_threshold` | `4.0` | px |
|
| `length_threshold` | `4.0` | px |
|
||||||
| `max_iterations` | `10` | |
|
| `max_iterations` | `10` | |
|
||||||
| `splice_threshold` | `45` | degrees |
|
| `splice_threshold` | `45` | degrees |
|
||||||
|
| `simplify` | `None` | curve simplification tolerance in px (try 1–2.5) |
|
||||||
| `path_precision` | `2` | output decimal places |
|
| `path_precision` | `2` | output decimal places |
|
||||||
| `palette` | `None` | list of `#rrggbb` strings |
|
| `palette` | `None` | list of `#rrggbb` strings |
|
||||||
| `max_colors` | `None` | auto-quantize target |
|
| `max_colors` | `None` | auto-quantize target |
|
||||||
| `optimize` | `1` | `0` off, `1` quantize+simplify, `2` + shorthands |
|
| `optimize` | `1` | `0` off, `1` quantize+cleanup, `2` + shorthands |
|
||||||
| `binary_threshold` | `128` | bw: fixed cutoff, foreground below it |
|
| `binary_threshold` | `128` | bw: fixed cutoff, foreground below it |
|
||||||
| `adaptive` | `False` | bw: Bradley–Roth adaptive thresholding |
|
| `adaptive` | `False` | bw: Bradley–Roth adaptive thresholding |
|
||||||
| `adaptive_window` | `0` | bw adaptive: window px (`0` = auto) |
|
| `adaptive_window` | `0` | bw adaptive: window px (`0` = auto) |
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ impl PyConfig {
|
|||||||
length_threshold = 4.0,
|
length_threshold = 4.0,
|
||||||
max_iterations = 10,
|
max_iterations = 10,
|
||||||
splice_threshold = 45,
|
splice_threshold = 45,
|
||||||
|
simplify = None,
|
||||||
path_precision = 2,
|
path_precision = 2,
|
||||||
palette = None,
|
palette = None,
|
||||||
max_colors = None,
|
max_colors = None,
|
||||||
@@ -162,6 +163,7 @@ impl PyConfig {
|
|||||||
length_threshold: f64,
|
length_threshold: f64,
|
||||||
max_iterations: usize,
|
max_iterations: usize,
|
||||||
splice_threshold: i32,
|
splice_threshold: i32,
|
||||||
|
simplify: Option<f64>,
|
||||||
path_precision: u32,
|
path_precision: u32,
|
||||||
palette: Option<Vec<String>>,
|
palette: Option<Vec<String>>,
|
||||||
max_colors: Option<usize>,
|
max_colors: Option<usize>,
|
||||||
@@ -188,8 +190,7 @@ impl PyConfig {
|
|||||||
length_threshold,
|
length_threshold,
|
||||||
max_iterations,
|
max_iterations,
|
||||||
splice_threshold,
|
splice_threshold,
|
||||||
// Curve simplification is not surfaced in the Python API yet.
|
simplify,
|
||||||
simplify: None,
|
|
||||||
path_precision: Some(path_precision),
|
path_precision: Some(path_precision),
|
||||||
palette,
|
palette,
|
||||||
max_colors,
|
max_colors,
|
||||||
@@ -331,6 +332,15 @@ impl PyConfig {
|
|||||||
self.inner.splice_threshold = v;
|
self.inner.splice_threshold = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[getter]
|
||||||
|
fn simplify(&self) -> Option<f64> {
|
||||||
|
self.inner.simplify
|
||||||
|
}
|
||||||
|
#[setter]
|
||||||
|
fn set_simplify(&mut self, v: Option<f64>) {
|
||||||
|
self.inner.simplify = v;
|
||||||
|
}
|
||||||
|
|
||||||
#[getter]
|
#[getter]
|
||||||
fn path_precision(&self) -> Option<u32> {
|
fn path_precision(&self) -> Option<u32> {
|
||||||
self.inner.path_precision
|
self.inner.path_precision
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class Config:
|
|||||||
length_threshold: float = 4.0,
|
length_threshold: float = 4.0,
|
||||||
max_iterations: int = 10,
|
max_iterations: int = 10,
|
||||||
splice_threshold: int = 45,
|
splice_threshold: int = 45,
|
||||||
|
simplify: Optional[float] = None, # curve simplification tolerance in px (None = off)
|
||||||
path_precision: int = 2,
|
path_precision: int = 2,
|
||||||
palette: Optional[list[str]] = None, # e.g. ["#112233", "#445566"]
|
palette: Optional[list[str]] = None, # e.g. ["#112233", "#445566"]
|
||||||
max_colors: Optional[int] = None, # auto-quantize target
|
max_colors: Optional[int] = None, # auto-quantize target
|
||||||
@@ -46,6 +47,7 @@ class Config:
|
|||||||
length_threshold: float
|
length_threshold: float
|
||||||
max_iterations: int
|
max_iterations: int
|
||||||
splice_threshold: int
|
splice_threshold: int
|
||||||
|
simplify: Optional[float]
|
||||||
path_precision: Optional[int]
|
path_precision: Optional[int]
|
||||||
palette: list[str]
|
palette: list[str]
|
||||||
max_colors: Optional[int]
|
max_colors: Optional[int]
|
||||||
|
|||||||
+8
-5
@@ -37,11 +37,14 @@ const svg2 = vtracer.convertPixels(rgba, width, height, { clustering: 'bw' });
|
|||||||
### `Options` (all optional, camelCase)
|
### `Options` (all optional, camelCase)
|
||||||
|
|
||||||
`preset` (`"bw" | "poster" | "photo"`, applied first), `clustering`
|
`preset` (`"bw" | "poster" | "photo"`, applied first), `clustering`
|
||||||
(`"color" | "bw"`), `hierarchical` (`"stacked" | "cutout"` for the seam-free
|
(`"color-cluster" | "bw" | "watershed"`), `hierarchical` (`"stacked" | "cutout"`
|
||||||
mosaic), `mode` (`"pixel" | "polygon" | "spline"`), `filterSpeckle`,
|
for the seam-free mosaic), `mode` (`"pixel" | "polygon" | "spline"`),
|
||||||
`colorPrecision`, `layerDifference`, `cornerThreshold`, `lengthThreshold`,
|
`filterSpeckle`, `colorPrecision`, `layerDifference`, `cornerThreshold`,
|
||||||
`maxIterations`, `spliceThreshold`, `pathPrecision`, `palette` (list of
|
`lengthThreshold`, `maxIterations`, `spliceThreshold`, `simplify` (curve
|
||||||
`#rrggbb`), `maxColors`, `optimize` (`0 | 1 | 2`).
|
simplification tolerance in px, try 1–2.5), `pathPrecision`, `palette` (list of
|
||||||
|
`#rrggbb`), `maxColors`, `optimize` (`0 | 1 | 2`), `binaryThreshold` /
|
||||||
|
`adaptive` / `adaptiveWindow` / `adaptiveT` (binary mode), `watershedDetail`
|
||||||
|
(0..=255).
|
||||||
|
|
||||||
## Build from source
|
## Build from source
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
@@ -13,6 +13,8 @@ export interface Options {
|
|||||||
lengthThreshold?: number;
|
lengthThreshold?: number;
|
||||||
maxIterations?: number;
|
maxIterations?: number;
|
||||||
spliceThreshold?: number;
|
spliceThreshold?: number;
|
||||||
|
/** Curve simplification tolerance in px (omit = off; try 1-2.5). */
|
||||||
|
simplify?: number;
|
||||||
pathPrecision?: number;
|
pathPrecision?: number;
|
||||||
/** Fixed palette: `#rrggbb` strings. */
|
/** Fixed palette: `#rrggbb` strings. */
|
||||||
palette?: string[];
|
palette?: string[];
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ struct Options {
|
|||||||
length_threshold: Option<f64>,
|
length_threshold: Option<f64>,
|
||||||
max_iterations: Option<usize>,
|
max_iterations: Option<usize>,
|
||||||
splice_threshold: Option<i32>,
|
splice_threshold: Option<i32>,
|
||||||
|
/// Curve simplification tolerance in px (omit = off).
|
||||||
|
simplify: Option<f64>,
|
||||||
path_precision: Option<u32>,
|
path_precision: Option<u32>,
|
||||||
palette: Option<Vec<String>>,
|
palette: Option<Vec<String>>,
|
||||||
max_colors: Option<usize>,
|
max_colors: Option<usize>,
|
||||||
@@ -104,6 +106,9 @@ fn config_from(options: JsValue) -> Result<Config, JsValue> {
|
|||||||
if let Some(v) = opts.splice_threshold {
|
if let Some(v) = opts.splice_threshold {
|
||||||
config.splice_threshold = v;
|
config.splice_threshold = v;
|
||||||
}
|
}
|
||||||
|
if let Some(v) = opts.simplify {
|
||||||
|
config.simplify = Some(v);
|
||||||
|
}
|
||||||
if let Some(v) = opts.path_precision {
|
if let Some(v) = opts.path_precision {
|
||||||
config.path_precision = Some(v);
|
config.path_precision = Some(v);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -12,11 +12,19 @@ let svg = vtracer.convertBuffer(data);
|
|||||||
assert(svg.includes('<svg') && svg.includes('<path'), 'default convertBuffer');
|
assert(svg.includes('<svg') && svg.includes('<path'), 'default convertBuffer');
|
||||||
console.log('convertBuffer default:', (svg.match(/<path/g) || []).length, 'paths');
|
console.log('convertBuffer default:', (svg.match(/<path/g) || []).length, 'paths');
|
||||||
|
|
||||||
// options: bw preset -> all black
|
// options: bw clustering -> all black
|
||||||
svg = vtracer.convertBuffer(data, { colorMode: 'bw' });
|
svg = vtracer.convertBuffer(data, { clustering: 'bw' });
|
||||||
assert(svg.includes('fill="#000000"'), 'bw produces black');
|
assert(svg.includes('fill="#000000"'), 'bw produces black');
|
||||||
console.log('convertBuffer bw:', (svg.match(/<path/g) || []).length, 'paths');
|
console.log('convertBuffer bw:', (svg.match(/<path/g) || []).length, 'paths');
|
||||||
|
|
||||||
|
// curve simplification shrinks the output
|
||||||
|
{
|
||||||
|
const plain = vtracer.convertBuffer(data);
|
||||||
|
const simplified = vtracer.convertBuffer(data, { simplify: 2 });
|
||||||
|
assert(simplified.length < plain.length, 'simplify shrinks output');
|
||||||
|
console.log('convertBuffer simplify:', plain.length, '->', simplified.length, 'bytes');
|
||||||
|
}
|
||||||
|
|
||||||
// options: mosaic + polygon + palette
|
// options: mosaic + polygon + palette
|
||||||
svg = vtracer.convertBuffer(data, { hierarchical: 'cutout', mode: 'polygon', palette: ['#000000', '#ffffff'], optimize: 2 });
|
svg = vtracer.convertBuffer(data, { hierarchical: 'cutout', mode: 'polygon', palette: ['#000000', '#ffffff'], optimize: 2 });
|
||||||
assert(svg.includes('<svg'), 'mosaic+palette');
|
assert(svg.includes('<svg'), 'mosaic+palette');
|
||||||
|
|||||||
Reference in New Issue
Block a user