mirror of
https://github.com/visioncortex/vtracer.git
synced 2026-09-03 02:46:07 -07:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1adde15f42 | |||
| 2a87d8cf82 | |||
| 3b76f32cd2 | |||
| 148328da45 | |||
| f35df1f6b2 | |||
| f4c7828049 |
@@ -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-16
|
||||||
|
|
||||||
|
* 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)
|
||||||
|
|||||||
+2
-1
@@ -3,4 +3,5 @@
|
|||||||
members = [
|
members = [
|
||||||
"cmdapp",
|
"cmdapp",
|
||||||
"webapp",
|
"webapp",
|
||||||
]
|
]
|
||||||
|
resolver = "2"
|
||||||
+14
-15
@@ -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
|
||||||
|
|||||||
+8
-4
@@ -1,8 +1,8 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "vtracer"
|
name = "vtracer"
|
||||||
version = "0.5.0"
|
version = "0.6.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"]
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
[project]
|
||||||
|
name = "vtracer"
|
||||||
|
version = "0.6.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"]
|
||||||
+5
-1
@@ -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::*;
|
||||||
@@ -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(())
|
||||||
|
}
|
||||||
@@ -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).
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .vtracer import convert_image_to_svg_py
|
||||||
@@ -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:
|
||||||
|
...
|
||||||
Generated
+6
-6
File diff suppressed because one or more lines are too long
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
Generated
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
Copyright (c) 2020 Tsang Hao Fung
|
Copyright (c) 2024 TSANG, Hao Fung
|
||||||
|
|
||||||
The content in the /docs directory is for GitHub pages, and is not covered under open source licenses.
|
The content in the /docs directory is for GitHub pages, and is not covered under open source licenses.
|
||||||
|
|||||||
+58
-58
@@ -61,92 +61,92 @@
|
|||||||
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_new_59cb74e423758ede": function() {
|
/******/ "__wbg_new_abda76e883ba8a5f": function() {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_new_59cb74e423758ede"]();
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_new_abda76e883ba8a5f"]();
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_stack_558ba5917b466edd": function(p0i32,p1i32) {
|
/******/ "__wbg_stack_658279fe44541cf6": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_stack_558ba5917b466edd"](p0i32,p1i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_stack_658279fe44541cf6"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_error_4bb6c2a97407129a": function(p0i32,p1i32) {
|
/******/ "__wbg_error_f851667af71bcfc6": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_error_4bb6c2a97407129a"](p0i32,p1i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_error_f851667af71bcfc6"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_instanceof_Window_adf3196bdc02b386": function(p0i32) {
|
/******/ "__wbg_instanceof_Window_f401953a2cf86220": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_instanceof_Window_adf3196bdc02b386"](p0i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_instanceof_Window_f401953a2cf86220"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_document_6cc8d0b87c0a99b9": function(p0i32) {
|
/******/ "__wbg_document_5100775d18896c16": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_document_6cc8d0b87c0a99b9"](p0i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_document_5100775d18896c16"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_createElementNS_ea14cb45a87a0719": function(p0i32,p1i32,p2i32,p3i32,p4i32) {
|
/******/ "__wbg_createElementNS_556a62fb298be5a2": function(p0i32,p1i32,p2i32,p3i32,p4i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_createElementNS_ea14cb45a87a0719"](p0i32,p1i32,p2i32,p3i32,p4i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_createElementNS_556a62fb298be5a2"](p0i32,p1i32,p2i32,p3i32,p4i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_getElementById_0cb6ad9511b1efc0": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbg_getElementById_c369ff43f0db99cf": function(p0i32,p1i32,p2i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_getElementById_0cb6ad9511b1efc0"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_getElementById_c369ff43f0db99cf"](p0i32,p1i32,p2i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_setAttribute_727bdb9763037624": function(p0i32,p1i32,p2i32,p3i32,p4i32) {
|
/******/ "__wbg_setAttribute_3c9f6c303b696daa": function(p0i32,p1i32,p2i32,p3i32,p4i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_setAttribute_727bdb9763037624"](p0i32,p1i32,p2i32,p3i32,p4i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_setAttribute_3c9f6c303b696daa"](p0i32,p1i32,p2i32,p3i32,p4i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_prepend_fa995bb42f6e2983": function(p0i32,p1i32) {
|
/******/ "__wbg_prepend_6fcfb183e9fe632c": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_prepend_fa995bb42f6e2983"](p0i32,p1i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_prepend_6fcfb183e9fe632c"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_debug_d101e002eb92f20b": function(p0i32,p1i32,p2i32,p3i32) {
|
/******/ "__wbg_instanceof_CanvasRenderingContext2d_20bf99ccc051643b": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_debug_d101e002eb92f20b"](p0i32,p1i32,p2i32,p3i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_instanceof_CanvasRenderingContext2d_20bf99ccc051643b"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_error_cb872335132b1ef7": function(p0i32,p1i32,p2i32,p3i32) {
|
/******/ "__wbg_getImageData_740186e596b34364": function(p0i32,p1f64,p2f64,p3f64,p4f64) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_error_cb872335132b1ef7"](p0i32,p1i32,p2i32,p3i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_getImageData_740186e596b34364"](p0i32,p1f64,p2f64,p3f64,p4f64);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_info_a25afde0ff8cd04a": function(p0i32,p1i32,p2i32,p3i32) {
|
/******/ "__wbg_data_c02d3aac6da15e9f": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_info_a25afde0ff8cd04a"](p0i32,p1i32,p2i32,p3i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_data_c02d3aac6da15e9f"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_log_3bafd82835c6de6d": function(p0i32) {
|
/******/ "__wbg_debug_7d879afce6cf56cb": function(p0i32,p1i32,p2i32,p3i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_log_3bafd82835c6de6d"](p0i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_debug_7d879afce6cf56cb"](p0i32,p1i32,p2i32,p3i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_log_64f566ae90a6c43c": function(p0i32,p1i32,p2i32,p3i32) {
|
/******/ "__wbg_error_696630710900ec44": function(p0i32,p1i32,p2i32,p3i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_log_64f566ae90a6c43c"](p0i32,p1i32,p2i32,p3i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_error_696630710900ec44"](p0i32,p1i32,p2i32,p3i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_warn_f632d7d3f55682b6": function(p0i32,p1i32,p2i32,p3i32) {
|
/******/ "__wbg_info_80803d9a3f0aad16": function(p0i32,p1i32,p2i32,p3i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_warn_f632d7d3f55682b6"](p0i32,p1i32,p2i32,p3i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_info_80803d9a3f0aad16"](p0i32,p1i32,p2i32,p3i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_instanceof_CanvasRenderingContext2d_5b86ec94bce38d5b": function(p0i32) {
|
/******/ "__wbg_log_5bb5f88f245d7762": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_instanceof_CanvasRenderingContext2d_5b86ec94bce38d5b"](p0i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_log_5bb5f88f245d7762"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_getImageData_888c08c04395524a": function(p0i32,p1f64,p2f64,p3f64,p4f64) {
|
/******/ "__wbg_log_151eb4333ef0fe39": function(p0i32,p1i32,p2i32,p3i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_getImageData_888c08c04395524a"](p0i32,p1f64,p2f64,p3f64,p4f64);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_log_151eb4333ef0fe39"](p0i32,p1i32,p2i32,p3i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_instanceof_HtmlCanvasElement_4f5b5ec6cd53ccf3": function(p0i32) {
|
/******/ "__wbg_warn_5d3f783b0bae8943": function(p0i32,p1i32,p2i32,p3i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_instanceof_HtmlCanvasElement_4f5b5ec6cd53ccf3"](p0i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_warn_5d3f783b0bae8943"](p0i32,p1i32,p2i32,p3i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_width_a22f9855caa54b53": function(p0i32) {
|
/******/ "__wbg_instanceof_HtmlCanvasElement_46bdbf323b0b18d1": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_width_a22f9855caa54b53"](p0i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_instanceof_HtmlCanvasElement_46bdbf323b0b18d1"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_height_9a404a6b3c61c7ef": function(p0i32) {
|
/******/ "__wbg_width_aee8b8809b033b05": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_height_9a404a6b3c61c7ef"](p0i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_width_aee8b8809b033b05"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_getContext_37ca0870acb096d9": function(p0i32,p1i32,p2i32) {
|
/******/ "__wbg_height_80053d3c71b338e0": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_getContext_37ca0870acb096d9"](p0i32,p1i32,p2i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_height_80053d3c71b338e0"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_data_c2cd7a48734589b2": function(p0i32,p1i32) {
|
/******/ "__wbg_getContext_df50fa48a8876636": function(p0i32,p1i32,p2i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_data_c2cd7a48734589b2"](p0i32,p1i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_getContext_df50fa48a8876636"](p0i32,p1i32,p2i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_call_8e95613cc6524977": function(p0i32,p1i32) {
|
/******/ "__wbg_newnoargs_e258087cd0daa0ea": function(p0i32,p1i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_call_8e95613cc6524977"](p0i32,p1i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_newnoargs_e258087cd0daa0ea"](p0i32,p1i32);
|
||||||
|
/******/ },
|
||||||
|
/******/ "__wbg_call_27c0f87801dedf93": function(p0i32,p1i32) {
|
||||||
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_call_27c0f87801dedf93"](p0i32,p1i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_object_clone_ref"](p0i32);
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_newnoargs_f3b8a801d5d4b079": function(p0i32,p1i32) {
|
/******/ "__wbg_self_ce0dbfc45cf2f5be": function() {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_newnoargs_f3b8a801d5d4b079"](p0i32,p1i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_self_ce0dbfc45cf2f5be"]();
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_self_07b2f89e82ceb76d": function() {
|
/******/ "__wbg_window_c6fb939a7f436783": function() {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_self_07b2f89e82ceb76d"]();
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_window_c6fb939a7f436783"]();
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_window_ba85d88572adc0dc": function() {
|
/******/ "__wbg_globalThis_d1e6af4856ba331b": function() {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_window_ba85d88572adc0dc"]();
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_globalThis_d1e6af4856ba331b"]();
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbg_globalThis_b9277fc37e201fe5": function() {
|
/******/ "__wbg_global_207b558942527489": function() {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_globalThis_b9277fc37e201fe5"]();
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_global_207b558942527489"]();
|
||||||
/******/ },
|
|
||||||
/******/ "__wbg_global_e16303fe83e1d57f": function() {
|
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_global_e16303fe83e1d57f"]();
|
|
||||||
/******/ },
|
/******/ },
|
||||||
/******/ "__wbindgen_is_undefined": function(p0i32) {
|
/******/ "__wbindgen_is_undefined": function(p0i32) {
|
||||||
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_is_undefined"](p0i32);
|
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_is_undefined"](p0i32);
|
||||||
@@ -258,7 +258,7 @@
|
|||||||
/******/ promises.push(installedWasmModuleData);
|
/******/ promises.push(installedWasmModuleData);
|
||||||
/******/ else {
|
/******/ else {
|
||||||
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
/******/ var importObject = wasmImportObjects[wasmModuleId]();
|
||||||
/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/vtracer_webapp_bg.wasm":"589cb57662b50620abca"}[wasmModuleId] + ".module.wasm");
|
/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/vtracer_webapp_bg.wasm":"1ea3f1b97c566154f2b2"}[wasmModuleId] + ".module.wasm");
|
||||||
/******/ var promise;
|
/******/ var promise;
|
||||||
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
|
||||||
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
|
||||||
|
|||||||
Generated
+166
-8
@@ -11,12 +11,14 @@
|
|||||||
<!-- UIkit JS -->
|
<!-- UIkit JS -->
|
||||||
<script src="./uikit/js/uikit.min.js"></script>
|
<script src="./uikit/js/uikit.min.js"></script>
|
||||||
<script src="./uikit/js/uikit-icons.min.js"></script>
|
<script src="./uikit/js/uikit-icons.min.js"></script>
|
||||||
<script type="text/javascript">
|
<!-- Google tag (gtag.js) -->
|
||||||
(function(c,l,a,r,i,t,y){
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XPL1JGMDSC"></script>
|
||||||
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
|
<script>
|
||||||
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
|
window.dataLayer = window.dataLayer || [];
|
||||||
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
|
function gtag(){dataLayer.push(arguments);}
|
||||||
})(window, document, "clarity", "script", "403biw7tra");
|
gtag('js', new Date());
|
||||||
|
|
||||||
|
gtag('config', 'G-XPL1JGMDSC');
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html, body {
|
||||||
@@ -128,6 +130,35 @@
|
|||||||
.uk-text-meta {
|
.uk-text-meta {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
.desktop-banner {
|
||||||
|
border: 1px solid rgba(204, 151, 46, 0.55);
|
||||||
|
background: rgba(204, 151, 46, 0.12);
|
||||||
|
gap: 8px 16px;
|
||||||
|
padding-top: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
.desktop-banner-title {
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.desktop-banner-copy {
|
||||||
|
margin: 4px 0 0 0;
|
||||||
|
}
|
||||||
|
.desktop-banner .uk-button {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.uk-light .desktop-banner {
|
||||||
|
border-color: rgba(204, 151, 46, 0.7);
|
||||||
|
background: rgba(204, 151, 46, 0.16);
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 640px) {
|
||||||
|
.desktop-banner {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.desktop-banner .uk-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -142,13 +173,21 @@
|
|||||||
/ VTracer
|
/ VTracer
|
||||||
</div>
|
</div>
|
||||||
<div class="uk-navbar-right uk-padding-small">
|
<div class="uk-navbar-right uk-padding-small">
|
||||||
<a class="uk-button uk-button-default" href="//www.visioncortex.org/vtracer-docs">Article</a>
|
|
||||||
|
|
||||||
<a class="uk-button uk-button-default" href="//github.com/visioncortex/vtracer">GitHub</a>
|
<a class="uk-button uk-button-default" href="//github.com/visioncortex/vtracer">GitHub</a>
|
||||||
|
|
||||||
<a id="export" class="uk-button uk-button-primary">Download as SVG</a>
|
<a id="export" class="uk-button uk-button-primary">Download as SVG</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="uk-width-1-1">
|
||||||
|
<div class="desktop-banner uk-padding-small uk-flex uk-flex-middle uk-flex-between uk-flex-wrap">
|
||||||
|
<div class="uk-margin-small-right">
|
||||||
|
<p id="desktop-banner-copy" class="desktop-banner-title">Try the latest VTracer Desktop App for native speed, curve simplification, and higher tracing quality.</p>
|
||||||
|
</div>
|
||||||
|
<a id="desktop-download" class="uk-button uk-button-primary" href="https://github.com/visioncortex/vtracer/releases/latest" rel="noopener">
|
||||||
|
Download Desktop App
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="progressregion" class="uk-width-1-1 uk-padding-small" style="display: none;">
|
<div id="progressregion" class="uk-width-1-1 uk-padding-small" style="display: none;">
|
||||||
<progress id="progressbar" class="uk-progress uk-align-right" value="0" max="100" style="width: 98%;"></progress>
|
<progress id="progressbar" class="uk-progress uk-align-right" value="0" max="100" style="width: 98%;"></progress>
|
||||||
</div>
|
</div>
|
||||||
@@ -314,6 +353,125 @@
|
|||||||
document.body.classList.remove('uk-dark');
|
document.body.classList.remove('uk-dark');
|
||||||
document.body.classList.add('uk-light');
|
document.body.classList.add('uk-light');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var releasesUrl = 'https://github.com/visioncortex/vtracer/releases/latest';
|
||||||
|
var manifestUrl = 'https://raw.githubusercontent.com/visioncortex/vtracer/desktop-updates/latest.json';
|
||||||
|
var downloadLink = document.getElementById('desktop-download');
|
||||||
|
var bannerCopy = document.getElementById('desktop-banner-copy');
|
||||||
|
|
||||||
|
function detectPlatform() {
|
||||||
|
var platform = navigator.userAgentData && navigator.userAgentData.platform
|
||||||
|
? navigator.userAgentData.platform
|
||||||
|
: navigator.platform || '';
|
||||||
|
var userAgent = navigator.userAgent || '';
|
||||||
|
var platformText = platform + ' ' + userAgent;
|
||||||
|
|
||||||
|
if (/Windows/i.test(platformText)) {
|
||||||
|
return {
|
||||||
|
label: 'Windows',
|
||||||
|
manifestKeys: ['windows-x86_64']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/Mac|Darwin/i.test(platformText) && !/iPhone|iPad|iPod/i.test(userAgent)) {
|
||||||
|
return {
|
||||||
|
label: 'macOS',
|
||||||
|
manifestKeys: ['macos-universal', 'darwin-universal', 'darwin-aarch64', 'darwin-x86_64']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/Linux|X11/i.test(platformText) && !/Android/i.test(userAgent)) {
|
||||||
|
return {
|
||||||
|
label: 'Linux',
|
||||||
|
manifestKeys: ['linux-x86_64']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: '',
|
||||||
|
manifestKeys: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFallback(platform) {
|
||||||
|
downloadLink.href = releasesUrl;
|
||||||
|
downloadLink.textContent = platform.label ? 'Download for ' + platform.label : 'View latest downloads';
|
||||||
|
bannerCopy.textContent = platform.label
|
||||||
|
? 'Try the latest VTracer Desktop App for ' + platform.label + ' with native speed, curve simplification, and higher tracing quality.'
|
||||||
|
: 'Try the latest VTracer Desktop App for native speed, curve simplification, and higher tracing quality.';
|
||||||
|
}
|
||||||
|
|
||||||
|
function findPlatformDownload(platforms, platform) {
|
||||||
|
var keys = platform.manifestKeys || [];
|
||||||
|
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
if (platforms[keys[i]] && platforms[keys[i]].url) {
|
||||||
|
return platforms[keys[i]].url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function publicDownloadUrl(platform, updaterUrl) {
|
||||||
|
if (platform.label !== 'macOS' || !updaterUrl) {
|
||||||
|
return updaterUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The manifest points at Tauri's updater bundle; a person wants the
|
||||||
|
// disk image sitting beside it. Rewrite only the filename, so the
|
||||||
|
// release tag comes from the URL we were handed: manifest.version
|
||||||
|
// carries a build suffix the tag does not, and building the URL from
|
||||||
|
// it 404s (version '1.0.0-alpha.3.app.59' lives under tag
|
||||||
|
// '1.0.0-alpha.3').
|
||||||
|
return updaterUrl.replace(/\.app\.tar\.gz$/i, '.dmg');
|
||||||
|
}
|
||||||
|
|
||||||
|
var platform = detectPlatform();
|
||||||
|
setFallback(platform);
|
||||||
|
|
||||||
|
downloadLink.addEventListener('click', function() {
|
||||||
|
if (typeof gtag !== 'function') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtag('event', 'desktop_download_click', {
|
||||||
|
platform: platform.label || 'unknown',
|
||||||
|
source: 'docs_banner',
|
||||||
|
download_url: downloadLink.href,
|
||||||
|
transport_type: 'beacon'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!window.fetch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(manifestUrl)
|
||||||
|
.then(function(response) {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Desktop manifest lookup failed');
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(function(manifest) {
|
||||||
|
var updaterUrl = findPlatformDownload(manifest.platforms || {}, platform);
|
||||||
|
var downloadUrl = publicDownloadUrl(platform, updaterUrl);
|
||||||
|
|
||||||
|
if (!downloadUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadLink.href = downloadUrl;
|
||||||
|
downloadLink.textContent = 'Download for ' + platform.label;
|
||||||
|
|
||||||
|
bannerCopy.textContent = 'Try the latest VTracer Desktop App for ' + platform.label + ' with native speed, curve simplification, and higher tracing quality.';
|
||||||
|
})
|
||||||
|
.catch(function() {
|
||||||
|
setFallback(platform);
|
||||||
|
});
|
||||||
|
})();
|
||||||
</script>
|
</script>
|
||||||
<script src="./bootstrap.js"></script>
|
<script src="./bootstrap.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+3
-3
@@ -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"
|
||||||
@@ -22,7 +22,7 @@ console_log = { version = "0.2", features = ["color"] }
|
|||||||
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
visioncortex = "0.6.0"
|
visioncortex = "0.8.1"
|
||||||
|
|
||||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||||
# logging them with `console.error`. This is great for development, but requires
|
# logging them with `console.error`. This is great for development, but requires
|
||||||
|
|||||||
+6
-2
@@ -35,7 +35,11 @@ document.addEventListener('paste', function (e) {
|
|||||||
|
|
||||||
// Download as SVG
|
// Download as SVG
|
||||||
document.getElementById('export').addEventListener('click', function (e) {
|
document.getElementById('export').addEventListener('click', function (e) {
|
||||||
const blob = new Blob([new XMLSerializer().serializeToString(svg)], {type: 'octet/stream'}),
|
const blob = new Blob([
|
||||||
|
`<?xml version="1.0" encoding="UTF-8"?>\n`,
|
||||||
|
`<!-- Generator: visioncortex VTracer -->\n`,
|
||||||
|
new XMLSerializer().serializeToString(svg)
|
||||||
|
], {type: 'octet/stream'}),
|
||||||
url = window.URL.createObjectURL(blob);
|
url = window.URL.createObjectURL(blob);
|
||||||
|
|
||||||
this.href = url;
|
this.href = url;
|
||||||
@@ -444,7 +448,7 @@ class ConverterRunner {
|
|||||||
this.converter.init();
|
this.converter.init();
|
||||||
this.stopped = false;
|
this.stopped = false;
|
||||||
if (clustering_mode == 'binary') {
|
if (clustering_mode == 'binary') {
|
||||||
svg.style.background = '#000';
|
svg.style.background = '#fff';
|
||||||
canvas.style.display = 'none';
|
canvas.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
svg.style.background = '';
|
svg.style.background = '';
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ impl BinaryImageConverter {
|
|||||||
self.params.max_iterations,
|
self.params.max_iterations,
|
||||||
self.params.splice_threshold
|
self.params.splice_threshold
|
||||||
);
|
);
|
||||||
let color = Color::color(&ColorName::White);
|
let color = Color::color(&ColorName::Black);
|
||||||
self.svg.prepend_path(
|
self.svg.prepend_path(
|
||||||
&paths,
|
&paths,
|
||||||
&color,
|
&color,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use visioncortex::PathSimplifyMode;
|
use visioncortex::PathSimplifyMode;
|
||||||
use visioncortex::color_clusters::{IncrementalBuilder, Clusters, Runner, RunnerConfig, HIERARCHICAL_MAX};
|
use visioncortex::color_clusters::{Clusters, Runner, RunnerConfig, HIERARCHICAL_MAX, IncrementalBuilder, KeyingAction};
|
||||||
|
|
||||||
use crate::canvas::*;
|
use crate::canvas::*;
|
||||||
use crate::svg::*;
|
use crate::svg::*;
|
||||||
@@ -78,6 +78,8 @@ impl ColorImageConverter {
|
|||||||
is_same_color_b: 1,
|
is_same_color_b: 1,
|
||||||
deepen_diff: self.params.layer_difference,
|
deepen_diff: self.params.layer_difference,
|
||||||
hollow_neighbours: 1,
|
hollow_neighbours: 1,
|
||||||
|
key_color: Default::default(),
|
||||||
|
keying_action: KeyingAction::Discard,
|
||||||
}, image);
|
}, image);
|
||||||
self.stage = Stage::Clustering(runner.start());
|
self.stage = Stage::Clustering(runner.start());
|
||||||
}
|
}
|
||||||
@@ -108,6 +110,8 @@ impl ColorImageConverter {
|
|||||||
is_same_color_b: 1,
|
is_same_color_b: 1,
|
||||||
deepen_diff: 0,
|
deepen_diff: 0,
|
||||||
hollow_neighbours: 0,
|
hollow_neighbours: 0,
|
||||||
|
key_color: Default::default(),
|
||||||
|
keying_action: KeyingAction::Discard,
|
||||||
}, image);
|
}, image);
|
||||||
self.stage = Stage::Reclustering(runner.start());
|
self.stage = Stage::Reclustering(runner.start());
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user