206 Commits

Author SHA1 Message Date
Chris Tsang 74c29b1a8c Release app 2026-08-29 22:27:11 +01:00
Chris Tsang 5a69ee33a8 Changelog 2026-08-29 22:14:25 +01:00
Chris Tsang 2500df76b5 Release 1.0.0-alpha.4
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
Bump every package version to 1.0.0-alpha.4 (PyPI 1.0.0a4) and promote the
CHANGELOG [Unreleased] section to 1.0.0-alpha.4. Refresh the tracked lockfile.
App download links are intentionally left at 1.0.0-alpha.3 (desktop app
release lands separately).
2026-08-29 01:02:58 +01:00
Chris Tsang 1ddc9ebbf7 CHANGELOG: note uncapped --watershed-detail under Unreleased
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
2026-08-15 12:36:01 +01:00
Chris Tsang 327e4b175f Track the workspace Cargo.lock
The workspace ships binaries (vtracer-cli, vtracer-bench, the desktop app
via CI), so a committed lockfile gives reproducible builds. Downstream
consumers of the vtracer library ignore this lock, so it does not pin them.
Nested crate lockfiles (nodejs, vtracer-py, webapp) stay ignored.
2026-08-15 12:35:26 +01:00
Chris Tsang 1adc60aa0d Bump visioncortex to 0.9.3
Minor upstream bug fix. No traced-output change (golden tests unchanged);
full workspace suite passes.
2026-08-15 12:30:31 +01:00
Chris Tsang d413a28779 Mark desktop app build 59 2026-08-14 16:41:00 +01:00
Chris Tsang f01c709cd1 App update 2026-08-14 16:16:56 +01:00
Chris Tsang e4210e926c README: pin version badges to blue (avoid prerelease orange) 2026-08-12 20:46:30 +01:00
Chris Tsang 712ce3bf50 readme
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
2026-08-08 22:41:10 +01:00
Chris Tsang 845f6a1ed1 remove web app 2026-08-08 22:25:35 +01:00
Chris Tsang 74da0efb84 Uncap watershed detail in the Node binding + sync docs
`6f163fc` widened watershed_detail from u8 to u32 in the core, CLI, and
Python binding but not the Node/wasm binding, which still assigned a u8 to
config.watershed_detail — a wasm build error (E0308). Widen the Node
Options field to u32 and refresh every "0..=255" watershed doc (CLI help,
Config field, .pyi, index.d.ts, and all three READMEs) to reflect that the
level is now uncapped (default 128; higher = more regions).
2026-08-08 21:50:55 +01:00
Chris Tsang 0d77ecf6f9 new app 2026-08-08 21:48:48 +01:00
Chris Tsang 6f163fcf7d Uncap watershed details 2026-08-06 16:14:44 +01:00
Chris Tsang febcc28920 Improve core lib docs for docs.rs
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
- lib.rs: rewrite the crate landing page — single-line pipeline diagram,
  define the Segmentation/VectorDoc IRs, stage->trait->module table with
  intra-doc links, and Quick start / Interactive tuning / Extending /
  wasm-safe sections.
- config.rs: fix stale Hierarchical::Cutout doc (it is the implemented
  seam-free mosaic, not "not yet implemented"); document the previously
  bare Hierarchical/FitMode/Preset enums and variants, the hierarchical/
  mode/max_iterations fields, and from_preset.
- frontend: surface adaptive thresholding — BinaryFrontend module bullet
  and struct doc now point at Threshold::Fixed / Threshold::Adaptive.
- error.rs: add the missing module-level doc.
- Fix two pre-existing rustdoc link warnings (private-item link in
  config.rs, redundant explicit target in session.rs); crate now
  documents warning-free under -D warnings.
2026-08-02 02:41:45 +01:00
Chris Tsang bf9858e359 Readme 2026-08-02 02:24:15 +01:00
Chris Tsang 7d754e17c3 publish script 2026-08-01 23:42:47 +01:00
Chris Tsang 58221025d5 Prepare 1.0.0-alpha.3 release
- version 1.0.0-alpha.3 across the workspace, Python, and Node packages
  (and the vtracer dep pins, install snippets, and docs.rs link)
- CHANGELOG: date the section; note the new vtracer-bench crate and the
  watershed blurred-crack filament fix

(Supersampling was explored after alpha.2 and reverted -- it did not
improve output enough to keep.)
2026-08-01 21:22:33 +01:00
Chris Tsang 4a7820bf03 Snap gate: admit blends of two neighbouring regions
The mixture gate only tested betweenness against the pixel's OWN region
and the flip candidate, so a pixel blending two foreign flanks could
never flip: on a blurred low-contrast crack the basin cut leaks a
distant region along the crack's blend band as a 1-px filament (the
striped synthetic under 1.2 px blur grows a 30 px hairline of the
circle's red along a stripe boundary), and the snap visited it every
sweep yet was forbidden to fix it. A pixel that reads as a blend of two
neighbouring regions now flips to the closer of them; genuine third
colors (outline strokes) still fail betweenness against every pair and
stay put.

Blurred synthetic circle: max boundary error 31.6 -> 1.5 px, rms
5.6 -> 0.7. Crisp images byte-unaffected (fidelity 0.9261 unchanged);
all watershed property tests pass unchanged.
2026-08-01 01:44:23 +01:00
Chris Tsang ae6731017f add vtracer-bench 2026-08-01 01:44:23 +01:00
Chris Tsang f9112c5ba9 Ship the Python README as the PyPI description
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
The `vtracer` package never declared a `readme`, so its PyPI page rendered
an empty description. Point `[project].readme` at the crate's README, and
mirror it in Cargo.toml alongside the core crate's convention.

Pin the documented install to 1.0.0a2 while the 1.0 line is pre-release:
`--pre` would resolve it, but a bare `pip install vtracer` still lands on
0.6.15, whose cp314 wheels segfault on any keyword argument (pyo3 0.19
predates CPython 3.14 moving `PyTupleObject::ob_item`, #124).
2026-07-31 16:35:01 +01:00
Chris Tsang 222cc6cbff Prepare 1.0.0-alpha.2 release
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
- version 1.0.0-alpha.2 across the workspace, Python, and Node packages
- CHANGELOG: date the unreleased section
- README: bump install snippets and docs.rs link
2026-07-27 23:20:26 +01:00
Chris Tsang f4fe428038 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.
2026-07-27 23:19:42 +01:00
Chris Tsang 640270a608 Reword the desktop app feature list
Each bullet leads with the feature and states the user-visible win.
Native speed (vs the old wasm webapp), the A/B sliding comparator, and
the curve inspector head the list; watershed clustering and curve
simplification join from the 1.0 engine.
2026-07-27 23:13:16 +01:00
Chris Tsang 87dd8f5168 Tidy the unreleased changelog
Watershed leads with its sub-features as nested bullets instead of one
paragraph-length entry; every bullet trimmed to its user-visible point.
2026-07-27 23:07:29 +01:00
Chris Tsang 2ef4bfb619 Hide the spline fine-tuning flags from CLI help
--corner-threshold, --segment-length, and --splice-threshold are still
accepted but no longer listed, and their -c/-l/-s short forms are gone:
the defaults serve virtually every conversion, and --simplify supersedes
them as the knob that actually moves output size (sweeping segment
length 3.5..=10 shifts the sample photo by 25% alone but under 2% once
simplify is on). README options block synced with the new help text.
2026-07-27 23:04:00 +01:00
Chris Tsang ef9496f792 Add a curve-simplification stage (--simplify), paper.js style
A new pipeline slot between curve fitting and composition: CurvePasses
rewrite each fitted contour, so mosaic mode transforms every shared
boundary segment exactly once and the tessellation stays seam-free by
construction. SimplifyCurves re-fits each smooth run between corners
with the fewest cubics within the tolerance (Schneider's algorithm via
a current flo_curves — visioncortex's copy is pinned to an old one and
block-splits at 200 points), with tangents from the chain's own ends,
corners kept in place, junction endpoints pinned bit-for-bit, and rings
seamed at their sharpest junction. Off by default; polylines pass
through untouched. Cityscape at tolerance 1: 229 -> 138 KB stacked,
103 -> 36 KB watershed cutout, with render diffs under golden noise.

CurveFitter now returns Vec<FittedGeom> (promoted from mosaic::fit) so
stacked contours flow through the same pass machinery; the optimizer's
SimplifyPass is renamed CleanupPass to free the word.
2026-07-27 22:30:05 +01:00
Chris Tsang d585984e78 Derive the watershed cutout merge tolerance from the detail dial
The detail dial has no color units - it targets a region count
(2^(detail/25.5)) and the cut threshold is volume persistence - so a
cutout merge tolerance cannot fall out of it dimensionally. Anchor it
instead: at max detail the user asked for every distinction the hierarchy
can make (merge only identical colors, as before), and at the default
detail (128) it matches the color-cluster default gradient step (16),
which is the tolerance the cutout merge was designed around. Linear in
between: merge_diff = (255 - detail) / 8, reaching 1 at detail 247.

Floor the watershed cutout merge tolerance at a just-noticeable difference

Faces a human cannot tell apart (e.g. #863339 next to #863238, 2 L1
apart) are pointless as separate patches at any detail, so the derived
tolerance becomes max(2, (255 - detail) / 8): the 248..=255 band merges
sub-JND neighbours instead of nothing. The default-detail anchor (16, the
color-cluster default gradient step) is unchanged. Cityscape cutout at
max detail: 992 faces down to 886.
2026-07-27 21:26:49 +01:00
Chris Tsang 9650808263 Snap watershed boundaries to the color-midpoint iso-line
Inside an antialiasing ramp (or JPEG halo) the per-pixel differences are
near-equal, so the minimum-spanning-forest cut meanders +-1-2 px with the
pixel noise and the fitted curves visibly wave. After the cut, boundary
pixels whose color is a mixture of the two adjacent region means are
re-assigned to the closer mean - the same rule color quantization applies,
which is why the color-cluster frontend never showed this. A mixture gate
keeps genuine third-color detail (e.g. dark outline strokes) with its
basin, and crisp synthetic edges are untouched (goldens unchanged).

The merge-tree replay now walks the full edge order: snapping can leave a
region's only adjacency running through a below-cut edge, and skipping
those left the tree unconnected. Costs ~6 ms on a 1400x775 cut (~30 ms
before, ~36 ms after); the first sweep scans the canvas, later sweeps
revisit only the moving front.

Absorb the fragments boundary snapping pinches off

A snap flip can strand a pixel (its supporting neighbour flips away in the
same sweep) or sever a thin strand of its source region. Watershed basins
are connected by construction and the mosaic gives every disjoint patch its
own face, so this debris surfaced in cutout mode as 1-px micro-faces wedged
between the real faces - visually gapless, but neighbours no longer shared
a fitted boundary (62 chips on the Cityscape sample, some with degenerate
zero-area outlines).

After the sweeps, flood every touched component with a small cap: one that
is disconnected from the rest of its region and fits under the floor moves
wholesale to the adjacent region with the closest mean. Substantial patches
severed at a thin antialiased neck stay - they make coherent faces of their
own, and recoloring them would be visible. Seeded by the sweep fronts, so
the cost is proportional to the flips, not the canvas (cut stays ~36 ms).

Cityscape cutout: 95 faces back down to 33 (32 pre-snap), zero coverage
gaps. Guarded by snap_leaves_no_debris on the real photo (smallest patch
was 1 px before, 147 patches; now every patch clears the speckle floor).
2026-07-27 21:26:49 +01:00
Chris Tsang 93a9939587 fix webapp 2026-07-27 19:56:03 +01:00
Chris Tsang 6671d7d45e Fix spline ballooning on sparse slices (visioncortex 0.9.1)
A splice slice with very uneven point spacing — a few-pixel jog followed
by a long straight leg, which the walker produces around thin strands —
was fitted by a single cubic that interpolated every sample exactly while
swinging up to ~30 px sideways between them (the fit error was only
measured at the samples). On the Cityscape sample at -p 8 -g 28 the
maroon strand's wall bulged across its 2 px gap; a long-standing defect
present in pre-1.0 vtracer as well.

The fix lives in visioncortex 0.9.1 (densify slices with witness points,
keep the full multi-cubic chain): the mosaic's shared-boundary spline
fitter switches to the new fit_points_with_beziers so open segments get
the same treatment as stacked mode. Verified against the exact pixel-mode
rasterization — the fitted wall now matches it at every probed row — with
identical path counts and only +3 cubics across the whole Cityscape
output. All three workspaces (core, py, nodejs) carry a [patch.crates-io]
entry pointing at the local visioncortex until 0.9.1 is published.

Regression coverage for spline handle anchoring; re-bless goldens

tests/spline_fit.rs traces the real reproduction (the Cityscape sample at
color precision 8 / gradient step 28, whose maroon region contains a 1 px
by 330 px strand) through both compositors and asserts the property the
sparse-slice bug violated: every cubic's control points stay within its
shape's on-curve bounding box plus a 15 px allowance. The ballooning fit
put a handle 25 px outside the whole shape, so the margin is decisive in
both directions. The sample photo is decoded via a test-only image
dev-dependency.

The synthetic goldens are re-blessed: the fitting fix shifts fixture
coordinates slightly (witness points refine fits even on clean shapes);
the old files still passed the render-diff, so the visual change is
sub-tolerance, but goldens should byte-match intentional behavior.

Depend on published visioncortex 0.9.1; drop local path patches
2026-07-27 19:56:03 +01:00
Chris Tsang fb75738328 Rust edition 2024; drop mod.rs for module-named files
Workspace, vtracer-py, and the nodejs wasm crate move from edition 2021
to 2024 (no code changes needed — clean build and test run on 1.95).
Module directories switch from foo/mod.rs to the modern foo.rs layout;
single-file modules (svg, optimize, compose, fitter) collapse from
directories into plain files. Pure git renames, history preserved.
2026-07-27 15:41:30 +01:00
Chris Tsang 7864a702da Watershed: synthetic tests pinning the algorithm's semantics
Five new cases exercising behavior rather than plumbing:

- diagonal_touch_does_not_connect — regions are 4-connected; same-colored
  squares meeting at a corner stay separate basins.
- nested_regions — frame/ring/core flat zones come out as three exact
  regions, and the holed ring face survives the mosaic.
- volume_extinction_prefers_vivid_over_large — the hierarchy's ranking
  attribute: a 9 px black dot (volume ~1150) outlives a 100 px
  barely-different patch (volume ~400) when cutting to two regions.
- plateaus_with_ramps — the antialiased-boundary shape: three plateaus
  joined by short ramps cut to three regions whose means stay near the
  plateau values; ramps neither form regions nor drag the means.
- degenerate_geometries — 1x1, 16x1, and 1x16 images segment correctly.

assert_stack additionally bounds the layer count by the merge tree
(at most 2K-1 layers).
2026-07-27 15:34:55 +01:00
Chris Tsang 39cc49061e Cutout: merge_diff 0 still merges identical-color faces
Making watershed's cutout native (merge_diff = 0) silently disabled the
same-color merge too: merge_similar early-returned on a non-positive
threshold, so two adjacent faces with the very same fill — e.g. after a
palette snap — kept a useless boundary between them. A threshold of 0 now
means 'merge only identical-color neighbours' (a boundary between two
same-colored faces is never useful); negative disables merging entirely.

The regression test snaps two boundary-sharing regions to the same
palette entry with a third region between them in stack order, so the
layer-level MergeAdjacent (consecutive runs only) cannot mask the mosaic
merge: 3 faces with the bug, 2 with the fix. The zero-threshold unit test
now asserts the new semantics, and negative-threshold identity.
2026-07-27 15:29:55 +01:00
Chris Tsang e2b47dab0f Session: prove cached renders equal full rebuilds
A 21-step cumulative parameter walk covering every category — finish-phase
dials (true cache hits, since the segment key provably ignores them),
clustering dials, frontend switches including leaving watershed and
returning to its cached hierarchy, compositing, thresholds, palettes and
quantization — asserting after each step that the session render is
byte-identical to a from-scratch pipeline. Plus: the progress-reporting
render path (a separate segmenting branch with the watershed hierarchy
shortcut) equals the plain path, a cache warmed by the progress path
serves the plain path identically, and invalidate() rebuilds identically.
2026-07-27 15:19:25 +01:00
Chris Tsang c3f56a6339 Watershed: hierarchy stacking, native cutout, and cached re-cuts
Three refinements that make the watershed frontend a first-class citizen
of both compositing modes and of interactive tuning:

Stacked mode now stacks for real. Instead of one full-canvas background
plus disjoint regions, the cut emits the merge tree itself: the root
(whole canvas, mean color) first, then progressively finer ancestor
regions, then the final regions on top — the same principle as the color
clustering frontend, just with watershed-born clusters. Sub-pixel gaps
between abutting regions therefore show their common ancestor's color
rather than an unrelated backdrop, and overdraw stays seam-free. A
painted-area budget (3x canvas) keeps pathological persistence chains
from ballooning the stack; the root and final regions are always emitted
so coverage never depends on it.

Cutout is native. The watershed hierarchy already decided every merge, so
the flattened partition reaches the mosaic untouched: merge_diff is 0 for
watershed (the gradient-step re-merge still applies to the color path).
Faces are exactly the cut regions.

Re-cuts are cached. WatershedHierarchy is now public and split into
build(img) — Kruskal, BPT, volume persistence; depends only on the image
— and cut(detail, min_area), which is near-linear: region formation,
graph-level small-basin absorption (region adjacencies, not pixel
sweeps), then the merge tree. Session builds the hierarchy lazily on the
first watershed render and re-cuts it on every watershed_detail or
filter_speckle change: ~25 ms per re-cut vs ~40 ms rebuild on a 1400x775
photo, with the one-shot Frontend::segment path unchanged (build + cut),
so Session output still equals the one-shot pipeline exactly.

Tests: flatten-based stack invariants (solid bottom layer, full coverage,
final regions topmost, exact region counts), hierarchy re-cut == one-shot,
Session re-cut == one-shot across detail changes, and cutout keeping two
regions one gradient step apart that the color path's merge would rejoin.
Watershed goldens re-blessed for the new stack structure.
2026-07-27 15:12:12 +01:00
Chris Tsang 46a1b90ccd Add watershed clustering: hierarchical watershed frontend
An alternative region-forming frontend selected by --clustering watershed
(the color_mode field is replaced by clustering: color-cluster | bw |
watershed across CLI, Rust, Python, and Node — it selects the algorithm,
not a color space).

The algorithm is the watershed hierarchy by volume on the 4-adjacency
pixel graph, implemented from the papers:

  Cousty, Bertrand, Najman, Couprie, "Watershed Cuts: Minimum Spanning
  Forests and the Drop of Water Principle", IEEE TPAMI 31(8), 2009.
  Najman, Cousty, Perret, "Playing with Kruskal", ISMM 2013.

Edge weights are the max per-channel color difference between adjacent
pixels (no gradient image); a counting-sorted Kruskal pass builds the
binary partition tree as a flat parents array; a leaves-to-root pass
computes subtree area and volume; each merge's persistence (the volume of
the smaller side, plateau-corrected) becomes its MST edge's saliency; and
cutting the hierarchy is single-linkage over MST edges below the cut
level. Watershed cuts label every pixel — no watershed-line pixel class —
so the output is a strict, gapless partition that drops straight into
both stacked and cutout modes. Integer arithmetic and flat u32 arrays
throughout; deterministic across platforms; ~66 ms on a 1400x775 photo.

The one dial, --watershed-detail (0..=255), maps exponentially to a
target region count (each +25.5 doubles it) since the persistence
distribution is far too skewed for a linear threshold. filter_speckle
absorbs undersized basins into their most color-similar neighbour rather
than dropping them, preserving the partition. The largest region is
emitted first as a solid full-canvas background layer so stacked mode
keeps its seam-free overdraw; the mosaic flatten is unaffected.

Tests: partition invariant (disjoint masks tiling the canvas), detail
monotonicity, min-area absorption, determinism, watershed cases in the
pipeline/golden suites, stacked-vs-cutout interior equivalence, a
watershed seam test, and SegmentKey coverage for the new params.
2026-07-27 14:45:25 +01:00
Chris Tsang f4872fcfe3 Shield the hand-formatted core crate from stray cargo fmt runs
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
disable_all_formatting in crates/vtracer/rustfmt.toml makes rustfmt a no-op
for every file under the crate, so an accidental workspace fmt cannot
rewrite it.
2026-07-27 13:45:12 +01:00
Chris Tsang 2b0f316778 Cutout: merge neighbouring mosaic regions within one gradient step
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
The stacked hierarchy deliberately splits smooth areas into gradient layers
one deepen_diff apart — that is what makes stacking look continuous. When
cutout flattens those layers into a mosaic, the layering degenerates into
abutting faces with barely distinguishable fills that clustering would have
treated as one region.

Add LabelMap::merge_similar: agglomerative union-find over the flattened
adjacency graph using the clustering color metric (sum of per-channel
absolute diffs, merge when <= deepen_diff). Most-similar pairs union first
and each merged region's color is re-derived as the area-weighted mean, so
gradient chains only coalesce while they genuinely stay within the
threshold — no transitive collapse. compose_mosaic runs it between
flattening and boundary extraction; Compositing::Mosaic carries the
threshold and Config wires it to layer_difference (gradient step), so there
is no new knob.

On the gum-tree sample (poster preset, cutout) this drops 919 faces to 745
with no visible difference. Covered by unit tests for the merge semantics
(running means, OUTSIDE handling, zero threshold) plus a compose-level test
that gradient strips coalesce into one face; goldens and the stacked/cutout
equivalence suite are unaffected.
2026-07-26 23:31:31 +01:00
Chris Tsang f6c8a139a4 update screenshot
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
2026-07-26 00:31:10 +01:00
Chris Tsang ba2b80455e Give each disjoint patch of a region its own face in cutout mode
Face assembly bucketed contours by region label, so a region appearing as
several disjoint patches contributed all of their contours to one face — and
compose emitted them as subpaths of a single <path>. Isolated islands were
therefore not separately addressable downstream.

Faces are now keyed by (region, island). `islands` flood-fills the label map
into connected components in one pass, and `island_of` attributes a contour via
the region-side pixel flanking its first directed edge: every contour is walked
with its region on the left, so that pixel is interior to the patch the contour
bounds, and an outer ring agrees with the holes inside it. graph gains
`left_pixel_coord` (the coordinate half of `left_pixel_at`, which now delegates
to it) and `dir_from_delta`, needed because a ring has no start node or
first_dir. A BTreeMap keeps face order deterministic: region ascending, then
island in raster-scan order.

Connectivity is 8-way to match the successor rule, which pinches a checkerboard
corner into a single contour: lobes meeting only at a diagonal are walked as one
contour and must stay in one face. Splitting them could separate a hole contour
from the ring enclosing it, and a lone hole ring fills solid under nonzero.

Gum tree in cutout goes 492 -> 517 paths and the tank sprite 1022 -> 1023, with
renders byte-identical in both cases: the change is structural only. Costs one
O(W*H) pass over a pipeline that is already O(W*H).
2026-07-25 20:01:16 +01:00
Chris Tsang 5ff4f3ae05 Union same-paint layers in one pass, not pairwise
MergeAdjacent folded RegionMask::union over each run of same-paint layers, and
every union allocates a mask over the combined bounding box and copies both
inputs into it. The accumulator reaches full-canvas size after the first few
merges, so each remaining layer reallocated and rewrote the whole canvas —
O(n * width * height) for a run of n layers.

A single palette color is the worst case, since every layer then shares a paint
and the entire stack folds into one accumulator: 474 layers at 1400x775 spent
~0.8s of the 1.17s conversion there. --max-colors escaped it only because runs
of identical consecutive paints stay short.

RegionMask::union_all sizes the destination from the combined bounding box in
one cheap pass, then blits each source exactly once; union delegates to it with
two elements. MergeAdjacent groups a run and unions it as a whole. Gum tree with
a one-color palette goes 1.17s -> 0.31s (now under the no-palette baseline,
since one merged layer leaves less geometry to fit), with byte-identical output.

Only the --palette and --max-colors paths construct MergeAdjacent, so the
default pipeline is untouched.
2026-07-25 19:44:43 +01:00
Chris Tsang 84ba49f0b9 upgrade webapp 2026-07-25 17:21:55 +01:00
Chris Tsang df94675494 Add Session: transparent segmentation caching for interactive tuning
A stateful, image-owning converter for the desktop tuning loop. The consumer
calls render / render_svg / render_with_progress with a fresh Config each
frame and never reasons about cachability: Session compares the Config's
SegmentKey (its clustering-relevant projection — color mode, color precision,
layer difference, speckle, binary threshold settings) to what it last
clustered and re-segments only when that changes. Everything else — fit mode,
curve params, compositing, palette, optimization — reuses the cached
Segmentation.

Config::segment_key is public too, so callers that hold their own state (e.g.
the wasm/JS side) can compare keys with the same source of truth.

Tests cover the key partition (finish-phase params share a key; clustering
params change it) and that Session output matches the one-shot pipeline for
both a reused-segmentation render and a re-segmented one.

Add desktop app screenshot referenced by the README

Condense the unreleased changelog notes
2026-07-25 16:08:26 +01:00
Chris Tsang abe21658dc Make filter_speckle a finish-phase filter, tunable without re-clustering
Speckle removal moves out of the frontends into Segmentation::filter_speckle,
applied in the finish phase. The color frontend now clusters with
good_min_area = 0 and the binary frontend emits every cluster, so the cached
segmentation retains all regions and the speckle threshold can be retuned via
finish() with no re-clustering. Pipeline gains a speckle_area field
(Config sets it from filter_speckle^2).

Frontend structs drop their filter_speckle_area field. Output on clean images
is unchanged (golden/equivalence pass unblessed); noisy images are filtered
downstream instead of during clustering. Adds a test tuning filter_speckle on
one cached segmentation.

Add finish-phase thin-strand filter (restores thread-like rejection)

good_min_area = 0 disabled visioncortex's thread-like rejection (which was
gated on good_min_area > 0). Reintroduce it in our repo as a finish-phase
step: Segmentation::filter_thin drops regions whose perimeter >= area
(average thickness under ~2px), using the same Shape::image_boundary_list
metric so the heuristic matches. It's toggleable on a cached segmentation
(Config::filter_thin, on by default), unlike the clustering-time version.

Exposed via CLI --keep-thin, Python filter_thin, and Node filterThin. Adds
RegionMask::perimeter/is_thin and a reuse test toggling it on one cached
segmentation. Clean-image goldens are unaffected (large regions aren't thin).

README: document binary thresholding, --keep-thin, and finish-phase filters

Add the new CLI flags (--threshold, --adaptive, --adaptive-window,
--adaptive-t, --keep-thin) to the options block and "New in 1.0"; note that
--optimize is encoding-only (precision is --path-precision) and that speckle/
thin filtering run after clustering. Add adaptive-threshold examples for CLI,
Python, and Node.

Return speckle/thin filtering to clustering (fix gum-tree regression)

good_min_area is visioncortex's clustering `deepen` gate, not a speckle
post-filter: it decides whether a small or thread-like patch is absorbed
into its nearest-color neighbour or kept as its own layer, and it enables
the thread-like rejection (perimeter < area). An earlier change set it to 0
to make filter_speckle "retunable downstream", which disabled the thin
check and reshaped the whole hierarchy — dissolving gradient-boundary
structure that clustering is meant to absorb. The Gum Tree preset's central
trunk vanished at gradient-step ~26 where the pre-1.0 path held it to 128.
Clean-logo goldens couldn't exercise it, so it shipped green.

Follow the proven webapp model instead: speckle lives inside clustering
(good_min_area = filter_speckle^2 for the colour frontend; a post-cluster
size gate for the binary frontend). The segment/finish split stays — it is
the progressive model (cluster once, re-run colour/curve/optimize cheaply);
clustering params (speckle, colour precision, layer difference, binary
threshold) re-segment.

Remove the downstream band-aids: Segmentation::filter_speckle/filter_thin,
RegionMask::perimeter/is_thin, the pipeline speckle_area/filter_thin fields,
Config::filter_thin, CLI --keep-thin, Python filter_thin, Node filterThin.
Update the two reuse tests that encoded the wrong contract and the binary
threshold test to use BinaryFrontend::min_area. All goldens, equivalence,
progress, and reuse tests pass.
2026-07-25 16:08:10 +01:00
Chris Tsang 5361a51011 Split pipeline into cacheable segment + re-runnable finish
Pipeline::segment runs only the frontend (the expensive clustering) and
returns a reusable Segmentation; Pipeline::finish re-runs just color
fitting, compositing, and optimization over a cached segmentation. This
restores the old stage-reuse workflow: cluster once, then tune curve-fit
or color-fit params without repaying clustering. Both have
*_with_progress variants; run/run_with_progress now compose the two
(one-shot path moves the owned segmentation, so it adds no clone).

finish clones the segmentation internally (color fitting mutates it), so
the cached copy stays pristine across many finish calls. Segmentation and
VectorDoc are re-exported at the crate root.
2026-07-25 00:51:46 +01:00
Chris Tsang a350e2532a Enrich binary thresholding: tunable fixed + Bradley–Roth adaptive
BinaryFrontend gains a Threshold enum: Fixed(u8) (now tunable, was
hardcoded to 128) and Adaptive { window, t } — Bradley–Roth adaptive
thresholding computed via visioncortex's SummedAreaTable, O(pixels)
regardless of window size, for images with uneven lighting. Both use a
shared (r+g+b)/3 intensity so they agree on "dark"; the grayscale
checker_bw golden is unaffected.

Exposed through Config and all bindings: CLI (--threshold, --adaptive,
--adaptive-window, --adaptive-t), Python (constructor kwargs + getters/
setters), and the Node package (binaryThreshold, adaptive, adaptiveWindow,
adaptiveT). Adds tests covering fixed tunability and adaptive recovering
locally-dark marks under a brightness gradient that a global cutoff can't.
2026-07-25 00:26:05 +01:00
Chris Tsang 50042f477d Add progress reporting and cancellation to the pipeline
Pipeline::run_with_progress(img, &CancelToken, &mut on_progress)
publishes per-phase Progress and aborts (Error::Cancelled) when the
token trips. The color-cluster frontend now drives visioncortex's
IncrementalBuilder so clustering reports fine-grained progress and
checks cancellation between batches; run() delegates to the new path,
which is output-identical since Runner::run() is that same tick loop.

Intended for native desktop apps (Tauri/egui/iced): run on a worker
thread, hand the UI a CancelToken clone for a cancel button, and
forward progress to a bar. Replaces the old browser-only cooperative
tick() API, which existed only because the main thread couldn't block.
2026-07-25 00:25:59 +01:00
Chris Tsang 1e3895318e README: surface the 1.0 packages (crates.io, PyPI, npm)
Rust / test (push) Has been cancelled
Rust / wasm-safety (core) (push) Has been cancelled
Rust / Node package (push) Has been cancelled
Add package badges, a Packages overview table, and note the npm
build's supported input formats (PNG/JPEG/GIF/BMP/WebP).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 18:21:09 +01:00
Chris Tsang 6e9b147bbd Add WebP decoding to the Node/wasm package
image-webp is pure Rust and compiles to wasm32; brings the npm
package's input formats closer to the CLI/Python surface. Wasm grows
~115 KB (486 KB -> 601 KB). Also gitignore nodejs/.npmrc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 18:09:50 +01:00
Chris Tsang ec715f8c3c Prepare 1.0.0-alpha.1 release
- CHANGELOG: document the 1.0 framework rewrite
- CI: build Python wheels only on release tags + manual dispatch,
  not on every push/PR

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 17:24:04 +01:00
Chris Tsang 61ca5e5946 Compare goldens by rendering, not byte-equality
The spline fitter's least-squares cubic fit (flo_curves, f64) diverges by ULPs
across architectures: on x86_64 vs arm64 an arc decomposes into slightly
different control points, changing the SVG bytes with no real geometry change
(verified with an x86_64 emulation: 0 pixels differ by >40, worst channel
delta 20 — visually identical). Byte-exact golden comparison is therefore
inappropriate for the spline output.

Render both the stored golden and the produced SVG (resvg) and diff pixels,
tolerating a tiny fraction for sub-pixel boundary flips. Encoding-agnostic and
architecture-robust, while still catching genuine regressions (which move
boundaries by whole pixels).
2026-07-24 16:47:01 +01:00
Chris Tsang 87b9660ed3 Scope the npm package to @visioncortex/vtracer
Publish under the @visioncortex npm org. Add publishConfig.access=public for
the scoped package and update the install/require examples in both READMEs.
2026-07-24 16:30:28 +01:00
Chris Tsang 5743912da6 Trim image codec features in the CLI and Python crates
vtracer only decodes input, but image's default features pulled a full AV1
encoder (ravif/rav1e) and OpenEXR into the CLI binary and the Python wheel.
Restrict to decode-only input formats (png, jpeg, gif, bmp, webp, tiff, ico,
pnm, tga, qoi). The release binary drops from ~3.23 MB to ~2.46 MB and builds
faster; supported inputs are unchanged in practice (avif decode was never in
image's defaults anyway).
2026-07-24 15:56:28 +01:00
Chris Tsang 601447af6c Depend on published visioncortex 0.9.0; simplify CI
visioncortex 0.9.0 is on crates.io, so the workspace now uses the registry
version instead of the local `../visioncortex` path (a [patch.crates-io]
example is left in a comment for local visioncortex development).

CI no longer needs the adjacent visioncortex checkout / published-crate caveats:
rust.yml, python.yml, and release.yml build from a single checkout.
2026-07-24 14:06:17 +01:00
Chris Tsang 8af376cb7c Update CI for the 1.0 workspace layout
- rust.yml: modernize (checkout@v4), build/test the whole workspace, add a
  wasm32 core build check and a Node package build+test job. Checks out
  visioncortex next to the repo so the local path dependency resolves.
- python.yml: build crates/vtracer-py (was the deleted cmdapp/); note that
  manylinux builds need visioncortex 0.9.0 published to crates.io.
- release.yml: note the same visioncortex prerequisite for the CLI binary.
2026-07-24 13:37:25 +01:00
Chris Tsang 42f94f0d15 Add local-publish script for the Node package
nodejs/scripts/publish.mjs builds the wasm (wasm-pack), runs the smoke test,
then `npm publish` to a configurable registry (default a local one at
http://localhost:4873; override via --registry= or NPM_REGISTRY). Supports
--dry-run. Wired as `npm run publish:local`.
2026-07-24 13:37:25 +01:00
Chris Tsang 170b0322a4 Bump pyo3 to 0.26 in vtracer-py 2026-07-24 13:37:25 +01:00
Chris Tsang 749f0df0bd Add nodejs: WebAssembly Node package with no native dependency
New nodejs/ package: a wasm-bindgen crate (vtracer-wasm) built with wasm-pack
that wraps the vtracer framework, plus a thin JS layer for file I/O. Image
decoding (png/jpeg/gif/bmp via the image crate) runs in wasm too, so the
package has zero native dependencies — no sharp, no node-gyp.

No separate general-purpose wasm crate: the Node package directly owns and
wraps the wasm. Excluded from the cargo workspace (wasm-bindgen cdylib), built
with wasm-pack.

JS API (camelCase options): convertBuffer, convertPixels, convertFile,
convertFileSync — each taking an Options object (preset, colorMode,
hierarchical/cutout mosaic, mode, palette, maxColors, optimize, ...). Ships
index.d.ts types and a node smoke test. README updated.

Verified: builds to wasm32-unknown-unknown; `node test.js` passes; output
matches the CLI/Python bindings (253 paths on the tank sample).
2026-07-24 13:08:53 +01:00
Chris Tsang f76aed78b2 Add vtracer-py: Python bindings with a rich API
New crates/vtracer-py (pyo3 + maturin, abi3) wrapping the vtracer framework.
Rather than a thin CLI-style wrapper, it exposes a mutable `Config` class with
named properties and `bw`/`poster`/`photo` preset constructors, plus three
input paths — `convert_file`, `convert_bytes` (encoded image, optional format),
and `convert_pixels` (raw RGBA8) — available as `Config` methods and
module-level functions. Palette is a list of `#rrggbb` strings; bad inputs
raise ValueError.

The core crate stays pure: image decoding lives here. The crate is excluded
from the cargo workspace (pyo3 extension-module cdylibs don't link libpython,
which breaks `cargo test` at the root) and is built with maturin. Ships a
vtracer.pyi type stub. README updated.
2026-07-24 11:53:47 +01:00
Chris Tsang 57d768e37e Update README CLI docs for the 1.0 command app
Replace the 0.6.x help block with the current options (kebab-case flags,
positional input/output, filter-speckle 0..=128), document the new
capabilities (positional args, seam-free mosaic cutout, fixed palette /
auto-quantize, output optimization levels), and refresh the usage examples.
2026-07-24 11:39:14 +01:00
Chris Tsang 837fde8aa4 Accept positional input/output args in the CLI
`vtracer in.png out.svg` now works alongside the `-i/--input` and
`-o/--output` flags. Input/output become optional positionals plus the
existing flags; an explicit flag wins over the positional, and a clear error
is shown if neither is given.
2026-07-24 11:18:21 +01:00
Chris Tsang 35b4b6f846 Raise filter_speckle CLI cap from 16 to 128
Ports visioncortex/vtracer#115: the command app capped filter_speckle at 16
while the web app allowed up to 128. Match the web app's range.
2026-07-24 11:15:29 +01:00
Chris Tsang 3300f97e37 Add mosaic spline fitter; fix stacked holes & relative writer; add test suite
Feature — mosaic spline segment fitter (crates/vtracer/src/mosaic/fit.rs):
open-path cubic fitting for boundary segments, reusing the now-public
visioncortex primitives (PathSimplify::limit_penalties for symmetric,
gap-free staircase removal; open-path SubdivideSmooth::{find_corners,
subdivide_keep_corners,find_splice_points}; fit_points_with_bezier per splice
slice). Matches stacked spline curve quality; endpoints pinned to lattice
nodes so shared boundaries stay seam-free.

Fix — stacked mode punched holes in cluster masks (to_image_with_hole .. true);
stacked must trace solid layers and occlude by paint-order overdraw (false).
Holes left the layer below exposed as hairline seams.

Fix — the relative SVG writer measured a subpath's opening `m` from the last
vertex instead of the subpath start (SVG resets the current point to the start
after Z), misplacing holes / extra subpaths at optimize=1/2.

Tests — new tests/equivalence.rs: stacked-vs-mosaic interior agreement (all
fitters) and a seam guard (a full-coverage image must render fully opaque).
svg round-trip test (absolute vs relative encode identical geometry). mosaic
spline endpoint-pinning test. Regenerated goldens; added disc_mosaic_spline.
resvg added as a dev-dependency (test-only; not compiled for wasm).

Drop unused MosaicOptions placeholder

The strict/seam-stroke mitigations aren't needed — the mosaic geometry is
already gapless and seam-free. Remove the no-op MosaicOptions struct and thread
it out of Compositing::Mosaic and compose_mosaic.
2026-07-24 11:13:02 +01:00
Chris Tsang 5ac90bb97c Add stacked-mode equivalence report
Documents the systematic verification that the 1.0 pipeline reproduces 0.6.x
stacked output byte-for-byte: 475 parameter configurations (full per-parameter
sweeps + randomized interactions, pixel/polygon/spline, color/bw), geometry
compared against the 0.6.x cmdapp reference at path-precision 8. Zero geometry
mismatches (worst deviation 1e-8). Records the two bugs found and fixed during
verification (stacked hole-punching; relative-writer subpath origin), the
intentional differences (compact SVG encoding, empty-path omission), and the
reproduction procedure.
2026-07-24 10:50:09 +01:00
Chris Tsang 17a9a6e6c5 Add mosaic mode: seam-free tessellation (pixel + polygon)
Implements the topological mosaic pipeline from docs/design/mosaic.md, turning
`--hierarchical cutout` into a true gapless tessellation instead of the old
re-cluster-and-retrace fake.

  LabelMap (flatten Segmentation top-down)
    → boundary-graph extraction  (integer-exact: corners, node rule, segment
                                   and ring tracing on the pixel-corner lattice)
    → face assembly              (left-region successor rule; winding falls out,
                                   so each region is one nonzero-fill path)
    → fit each segment ONCE       (shared by both adjacent faces, reversed
                                   exactly → byte-identical shared boundaries)
    → compose per-region paths

Backends: PixelSegmentFitter (exact reference) and PolygonSegmentFitter
(symmetric open Douglas-Peucker collapsing staircases to the crack midline).
The spline segment fitter is still pending; mosaic + spline currently falls
back to polygon.

Compositing now owns its fitter (Stacked(CurveFitter) / Mosaic(SegmentFitter)).

Tests: single region, vertical split, T-junction, checkerboard pinch, nested
rings, border-touching, and a pixel round-trip property test over 40 random
maps (rasterize composed faces == input label map). Plus two mosaic goldens.
2026-07-23 23:26:18 +01:00
Chris Tsang 572d9e5f82 Add golden-snapshot fixtures to lock in pipeline output
12 synthetic-image cases covering every stage: all three fitters, holes,
region adjacency, hierarchical layering, binary mode, fixed-palette and
auto-quantize color fitting, and the three optimizer/writer levels.

Fixtures are built from in-code images, not the JPEG samples, because JPEG
decoding is image-crate-version dependent and would make goldens fragile.
Regenerate after an intentional change with VTRACER_BLESS=1.
2026-07-23 23:13:06 +01:00
Chris Tsang 660dc4ff93 Remove the 0.6.x cmdapp crate
Superseded by crates/vtracer (framework) + crates/vtracer-cli. Verified the
new pipeline reproduces cmdapp's geometry and colors byte-for-byte (PNG always;
JPEG once the image-crate decoder is held constant), so the old crate is
retired. Drop its now-stale workspace exclude entry. Git history preserves it.
2026-07-23 23:08:04 +01:00
Chris Tsang e46c971845 Rewrite into a vectorization framework (pillars 1–4)
Replace the 0.6.x single-pipeline crate with a stage-based framework, per
docs/design/. Implements Motivation pillars 1–4 (frontend, curve fitting,
color fitting, optimizer); mosaic (5) and bindings are deferred.

Workspace:
- crates/vtracer      — the framework library (wasm-safe, no I/O)
- crates/vtracer-cli  — thin CLI wrapper (clap 4 + image I/O)
- cmdapp/ and webapp/ excluded from the workspace (git-preserved)

Stages behind object-safe traits, composed by a Pipeline driver:
- Frontend: ColorClusterFrontend (+ transparency keying), BinaryFrontend
- CurveFitter: Pixel / Polygon / Spline (region tracing via visioncortex)
- ColorFitter: Identity, FixedPalette (OKLab-nearest), AutoQuantize
  (area-weighted median cut), MergeAdjacent
- OptimizerPass: QuantizePass, SimplifyPass
- SvgWriter: relative/absolute shortest encoding, H/V/S shorthands,
  compact number formatting, <g fill> grouping

visioncortex is a path dependency on the local 0.9.0 checkout.

Verified: 14 unit/integration tests pass; framework builds for
wasm32-unknown-unknown; CLI output renders faithfully via rsvg.
2026-07-23 22:27:24 +01:00
Chris Tsang 913d0ac7e0 New design 2026-07-23 18:11:19 +01:00
Chris Tsang fd9cdb08e6 missing artifacts
Rust / build (push) Has been cancelled
2026-03-23 15:30:48 +00:00
Chris Tsang 3b2991be84 0.6.12 2026-02-04 12:21:42 +00:00
Chris Tsang f24ea56a52 use Trusted Publisher 2026-02-04 11:47:44 +00:00
Chris Tsang 592bee6c5c Regenerate python workflow 2026-02-04 10:11:32 +00:00
Chris Tsang 3ebc358b48 Bump CI 2026-01-30 14:35:48 +00:00
Chris Tsang 3a24c2f755 0.6.6 2026-01-28 18:21:44 +00:00
Chris Tsang 8acb6bd911 bump fastrand
Rust / build (push) Has been cancelled
2025-10-17 22:02:50 +01:00
Chris Tsang efa4351b2c Update README.md 2024-09-27 10:43:47 +01:00
Chris Tsang a46292b5ed Update README.md 2024-09-27 10:43:02 +01:00
Chris Tsang 8889cbc7ea Tweaks
Rust / build (push) Has been cancelled
2024-09-26 12:59:45 +01:00
Wil Carmon 6b379a02ef Update svg.rs (#92) 2024-09-26 12:58:43 +01:00
Wil Carmon 2635d5b874 Update config.rs (#91)
added #[derive(Clone, Debug)]
2024-09-26 12:58:30 +01:00
Chris Tsang f6cf3e8705 Refactor 2024-05-30 10:04:23 +01:00
Chris Tsang 36b16de17a Key transparent image in webapp 2024-05-29 15:10:11 +01:00
Chris Tsang 7887c1ebf8 Update readme 2024-05-02 23:57:13 +01:00
Chris Tsang 6fdfec8610 python 0.6.11 2024-05-02 22:58:11 +01:00
York 1aff9a300a Add support for conversion from python bytes (#79)
* Allow conversion from python bytes

* Update function name

* Add convert_pixels_to_svg python function

* Update README.md

* Update README.md
2024-05-02 22:24:56 +01:00
Chris Tsang ac0a89e08a README 2024-04-20 16:24:41 +01:00
Chris Tsang b09f71a2b5 LICENSE 2024-04-20 16:21:36 +01:00
Chris Tsang e4897dfe99 README 2024-04-20 16:16:57 +01:00
Chris Tsang 4544ca740d README 2024-04-20 16:14:21 +01:00
Chris Tsang 3d92586e33 Update CI script 2024-04-20 15:52:58 +01:00
Chris Tsang 725adf5364 Update README.md 2024-03-30 14:46:52 +00:00
Chris Tsang 05f82c7bb5 Test 2024-03-29 19:26:28 +00:00
Chris Tsang b7ac336b6d Add release script 2024-03-29 19:06:29 +00:00
Chris Tsang c03a8ffced 0.6.4 2024-03-29 19:01:16 +00:00
Chris Tsang 3223ba56ec Upgrade dependency 2024-03-29 18:59:55 +00:00
Chris Tsang ddb47e1ad4 Revert "Experiment with idealizing small circles"
This reverts commit c3012c6aef.
2024-03-29 18:58:06 +00:00
Chris Tsang 177797108d Changelog 2024-03-29 18:57:57 +00:00
Chris Tsang 370083f818 0.6.3 2024-03-29 18:57:57 +00:00
Chris Tsang c3012c6aef Experiment with idealizing small circles 2024-03-29 18:57:57 +00:00
Chris Tsang 2774fc06c9 Reduce default path precision 2023-11-12 23:05:45 +00:00
Chris Tsang fa7d021055 Readme 2023-11-12 20:39:25 +00:00
Chris Tsang cc43924601 cargo fmt 2023-11-12 20:38:01 +00:00
Chris Tsang 9dbbd100df Bump 2023-11-12 20:36:35 +00:00
linkmauve 37a2570f49 Add a function to do in-memory conversion (#59)
* Move path handling out of conversion functions

This lets us decouple file reading/writing from the actual conversion.

* Move Config::from_args() to main.rs

* Remove path support from Config

Instead the input_path and output_path have to be passed to
convert_image_to_svg() manually.

* Add a simplified convert() function

This lets the user convert an image from memory, without encoding it to
PNG, writing it to a file, then reopening this file and decoding it
using the image crate.

It also allows the user to not write a SVG directly to a file.
2023-11-13 04:28:05 +08:00
Chris Tsang b2cd1a9524 Expose as rlib too 2023-10-24 08:43:37 +01:00
Chris Tsang ac93bd4a51 Edit 2023-09-24 11:08:30 +01:00
Chris Tsang e62f071b34 Edit 2023-09-23 11:52:36 +01:00
Chris Tsang 884092a5b9 Edit 2023-09-23 11:49:54 +01:00
Chris Tsang 5f5a6c6648 README 2023-09-23 11:45:36 +01:00
Chris Tsang 022018beb2 0.6.1 2023-09-23 11:12:34 +01:00
Chris Tsang cc39c8c5ca README 2023-09-23 11:06:18 +01:00
Evan Jones fa1ab68ef3 Python Bindings. Again. No, really! (#55)
* - Cargo.toml:  add `crate-type = ["cdylib"] to [lib]; lacking this is what was causing the executable to be put in wheels
- pyproject.toml: add "python-binding" to features for conditional compilation
- main.rs:  `cargo build` was failing for the vtracer executable; I think the previous import scheme had an implicit dependency on the library being built and called 'vtracer'. The other way to do this would have been to add an explicit dependency to the [[bin]], but making explicit imports here solves things directly

* re-enable linux builds; features are defined in the pyproject.toml now rather than in the workflow arguments

* And publish Linux, too!
2023-09-23 02:10:04 +08:00
Chris Tsang b04738fd18 well 2023-09-16 19:38:07 +01:00
Chris Tsang 1080c562ce Try again 2023-09-16 19:27:30 +01:00
Chris Tsang e44e750721 try again 2023-09-16 19:09:20 +01:00
Chris Tsang 05f5b51db0 Add xml comment 2023-09-17 16:24:33 +01:00
Chris Tsang 68e8e7fdf1 Disable Linux for now 2023-09-17 15:47:55 +01:00
Chris Tsang f5cce867f2 python again 2023-09-16 17:59:52 +01:00
Chris Tsang 79dd451da1 Remove filestar
From my knowledge they are no longer using vtracer
2023-09-16 17:53:43 +01:00
Chris Tsang f71dd47907 python release 2023-09-16 17:47:04 +01:00
Chris Tsang 594125f737 Release notes 2023-09-16 15:31:36 +01:00
Chris Tsang 93e946f3c2 python release 2023-09-16 15:05:24 +01:00
Chris Tsang 914e4ab875 python release 2023-09-16 14:51:26 +01:00
Chris Tsang 95b8cbce6c Rename workflow 2023-09-16 14:40:29 +01:00
Chris Tsang b49158f24c Rename workflow 2023-09-16 14:40:17 +01:00
Chris Tsang f35df1f6b2 0.6.0 2023-09-16 14:35:49 +01:00
Evan Jones f4c7828049 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>
2023-09-17 06:24:13 +08:00
Chris Tsang d5dfa9fd73 Readme 2023-07-24 22:55:26 +08:00
Chris Tsang 685009bd21 Allow filter_speckle to be 0 #47 2023-06-30 05:45:35 +08:00
Chris Tsang 971bffa948 Mentions Aliyun
Foot note: I was in touch with one of their engineers
2022-11-10 17:53:12 +08:00
Chris Tsang 7be6882d6b Readme 2022-10-14 00:32:02 +08:00
Chris Tsang 386a0bcaab Filestar 2022-10-14 00:29:13 +08:00
Chris Tsang 82284ab470 0.5.0 2022-10-09 18:01:35 +08:00
Chris Tsang ead104f0ce Tweak should_key_image 2022-10-09 17:21:00 +08:00
zachwolfe a7219fd370 Alpha channel handling in CLI (#23)
* Support transparent color images

* Remove unnecessary conditional

* Add temporary git url to visioncortex dependency

* Use fastrand instead of rand

* Reduce the number of random iterations when keying

* Add heuristic to avoid expensive calculations for non-transparent input

* Add three additional special keying colours

* Add transparency check to some inner pixels
2022-10-09 15:41:43 +08:00
Oskar Skuteli 2448dbb3ba fix docs typo (#25) 2022-09-25 15:06:19 +08:00
Chris Tsang c9d9073b17 Merge pull request #16 from wolfgangmeyers/fix-converter-warning
Fix deprecation warning from converter.rs
2022-02-11 21:45:33 +08:00
Wolfgang Meyers 47091b0bf5 Fix deprecation warning from converter.ts 2022-02-10 18:13:51 -08:00
Chris Tsang 8439cc995d Refactor path_precision 2021-07-27 21:01:20 +08:00
Chris Tsang 0b292ad35f Readme 2021-07-24 16:48:47 +08:00
Chris Tsang ebb17ac22b vtracer-webapp 2021-07-24 16:37:41 +08:00
Chris Tsang 227850dd83 Release 2021-07-24 15:58:51 +08:00
Chris Tsang e0dac19c31 Article link 2021-07-24 15:42:35 +08:00
Chris Tsang d18d4f8b81 Readme 2021-07-24 00:00:59 +08:00
Chris Tsang 60a4ce579f Release 2021-07-23 23:35:54 +08:00
Chris Tsang c1c09d964c Readme 2021-07-23 23:35:54 +08:00
Chris Tsang c2a5626afa 0.4.0 2021-07-23 23:35:54 +08:00
Bobby Ng d0593e716a SVG path string numeric precision 2021-07-23 23:35:45 +08:00
Chris Tsang 9ce7df176a Update .gitattributes 2021-07-23 18:29:12 +08:00
Chris Tsang 5928c0a7f5 Update screenshots 2021-03-01 21:13:24 +08:00
Chris Tsang b2c95a50cd Update README.md 2021-03-01 21:13:24 +08:00
Chris Tsang bcd3ffb40e Update COPYRIGHT 2021-02-07 14:22:26 +08:00
Chris Tsang 20da3efd3c Create .gitattributes 2021-01-25 00:57:44 +08:00
Chris Tsang 0c27d1f06a Update README.md 2021-01-25 00:53:01 +08:00
Chris Tsang 0c7c7fc808 Demo fixup 2021-01-24 22:12:01 +08:00
Chris Tsang 97ac767844 0.3.0 2021-01-24 21:31:55 +08:00
Chris Tsang 0b37051d40 Cutout mode 2021-01-24 21:31:08 +08:00
Chris Tsang 2695d7b59b Release (with cutout mode) 2021-01-24 21:17:18 +08:00
Chris Tsang 433a68d6d6 Update to visioncortex 0.4.0 2020-12-19 01:34:01 +08:00
Chris Tsang bb3b66780b UI tweaks 2020-12-18 00:32:35 +08:00
Chris Tsang 049ba7f503 UI tweaks 2020-12-18 00:19:57 +08:00
Chris Tsang 9d67b7c554 Release 2020-12-18 00:14:55 +08:00
Chris Tsang fa5d2906c0 Change sample artwork 2020-12-09 15:21:12 +08:00
Chris Tsang fae37a709e Update README.md 2020-12-09 14:51:15 +08:00
Chris Tsang 5c9d5cd757 Example for pixel art 2020-12-09 14:36:07 +08:00
Chris Tsang 1b49880f85 Create rust.yml 2020-11-15 21:10:13 +08:00
Chris Tsang 0b0d69839a Release 2020-11-15 17:33:32 +08:00
Chris Tsang 7ea4600176 Readme 2020-11-15 16:54:46 +08:00
Chris Tsang 20187e0993 0.2.0 2020-11-15 16:27:37 +08:00
Chris Tsang 04d575dec6 UI tweaks 2020-11-15 16:03:26 +08:00
Chris Tsang c8f93acf04 Release 2020-11-09 12:17:55 +08:00
Chris Tsang a33a659b22 Fix memory leak 2020-11-09 12:17:48 +08:00
Chris Tsang 31c3f109a8 Release 2020-11-09 01:00:21 +08:00
Chris Tsang 5f18837b61 Relative & compound path 2020-11-09 00:38:44 +08:00
Chris Tsang 99cb79895b Move license files 2020-11-07 19:20:17 +08:00
Chris Tsang 08483eb7a8 Clarity tracking code 2020-11-07 19:15:30 +08:00
Chris Tsang b5f8753410 Update Readme.md 2020-11-01 17:37:11 +08:00
Chris Tsang 6b86baad75 Add download link 2020-11-01 14:59:40 +08:00
Chris Tsang ba0ab63a92 vtracer 0.1.1 2020-11-01 14:54:33 +08:00
Chris Tsang 3df69f6274 svg namespace 2020-11-01 14:52:44 +08:00
Chris Tsang 5efd479885 Docs 2020-10-31 19:18:45 +08:00
Chris Tsang 105bdfc7a3 Space 2020-10-31 19:16:41 +08:00
Chris Tsang d8b6d1cf33 Docs 2020-10-31 19:12:15 +08:00
Chris Tsang cbb6c97ce4 Publish to crates.io 2020-10-31 18:49:45 +08:00
Sanford Pun 0c4fa1d742 CMD app 2020-10-31 17:42:04 +08:00
Chris Tsang 43c403e06f Release 2020-10-31 16:59:19 +08:00
Chris Tsang 3c2d4f3c8c Tweaks 2020-10-31 01:01:23 +08:00
Chris Tsang 956fd4fa57 Release 2020-10-31 00:26:21 +08:00
Chris Tsang c8f4fc1133 Update Cargo 2020-10-29 11:41:06 +08:00
Chris Tsang 2243d107d5 Runs faster 2020-10-29 11:20:33 +08:00
Chris Tsang 7a62846470 Docs 2020-10-25 15:43:40 +08:00
Chris Tsang 46c49e5867 Docs 2020-10-25 15:06:19 +08:00
Sanford Pun 1544f54b99 Credit 2020-10-25 14:51:19 +08:00
Chris Tsang 00375567cc Touch 2020-10-25 14:49:59 +08:00
Chris Tsang 1d3407eec1 Docs 2020-10-25 14:46:26 +08:00
Chris Tsang 2b2e08d311 License 2020-10-25 14:29:08 +08:00
Chris Tsang f6f4839185 Source Release 2020-10-25 14:22:42 +08:00
Chris Tsang f0a1369dc4 Docs 2020-10-24 21:57:16 +08:00
Chris Tsang 2c423ae43e Docs 2020-10-24 12:03:23 +08:00
Chris Tsang e1bf11d531 Tweaks 2020-10-23 16:25:45 +08:00
Chris Tsang 69b7af1b30 Tweaks 2020-10-23 12:34:24 +08:00
Chris Tsang f0fcb7b4cc icon 2020-10-23 12:17:03 +08:00
Chris Tsang 2aae302edf touch 2020-10-23 12:04:01 +08:00
Chris Tsang 445d32927c Initial Release 2020-10-23 11:59:59 +08:00
46 changed files with 1528 additions and 38939 deletions
+3
View File
@@ -1,5 +1,8 @@
target
# Track the workspace lockfile (reproducible binary/CI builds); keep the
# nested crates' lockfiles (nodejs, vtracer-py, webapp) ignored.
Cargo.lock
!/Cargo.lock
*.sublime*
.vscode
.DS_Store
+7
View File
@@ -5,6 +5,13 @@ 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/).
## 1.0.0-alpha.4 - 2026-08-29
### Changed
* `--watershed-detail` (and `watershed_detail` on `Config` and in the Python and Node bindings) is no longer capped at 255 — it now accepts any value, so extremely fine segmentation is reachable past the old ceiling. The default stays 128 and each +25.5 still roughly doubles the region count.
* Bump `visioncortex` to 0.9.3 — a minor upstream bug fix.
## 1.0.0-alpha.3 - 2026-08-01
### Added
+62
View File
@@ -0,0 +1,62 @@
# VTracer App Changelog
All notable changes to the VTracer desktop app will be documented in this file.
## 1.0.0-alpha.4 - Build 116 - 2026-08-29
### Added
* VTracer 2 preview. Trial license can be activated in app.
* SVG saving without a dialog. A preferred save folder can be set in Preferences, or the app can keep asking each time.
* A source image display preference, choosing smooth or pixelated scaling for the source image.
* Selected SVG shapes now show their bounds, and can be dragged around the canvas to inspect what sits beneath them.
* A configurable disk cache limit for VTracer 2, defaulting to 2 GB. Lowering it reclaims space immediately.
### Fixed
* Pasting an image now works consistently across the app rather than only when the canvas held focus.
## 1.0.0-alpha.3 - Build 59 - 2026-08-14
### Added
* User-managed presets. A preset stores the complete tracing configuration and its source image; presets can be created or updated by name, reordered, deleted, and restored to the shipped defaults.
* Side-by-side comparison mode with synchronized, mirrored views of the source image and generated SVG. Switching between overlay and side-by-side comparison preserves the canvas position and zoom.
* A new etched-cat sample demonstrating adaptive black-and-white tracing.
### Changed
* The canvas comparator and SVG rendering now remain sharp and stable while zooming, panning, dragging the divider, and switching comparison modes.
### Fixed
* Trace sessions recover after an engine panic instead of leaving the app stuck with an unavailable session cache.
* Large images and repeated image uploads no longer leave the frontend unable to start a new trace.
## 1.0.0-alpha.3 - 2026-08-01
First public preview of the rebuilt VTracer desktop app.
### Added
* Native VTracer 1.0 tracing for macOS and Windows, with Linux packaging support.
* Cancellable tracing with stage-aware progress. Changing a tracing control aborts obsolete work and immediately starts the new trace.
* Session caching that reuses expensive clustering work while tuning compatible curve and color fitting settings.
* An interactive source/SVG comparator with a draggable divider, zoom controls, scroll-to-zoom, drag-to-pan, actual-size and fit modes, and a focused full-canvas view.
* SVG shape inspection with yellow hover outlines and selectable curve nodes.
* Full controls for color, black-and-white, and watershed clustering; stacked and seam-free cutout composition; pixel, polygon, and spline fitting; fixed palettes; adaptive thresholding; and curve simplification.
* Open, paste, and drag-and-drop image input, including EXIF orientation normalization for camera images.
* A scrollable sample preset strip with image credits.
* Native SVG save dialogs and save completion feedback.
* System light and dark themes.
* In-app update checks, engine release notes, and open-source license information.
### Changed
* Tracing runs in the native backend rather than WebAssembly.
* The desktop shell serves the frontend and API over an authenticated loopback HTTP session, aligning development and production behavior.
### Fixed
* External links open directly in the default browser on macOS and Windows without displaying a command window.
* Native context menus are suppressed across production app surfaces.
+10
View File
@@ -0,0 +1,10 @@
# VTracer 2 Changelog
All notable changes to the VTracer 2 engine will be documented in this file.
## 1.0.0-alpha.4 - Build 116 - 2026-08-29
Initial release. Supported systems:
* macOS on Apple Silicon
* Windows 10 x64 with TPM, Windows 11
Generated
+1090
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -19,7 +19,7 @@ exclude = [
resolver = "2"
[workspace.package]
version = "1.0.0-alpha.3"
version = "1.0.0-alpha.4"
authors = ["Chris Tsang <chris.2y3@outlook.com>"]
edition = "2024"
license = "MIT OR Apache-2.0"
@@ -27,7 +27,7 @@ homepage = "http://www.visioncortex.org/vtracer"
repository = "https://github.com/visioncortex/vtracer/"
[workspace.dependencies]
visioncortex = "0.9.1"
visioncortex = "0.9.3"
# Schneider curve fitting for the simplify pass. visioncortex pins an old
# flo_curves internally for legacy reasons; we depend on the current one
# directly and convert at the call boundary.
+64 -80
View File
@@ -8,39 +8,28 @@
</p>
<h3>
<a href="https://github.com/visioncortex/vtracer/releases">Releases</a>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_x64-setup.exe">Windows App</a>
<span> | </span>
<a href="https://www.visioncortex.org/vtracer/">Web App</a>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_universal.dmg">macOS App</a>
<span> | </span>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.3/VTracer_1.0.0-alpha.3_x64-setup.exe">Windows App</a>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_x64.AppImage">Linux App</a>
</h3>
<p>
<a href="https://crates.io/crates/vtracer"><img src="https://img.shields.io/crates/v/vtracer.svg?label=crates.io" alt="Rust library on crates.io"></a>
<a href="https://pypi.org/project/vtracer/"><img src="https://img.shields.io/pypi/v/vtracer.svg?label=PyPI" alt="Python package on PyPI"></a>
<a href="https://www.npmjs.com/package/@visioncortex/vtracer"><img src="https://img.shields.io/npm/v/@visioncortex/vtracer.svg?label=npm" alt="Node package on npm"></a>
<a href="https://crates.io/crates/vtracer"><img src="https://img.shields.io/crates/v/vtracer.svg?label=crates.io&color=blue" alt="Rust library on crates.io"></a>
<a href="https://pypi.org/project/vtracer/"><img src="https://img.shields.io/pypi/v/vtracer.svg?label=PyPI&color=blue" alt="Python package on PyPI"></a>
<a href="https://www.npmjs.com/package/@visioncortex/vtracer"><img src="https://img.shields.io/npm/v/@visioncortex/vtracer.svg?label=npm&color=blue" alt="Node package on npm"></a>
</p>
</div>
## Packages
VTracer 1.0 is a vectorization **framework** (pluggable frontends, curve fitters, color fitting, and output optimization) shipped across four surfaces from this repository:
| Package | Registry | Source | Use |
| --- | --- | --- | --- |
| `vtracer-cli` | [crates.io](https://crates.io/crates/vtracer-cli) | [`crates/vtracer-cli`](crates/vtracer-cli) | Command-line tool (`vtracer` binary) |
| `vtracer` | [crates.io](https://crates.io/crates/vtracer) | [`crates/vtracer`](crates/vtracer) | Rust library / the framework core |
| `vtracer` | [PyPI](https://pypi.org/project/vtracer/) | [`crates/vtracer-py`](crates/vtracer-py) | Python native extension (pyo3 + maturin) |
| `@visioncortex/vtracer` | [npm](https://www.npmjs.com/package/@visioncortex/vtracer) | [`nodejs`](nodejs) | Node.js WebAssembly build, no native dependency |
## 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. tl;dr: Potrace uses a `O(n^2)` fitting algorithm, whereas `vtracer` is entirely `O(n)`.
Comparing to Potrace, VTracer has an image processing pipeline which can handle colored images. VTracer skips Potrace's expensive optimal-polygon search in favor of a fast, linear pipeline that stays faithful to high-resolution images.
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.
Comparing to Adobe Illustrator's Image Trace, VTracer's output is much more compact 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.
@@ -50,28 +39,50 @@ Technical descriptions of the [tracing algorithm](https://www.visioncortex.org/v
![screenshot](docs/images/desktop-app.png)
The familiar web-app workflow, now on the native 1.0 engine:
VTracer App powered by the 1.0 tracing engine:
+ **Native speed** — the engine runs natively instead of in-browser wasm, so conversions are quicker
+ **A/B comparator** — a sliding split view to check the trace against the original
+ **Curve inspector** — examine the fitted curves up close
+ **Seam-free cutout** — a true gapless tessellation with shared boundaries, no cracks between shapes
+ **Watershed clustering** — content-adaptive regions that follow object shape, with one interactive detail slider
+ **Curve simplification** — the fewest curves within a pixel tolerance, typically halving file size
+ **Adaptive B/W thresholding** — handles scans and photos with uneven lighting
+ **Fixed color palettes** snap the output to your own colors
+ **Native speed**: faster conversions on large images
+ **A/B comparator**: compare the trace against the original
+ **Curve inspector**: inspect fitted curves up close
+ **Curve simplification**: fewer nodes, often half the file size
+ **Seam-free cutout**: gapless shapes with shared boundaries
+ **Watershed clustering**: edge-aware regions for sharper image traces
+ **Adaptive B/W thresholding**: cleaner traces from uneven scans and photos
+ **Fixed color palettes**: snap output to your own colors
## Cmd App
## Console App
Input and output can be given as positional arguments or as named flags:
You can download pre-built binaries from [Releases](https://github.com/visioncortex/vtracer/releases).
You can also install the program from source:
```sh
vtracer input.jpg output.svg
# equivalent to:
vtracer --input input.jpg --output output.svg
cargo install vtracer-cli
```
Full options (flag names are kebab-case, e.g. `--filter-speckle`):
### Usage
```sh
# simplest form
./vtracer input.jpg output.svg
# black & white line art
./vtracer input.jpg output.svg --preset bw
# scanned/photographed line art with uneven lighting
./vtracer scan.jpg output.svg --clustering bw --adaptive
# seam-free mosaic (gapless tessellation)
./vtracer input.jpg output.svg --hierarchical cutout
# watershed region forming, cut to taste
./vtracer photo.jpg output.svg --clustering watershed --watershed-detail 192
# constrain to a fixed palette
./vtracer input.jpg output.svg --palette '#1b1b1b,#e0c088,#5a7d3c,#8fb0d0'
```
Full options:
```sh
Usage: vtracer [OPTIONS] [INPUT] [OUTPUT]
@@ -100,7 +111,7 @@ Options:
--adaptive Binary mode: BradleyRoth adaptive threshold (uneven lighting)
--adaptive-window <ADAPTIVE_WINDOW> Adaptive window size in px (0 = auto); implies --adaptive
--adaptive-t <ADAPTIVE_T> Adaptive sensitivity: % below local mean (default 15)
--watershed-detail <WATERSHED_DETAIL> Watershed: hierarchy cut level 0..=255 (higher = more regions)
--watershed-detail <WATERSHED_DETAIL> Watershed: hierarchy cut level (default 128; higher = more regions, uncapped)
-h, --help Print help
-V, --version Print version
```
@@ -113,63 +124,38 @@ output size and smoothness.
### New in 1.0
- **Positional arguments** `vtracer in.png out.svg`.
- **Positional arguments**: `vtracer in.png out.svg`.
- **`--hierarchical cutout`** is now a true seam-free mosaic (a gapless
tessellation with shared boundaries), replacing the old re-clustered cutout.
- **`--palette` / `--palette-file`** snap colors to a fixed palette
- **`--palette` / `--palette-file`**: snap colors to a fixed palette
(nearest in OKLab); **`--max-colors`** auto-quantizes the palette.
- **Binary thresholding** a tunable fixed cutoff (`--threshold`) or
- **Binary thresholding**: a tunable fixed cutoff (`--threshold`) or
**BradleyRoth adaptive** thresholding (`--adaptive`, with `--adaptive-window`
/ `--adaptive-t`) for scans with uneven lighting.
- **`--simplify <tolerance>`** paper.js-style curve simplification: re-fits
- **`--simplify <tolerance>`**: paper.js-style curve simplification: re-fits
smooth runs with the fewest cubics that stay within the tolerance (px),
typically halving file size; seam-free in cutout mode because shared
boundaries are simplified once for both faces.
- **`--clustering watershed`** an alternative region-forming algorithm: a
- **`--clustering watershed`**: an alternative region-forming algorithm: a
hierarchical watershed on the pixel graph (Cousty et al., TPAMI 2009; Najman,
Cousty & Perret, ISMM 2013), cut at `--watershed-detail`. Content-adaptive
regions that follow object shape pairs beautifully with `cutout`.
regions that follow object shape: pairs beautifully with `cutout`.
## Downloads
## Programming Libraries
You can download pre-built binaries from [Releases](https://github.com/visioncortex/vtracer/releases).
VTracer 1.0 is a vectorization framework with pluggable stages: segmentation, curve fitting, color fitting, and output optimization — usable from the command line or as a library in Rust, Python, and JavaScript:
You can also install the program from source:
```sh
cargo install vtracer-cli
```
> You are strongly advised to not download from any other third-party sources
### Usage
```sh
# simplest form
./vtracer input.jpg output.svg
# black & white line art
./vtracer input.jpg output.svg --preset bw
# scanned/photographed line art with uneven lighting
./vtracer scan.jpg output.svg --clustering bw --adaptive
# seam-free mosaic (gapless tessellation)
./vtracer input.jpg output.svg --hierarchical cutout
# watershed region forming, cut to taste
./vtracer photo.jpg output.svg --clustering watershed --watershed-detail 192
# constrain to a fixed palette
./vtracer input.jpg output.svg --palette '#1b1b1b,#e0c088,#5a7d3c,#8fb0d0'
```
| Package | Registry | Source | Use |
| --- | --- | --- | --- |
| `vtracer-cli` | [crates.io](https://crates.io/crates/vtracer-cli) | [`crates/vtracer-cli`](crates/vtracer-cli) | Command-line tool (`vtracer` binary) |
| `vtracer` | [crates.io](https://crates.io/crates/vtracer) | [`crates/vtracer`](crates/vtracer) | Rust library / the framework core |
| `vtracer` | [PyPI](https://pypi.org/project/vtracer/) | [`crates/vtracer-py`](crates/vtracer-py) | Python native extension (pyo3 + maturin) |
| `@visioncortex/vtracer` | [npm](https://www.npmjs.com/package/@visioncortex/vtracer) | [`nodejs`](nodejs) | Node.js WebAssembly build, no native dependency |
### Rust Library
You can install [`vtracer`](https://crates.io/crates/vtracer) as a Rust library.
```sh
cargo add vtracer@1.0.0-alpha.3
cargo add vtracer@1.0.0-alpha.4
```
```rust
@@ -199,14 +185,12 @@ let seg = pipeline.segment(&img)?; // the expensive part
let doc = pipeline.finish(&seg)?; // VectorDoc, ready to serialize
```
See [docs.rs/vtracer](https://docs.rs/vtracer/1.0.0-alpha.3/vtracer/) for the full API.
See [docs.rs/vtracer](https://docs.rs/vtracer/1.0.0-alpha.4/vtracer/) for the full API.
### Python Library
[`vtracer`](https://pypi.org/project/vtracer/) is also packaged as a Python native extension.
```sh
pip install vtracer==1.0.0a3
pip install vtracer==1.0.0a4
```
```python
@@ -238,7 +222,7 @@ See [`crates/vtracer-py`](crates/vtracer-py/README.md) for the full API.
[`@visioncortex/vtracer`](https://www.npmjs.com/package/@visioncortex/vtracer) is available for Node as a WebAssembly build (from the [`nodejs`](nodejs/README.md) package) — image decoding and vectorization both run in wasm, so there is **no native dependency**. Decodes PNG, JPEG, GIF, BMP, and WebP; for other formats, decode yourself and pass raw RGBA to `convertPixels`.
```sh
npm install @visioncortex/vtracer@1.0.0-alpha.3
npm install @visioncortex/vtracer@1.0.0-alpha.4
```
```js
+34 -7
View File
@@ -64,8 +64,13 @@ pub struct FidelityReport {
fn dssim_score(a_rgb: &[u8], b_rgb: &[u8], w: usize, h: usize) -> f64 {
let d = dssim_core::Dssim::new();
let to = |buf: &[u8]| {
let px: Vec<rgb::RGB<u8>> =
(0..w * h).map(|i| rgb::RGB { r: buf[i * 3], g: buf[i * 3 + 1], b: buf[i * 3 + 2] }).collect();
let px: Vec<rgb::RGB<u8>> = (0..w * h)
.map(|i| rgb::RGB {
r: buf[i * 3],
g: buf[i * 3 + 1],
b: buf[i * 3 + 2],
})
.collect();
d.create_image_rgb(&px, w, h).expect("dssim image")
};
let (val, _) = d.compare(&to(a_rgb), &to(b_rgb));
@@ -75,7 +80,13 @@ fn dssim_score(a_rgb: &[u8], b_rgb: &[u8], w: usize, h: usize) -> f64 {
/// Compare an original against a candidate reconstruction, both RGB8, w×h.
/// `thresh` is the RGB Euclidean bad-pixel gate (use [`DEFAULT_THRESH`]).
/// Returns the report plus the bad-pixel mask (255/0, one byte per pixel).
pub fn fidelity(orig_rgb: &[u8], cand_rgb: &[u8], w: usize, h: usize, thresh: f64) -> (FidelityReport, Vec<u8>) {
pub fn fidelity(
orig_rgb: &[u8],
cand_rgb: &[u8],
w: usize,
h: usize,
thresh: f64,
) -> (FidelityReport, Vec<u8>) {
assert_eq!(orig_rgb.len(), w * h * 3);
assert_eq!(cand_rgb.len(), w * h * 3);
@@ -108,7 +119,11 @@ pub fn fidelity(orig_rgb: &[u8], cand_rgb: &[u8], w: usize, h: usize, thresh: f6
// the signature of a slightly blurred/compressed source) vanish; genuine
// missing patches survive. The reported mask keeps the raw bad pixels.
let at = |m: &[u8], x: i64, y: i64| {
x >= 0 && y >= 0 && (x as usize) < w && (y as usize) < h && m[y as usize * w + x as usize] != 0
x >= 0
&& y >= 0
&& (x as usize) < w
&& (y as usize) < h
&& m[y as usize * w + x as usize] != 0
};
let mut eroded = vec![0u8; w * h];
for y in 0..h as i64 {
@@ -142,7 +157,11 @@ pub fn fidelity(orig_rgb: &[u8], cand_rgb: &[u8], w: usize, h: usize, thresh: f6
let patch_mass = if sizes.is_empty() {
0.0
} else {
sizes.iter().map(|&a| (a as f64) * (a as f64)).sum::<f64>().sqrt()
sizes
.iter()
.map(|&a| (a as f64) * (a as f64))
.sum::<f64>()
.sqrt()
};
let p_frac = patch_mass / (w * h) as f64;
@@ -212,7 +231,12 @@ mod tests {
assert!((rd.s_patch - 1.0).abs() < 1e-9);
// identical PSNR/RMSE by construction; the patch axis must separate them
assert!((rb.rmse - rd.rmse).abs() < 1e-9);
assert!(rb.s_patch < rd.s_patch * 0.25, "blob {} dust {}", rb.s_patch, rd.s_patch);
assert!(
rb.s_patch < rd.s_patch * 0.25,
"blob {} dust {}",
rb.s_patch,
rd.s_patch
);
assert!(rb.fidelity < rd.fidelity);
}
@@ -231,7 +255,10 @@ mod tests {
let (rf, _) = fidelity(&clean, &fil, 64, 64, DEFAULT_THRESH);
assert_eq!(rf.bad_px, 128);
assert_eq!(rf.clusters, 0);
assert!((rf.s_patch - 1.0).abs() < 1e-9, "filament must not count as a patch");
assert!(
(rf.s_patch - 1.0).abs() < 1e-9,
"filament must not count as a patch"
);
}
#[test]
+13 -4
View File
@@ -7,7 +7,7 @@
//! metrics, their [0,1] subscores, the composite fidelity, and a
//! machine-readable csv line.
use vtracer_bench::{fidelity, DEFAULT_THRESH};
use vtracer_bench::{DEFAULT_THRESH, fidelity};
fn main() {
let args: Vec<String> = std::env::args().collect();
@@ -49,11 +49,20 @@ fn main() {
let (r, mask) = fidelity(orig.as_raw(), &cand, w, h, thresh);
if let Some(out) = mask_out {
image::GrayImage::from_raw(w as u32, h as u32, mask).unwrap().save(&out).expect("save mask");
image::GrayImage::from_raw(w as u32, h as u32, mask)
.unwrap()
.save(&out)
.expect("save mask");
}
println!("psnr {:>8.2} dB (rmse {:.2}) -> {:.4}", r.psnr, r.rmse, r.s_psnr);
println!("ssim {:>8.5} (dssim {:.5}) -> {:.4}", r.s_ssim, r.dssim, r.s_ssim);
println!(
"psnr {:>8.2} dB (rmse {:.2}) -> {:.4}",
r.psnr, r.rmse, r.s_psnr
);
println!(
"ssim {:>8.5} (dssim {:.5}) -> {:.4}",
r.s_ssim, r.dssim, r.s_ssim
);
println!(
"patch {:>8.1} px rms ({} bad px, {} clusters, largest {}) -> {:.4}",
r.patch_mass, r.bad_px, r.clusters, r.largest, r.s_patch
+1 -1
View File
@@ -15,7 +15,7 @@ name = "vtracer"
path = "src/main.rs"
[dependencies]
vtracer = { version = "1.0.0-alpha.3", path = "../vtracer" }
vtracer = { version = "1.0.0-alpha.4", path = "../vtracer" }
visioncortex.workspace = true
# Decode-only: trimmed to real input formats (drops the AV1 encoder + OpenEXR).
image = { version = "0.25", default-features = false, features = [
+3 -3
View File
@@ -120,9 +120,9 @@ struct Args {
#[arg(long)]
adaptive_t: Option<f64>,
/// Watershed clustering: hierarchy cut level (0..=255, higher = more regions).
#[arg(long, value_parser = clap::value_parser!(u8))]
watershed_detail: Option<u8>,
/// Watershed clustering: hierarchy cut level (default 128; higher = more regions, uncapped).
#[arg(long, value_parser = clap::value_parser!(u32))]
watershed_detail: Option<u32>,
}
fn parse_simplify_tolerance(s: &str) -> Result<f64, String> {
+2 -2
View File
@@ -1,7 +1,7 @@
[package]
name = "vtracer-py"
description = "Python bindings for the vtracer vectorization framework."
version = "1.0.0-alpha.3"
version = "1.0.0-alpha.4"
authors = ["Chris Tsang <tyt2y7@gmail.com>"]
edition = "2024"
license = "MIT OR Apache-2.0"
@@ -19,7 +19,7 @@ name = "vtracer"
crate-type = ["cdylib"]
[dependencies]
vtracer = { version = "1.0.0-alpha.3", path = "../vtracer" }
vtracer = { version = "1.0.0-alpha.4", path = "../vtracer" }
# Decode-only: trimmed to real input formats (drops the AV1 encoder + OpenEXR).
image = { version = "0.25", default-features = false, features = [
"png", "jpeg", "gif", "bmp", "webp", "tiff", "ico", "pnm", "tga", "qoi",
+36 -6
View File
@@ -1,14 +1,44 @@
<div align="center">
<img src="https://raw.githubusercontent.com/visioncortex/vtracer/master/docs/images/visioncortex-banner.png">
<h1>VTracer</h1>
<p>
<strong>Raster to Vector Graphics Converter</strong>
</p>
<h3>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_x64-setup.exe">Windows App</a>
<span> | </span>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_universal.dmg">macOS App</a>
<span> | </span>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_x64.AppImage">Linux App</a>
</h3>
</div>
# vtracer (Python)
Python bindings for the [`vtracer`](https://github.com/visioncortex/vtracer)
raster-to-vector framework. Built with [pyo3](https://pyo3.rs) +
[maturin](https://www.maturin.rs); the core Rust crate stays pure (no I/O), and
this crate adds image decoding and a Pythonic API.
Python bindings for [`vtracer`](https://github.com/visioncortex/vtracer). Built
with [pyo3](https://pyo3.rs) + [maturin](https://www.maturin.rs); the core Rust
crate stays pure (no I/O), and this crate adds image decoding and a Pythonic API.
## 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, VTracer has an image processing pipeline which can handle colored images. VTracer skips Potrace's expensive optimal-polygon search in favor of a fast, linear pipeline that stays faithful to high-resolution images.
Comparing to Adobe Illustrator's Image Trace, VTracer's output is much more compact 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.
Technical descriptions of the [tracing algorithm](https://www.visioncortex.org/vtracer-docs) and [clustering algorithm](https://www.visioncortex.org/impression-docs).
## Install
```sh
pip install vtracer==1.0.0a3
pip install vtracer==1.0.0a4
```
## Usage
@@ -60,7 +90,7 @@ properties, plus the presets `Config.bw()`, `Config.poster()`, `Config.photo()`:
| `adaptive` | `False` | bw: BradleyRoth adaptive thresholding |
| `adaptive_window` | `0` | bw adaptive: window px (`0` = auto) |
| `adaptive_t` | `15.0` | bw adaptive: % below local mean |
| `watershed_detail` | `128` | watershed: hierarchy cut level 0..=255 |
| `watershed_detail` | `128` | watershed: hierarchy cut level (higher = more regions, uncapped) |
Each `Config` has `convert_file(input, output)`, `convert_bytes(data, format=None) -> str`,
and `convert_pixels(rgba, width, height) -> str`.
+3 -3
View File
@@ -172,7 +172,7 @@ impl PyConfig {
adaptive: bool,
adaptive_window: u32,
adaptive_t: f64,
watershed_detail: u8,
watershed_detail: u32,
) -> PyResult<Self> {
let palette = match palette {
Some(list) => list.iter().map(|s| parse_hex(s)).collect::<PyResult<_>>()?,
@@ -241,11 +241,11 @@ impl PyConfig {
}
#[getter]
fn watershed_detail(&self) -> u8 {
fn watershed_detail(&self) -> u32 {
self.inner.watershed_detail
}
#[setter]
fn set_watershed_detail(&mut self, v: u8) {
fn set_watershed_detail(&mut self, v: u32) {
self.inner.watershed_detail = v;
}
+1 -1
View File
@@ -27,7 +27,7 @@ class Config:
adaptive: bool = False, # bw: BradleyRoth adaptive
adaptive_window: int = 0, # bw adaptive: window px (0 = auto)
adaptive_t: float = 15.0, # bw adaptive: % below local mean
watershed_detail: int = 128, # watershed: cut level 0..=255
watershed_detail: int = 128, # watershed: cut level (higher = more regions, uncapped)
) -> None: ...
@staticmethod
+31 -7
View File
@@ -30,31 +30,46 @@ pub enum Clustering {
Watershed,
}
/// How regions are combined into the final document.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Hierarchical {
/// Trace each layer independently and stack them in paint order (painter's
/// algorithm). Simple and robust; smoothed neighbours may drift slightly
/// apart along a shared edge.
Stacked,
/// True mosaic cutout — not yet implemented (separate milestone).
/// Seam-free, gapless mosaic: each shared boundary is fitted once and
/// referenced by both adjacent faces, so the tessellation never cracks.
/// See [`crate::mosaic`].
Cutout,
}
/// How a region's pixel outline is turned into vector geometry.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FitMode {
/// Exact pixel-lattice polyline; no smoothing.
Pixel,
/// DouglasPeucker polygon — straight edges, fewer points.
Polygon,
/// Corner detection plus least-squares cubic Béziers — smooth curves.
Spline,
}
/// A starting point for [`Config`], tuned for a common kind of input. See
/// [`Config::from_preset`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Preset {
/// Black-and-white line art (binary clustering).
Bw,
/// Flat, poster-like color with a fuller palette.
Poster,
/// Photographic input: heavier speckle filtering and coarser layering.
Photo,
}
/// The clustering-relevant projection of a [`Config`]. Two configs with equal
/// keys produce the same [`Segmentation`](crate::Segmentation), so a cached one
/// stays valid — this is what [`Session`](crate::Session) compares to decide
/// whether to re-segment. Kept in sync with [`Config::frontend`] in one place.
/// whether to re-segment. Produced by [`Config::segment_key`].
#[derive(Debug, Clone, PartialEq)]
pub struct SegmentKey {
clustering: Clustering,
@@ -65,7 +80,7 @@ pub struct SegmentKey {
binary_adaptive: bool,
binary_adaptive_window: u32,
binary_adaptive_t: f64,
watershed_detail: u8,
watershed_detail: u32,
}
/// High-level converter configuration. [`Config::build`] turns this into a
@@ -74,6 +89,8 @@ pub struct SegmentKey {
pub struct Config {
/// Region-forming algorithm (see [`Clustering`]).
pub clustering: Clustering,
/// How regions are combined — stacked layers or a seam-free mosaic (see
/// [`Hierarchical`]).
pub hierarchical: Hierarchical,
/// Speckle filter given as a side length; the area threshold is its square.
pub filter_speckle: usize,
@@ -81,11 +98,13 @@ pub struct Config {
pub color_precision: i32,
/// Color difference between gradient layers.
pub layer_difference: i32,
/// Curve-fitting mode (see [`FitMode`]).
pub mode: FitMode,
/// Corner threshold in degrees.
pub corner_threshold: i32,
/// Segment length threshold in pixels.
pub length_threshold: f64,
/// Maximum least-squares refinement iterations per spline segment.
pub max_iterations: usize,
/// Splice threshold in degrees.
pub splice_threshold: i32,
@@ -112,9 +131,10 @@ pub struct Config {
pub binary_adaptive_window: u32,
/// Adaptive sensitivity `t`: percent below the local mean (default 15).
pub binary_adaptive_t: f64,
/// Watershed clustering: where to cut the hierarchy (0..=255). Higher
/// keeps more regions; 0 collapses the image to a single region.
pub watershed_detail: u8,
/// Watershed clustering: where to cut the hierarchy. Higher keeps more
/// regions (each +25.5 roughly doubles the region count); 0 collapses the
/// image to a single region. Uncapped.
pub watershed_detail: u32,
}
impl Default for Config {
@@ -145,6 +165,8 @@ impl Default for Config {
}
impl Config {
/// Build a [`Config`] from a [`Preset`], adjusting the defaults for a
/// common kind of input.
pub fn from_preset(preset: Preset) -> Self {
match preset {
Preset::Bw => Self {
@@ -321,7 +343,9 @@ impl Config {
// apart (within a just-noticeable difference) from surviving
// as separate patches even at maximum detail.
merge_diff: match self.clustering {
Clustering::Watershed => ((255 - self.watershed_detail as i32) / 8).max(2),
Clustering::Watershed => {
(((255i64 - self.watershed_detail as i64) / 8).max(2)) as i32
}
_ => self.layer_difference,
},
},
+2
View File
@@ -1,3 +1,5 @@
//! The crate's [`Error`] type, returned by the pipeline and every stage.
use std::fmt;
/// Errors produced by the framework stages and the pipeline driver.
+3 -1
View File
@@ -3,7 +3,9 @@
//! Built-ins:
//! * [`ColorClusterFrontend`] — hierarchical color clustering (the classic
//! VTracer color path), including transparency keying.
//! * [`BinaryFrontend`] — threshold to black/white then cluster.
//! * [`BinaryFrontend`] — threshold to black/white then cluster; the
//! [`Threshold`] can be a fixed global cutoff or BradleyRoth adaptive
//! thresholding for unevenly-lit input.
//! * [`WatershedFrontend`] — hierarchical watershed on the pixel graph.
//!
//! Third parties can implement [`Frontend`] to feed external label maps or ML
+6 -1
View File
@@ -53,11 +53,16 @@ impl Default for Threshold {
/// Binary (black/white) frontend: threshold the image then cluster the
/// foreground. Every region is painted black.
///
/// The [`Threshold`] chooses how foreground is separated from background — a
/// fixed global cutoff ([`Threshold::Fixed`]) or BradleyRoth adaptive
/// thresholding ([`Threshold::Adaptive`]) for scans and photos with uneven
/// lighting.
///
/// Speckle removal drops clusters smaller than `min_area` px as the clusters
/// are collected, matching the pre-1.0 binary path (`cluster.size() >= area`).
#[derive(Debug, Clone)]
pub struct BinaryFrontend {
/// How foreground pixels are selected.
/// How foreground pixels are selected (see [`Threshold`]).
pub threshold: Threshold,
/// Whether to connect clusters diagonally.
pub diagonal: bool,
+9 -5
View File
@@ -53,9 +53,10 @@ const ANCESTOR_AREA_BUDGET: usize = 3;
/// Watershed frontend: hierarchical watershed by volume, cut at `detail`.
#[derive(Debug, Clone)]
pub struct WatershedFrontend {
/// Detail level (0..=255): where to cut the hierarchy. Each +25.5 roughly
/// doubles the region count; 0 collapses the image to a single region.
pub detail: u8,
/// Detail level: where to cut the hierarchy. The normal range is 0..=255
/// each +25.5 roughly doubles the region count, 0 collapses the image to a
/// single region. Values above 255 are practically uncapped.
pub detail: u32,
/// Absorb regions smaller than this many pixels into their most
/// color-similar neighbour after the cut (0 = keep all).
pub min_area: usize,
@@ -268,7 +269,7 @@ impl WatershedHierarchy {
/// Cut the hierarchy at `detail` and emit the stacked [`Segmentation`].
/// Near-linear; safe to call repeatedly with different parameters.
pub fn cut(&self, img: &ColorImage, detail: u8, min_area: usize) -> Segmentation {
pub fn cut(&self, img: &ColorImage, detail: u32, min_area: usize) -> Segmentation {
let (w, h) = (self.width, self.height);
let n = w * h;
let m = self.mst.len();
@@ -279,7 +280,10 @@ impl WatershedHierarchy {
// merge a little more). The persistence distribution is extremely
// skewed — most merges are trivia at ≈ 0 — so the dial maps to a
// region *count*, exponentially: every +25.5 of detail doubles the
// target, from 1 region at 0 up to 1024 at 255.
// target, from 1 region at 0. The target saturates at the edge count,
// so a large detail (≥ 25.5·log2(pixels), e.g. ≥ 612 for a 4096²
// image) is practically uncapped: λ = min persistence, keeping every
// basin above the zero-persistence trivia.
let mut uf = Uf::new(n);
if m > 0 {
let target = (2f64).powf(detail as f64 / 25.5).round() as usize;
+65 -16
View File
@@ -1,33 +1,82 @@
//! # vtracer
//!
//! A vectorization *framework*: raster images become vector graphics through a
//! pipeline of pluggable stages.
//! Convert raster images into vector graphics (SVG). VTracer is a
//! *framework*: the conversion runs as a pipeline of small, swappable stages,
//! so you can reach for a one-line convenience call or rebuild the pipeline
//! stage by stage.
//!
//! ## The pipeline
//!
//! ```text
//! Frontend ─▶ ColorFitter* ─▶ Compositing ─▶ CurveFitter ─▶ CurvePass* ─▶ VectorDoc
//! │
//! OptimizerPass* ─────┤
//! ▼
//! SvgWriter ─▶ SVG
//! image ──▶ Frontend ─▶ ColorFitter ─▶ Compositing ─▶ Optimizer ─SvgWriter ──▶ SVG
//! ```
//!
//! The crate is wasm-safe: it performs no file or image I/O (that lives in the
//! `vtracer-cli` wrapper). Everything here compiles to
//! `wasm32-unknown-unknown`.
//! Two intermediate representations carry the work between stages:
//!
//! * a [`Segmentation`] — the frontend's output: flat-color regions (paint
//! layers) over the canvas, which the color fitters may recolor or quantize;
//! * a [`VectorDoc`] — the output document: resolved shapes with fitted vector
//! paths, which the optimizer passes shrink and the writer serializes.
//!
//! Compositing is where the geometry is built — it runs the curve
//! [`CurveFitter`](fitter::CurveFitter) on each region outline, then any
//! geometry [`CurvePass`](simplify::CurvePass)es (curve simplification and the
//! like) over the fitted curves. Every stage is a trait in its own module, and
//! most can run more than once (a chain of color fitters, several optimizer
//! passes):
//!
//! | Stage | Trait | Module |
//! |---|---|---|
//! | Region forming | [`Frontend`](frontend::Frontend) | [`frontend`] |
//! | Recolor / quantize | [`ColorFitter`](colorfit::ColorFitter) | [`colorfit`] |
//! | Curve fitting | [`CurveFitter`](fitter::CurveFitter) | [`fitter`] |
//! | Geometry passes | [`CurvePass`](simplify::CurvePass) | [`simplify`] |
//! | Compositing | *(stacked or mosaic)* | [`compose`], [`mosaic`] |
//! | Optimization | [`OptimizerPass`](optimize::OptimizerPass) | [`optimize`] |
//! | Serialization | *(SVG writer)* | [`svg`] |
//!
//! ## Quick start
//!
//! ```no_run
//! use vtracer::{Config, ColorImage};
//! [`Config`] is the high-level entry point: choose options (or start from a
//! [`Preset`]), [`build`](Config::build) a [`Pipeline`], and run it. The crate
//! does no image decoding — hand it a decoded [`ColorImage`] and get back an
//! SVG string.
//!
//! ```no_run
//! use vtracer::{Config, ColorImage, Preset};
//! # fn load() -> ColorImage { todo!() }
//! let img: ColorImage = load();
//! let svg = Config::default().build().unwrap().to_svg(&img).unwrap();
//!
//! // one-shot: image → SVG string, all defaults
//! let svg = Config::default().build()?.to_svg(&img)?;
//!
//! // start from a preset and tweak
//! let mut cfg = Config::from_preset(Preset::Poster);
//! cfg.simplify = Some(1.5); // paper.js-style curve simplification
//! let svg = cfg.build()?.to_svg(&img)?;
//! # Ok::<(), vtracer::Error>(())
//! ```
//!
//! For finer control, assemble a [`Pipeline`] directly from the stage traits
//! in [`frontend`], [`colorfit`], [`fitter`], [`simplify`], [`compose`],
//! [`optimize`], and [`svg`].
//! ## Interactive tuning
//!
//! Segmentation is the expensive stage. A [`Session`] caches it and re-renders
//! only the cheap downstream stages when a non-clustering parameter changes,
//! re-segmenting automatically when it must — ideal behind a live UI with
//! sliders. See the [`session`] module.
//!
//! ## Extending the pipeline
//!
//! Build a [`Pipeline`] by hand to mix in your own stages: implement
//! [`Frontend`](frontend::Frontend) to feed an external label map or ML
//! segmentation, [`ColorFitter`](colorfit::ColorFitter) for a custom palette
//! policy, or [`CurvePass`](simplify::CurvePass) for a geometry transform.
//!
//! ## No I/O, wasm-safe
//!
//! Because it performs no file or image I/O, the crate compiles cleanly to
//! `wasm32-unknown-unknown`. Decoding and file handling live in the wrappers:
//! the `vtracer-cli` command-line tool, the `vtracer` Python package, and the
//! `@visioncortex/vtracer` Node package.
pub mod colorfit;
pub mod compose;
+1 -1
View File
@@ -3,7 +3,7 @@
//!
//! A desktop app loads an image once, then calls [`Session::render`] on every
//! slider change with a fresh [`Config`]. The session compares the config's
//! [`SegmentKey`](crate::config::SegmentKey) to what it last clustered and
//! [`SegmentKey`] to what it last clustered and
//! re-segments only if a clustering parameter changed — the caller never has to
//! know which parameters those are.
//!
+4 -4
View File
@@ -78,7 +78,7 @@ fn regions(seg: &Segmentation) -> usize {
#[test]
fn flat_image_is_one_region() {
let img = image(24, 16, |_, _| (90, 120, 150));
for detail in [0u8, 128, 255] {
for detail in [0u32, 128, 255] {
let seg = WatershedFrontend {
detail,
min_area: 0,
@@ -127,7 +127,7 @@ fn detail_is_monotone() {
(r, g, 128)
});
let mut prev = 0usize;
for detail in [0u8, 64, 128, 192, 255] {
for detail in [0u32, 64, 128, 192, 255] {
let seg = WatershedFrontend {
detail,
min_area: 0,
@@ -202,7 +202,7 @@ fn hierarchy_recut_matches_one_shot() {
(((x * 5 + y * 3) % 200) as u8, ((x / 8) * 30) as u8, ((y / 8) * 40) as u8)
});
let hierarchy = WatershedHierarchy::build(&img).unwrap();
for detail in [64u8, 128, 200] {
for detail in [64u32, 128, 200] {
let recut = hierarchy.cut(&img, detail, 16);
let one_shot = WatershedFrontend {
detail,
@@ -231,7 +231,7 @@ fn session_recut_matches_one_shot() {
clustering: Clustering::Watershed,
..Config::default()
};
for detail in [128u8, 200, 64] {
for detail in [128u32, 200, 64] {
let cfg = Config {
watershed_detail: detail,
..base.clone()
-72
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
-3
View File
@@ -1,3 +0,0 @@
Copyright (c) 2020 Tsang Hao Fung
The content in the /docs directory is for GitHub pages, and is not covered under open source licenses.
-543
View File
@@ -1,543 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="2800px" height="2800px" viewBox="0 0 2800 2800" enable-background="new 0 0 2800 2800" xml:space="preserve">
<g>
<g>
<polygon fill="#333333" points="2442.8,1360 1625.1,1360 1728.1,1158.7 1625.1,970.2 2442.8,970.2 2347.8,1163.5 "/>
<g>
<path fill="#FFFFFF" d="M1875,1170.5c6.3,6.8,9.5,15.3,9.5,25.5l-9.3,117c0,5.6-5.2,9.3-15.6,11.1c-10.4,1.9-19.9,2.8-28.6,2.8
h-63.2V997.3h61.8c10.8,0,21.1,2.6,30.9,7.9c9.8,5.3,14.6,12.2,14.6,20.9v93.3l-19,38.5C1862.3,1159.6,1868.6,1163.7,1875,1170.5
z M1802.8,1142.7h33.4c0.9,0,2-0.6,3.3-1.9c0.3-0.3,0.6-1.1,0.9-2.3l4.2-111c0-1.2-2.2-1.9-6.5-1.9l-40.9,1.9V1139
C1797.2,1141.4,1799,1142.7,1802.8,1142.7z M1845.9,1275.9c0-1.9-0.3-2.8-0.9-2.8V1178c0.9-0.6,1.4-1.1,1.4-1.4
c0-0.9-1.1-1.4-3.3-1.4l-35.3-4.6c-0.9,0-1.9,0.3-3,0.9c-1.1,0.6-1.8,1.2-2.1,1.9v126.3l5.1,1.4
C1833.2,1291.7,1845.9,1283.4,1845.9,1275.9z"/>
<path fill="#FFFFFF" d="M2028.4,1327h-99.4V997.3h99.4v28.8l-58-2.8v105.4l58,10.7v22.3l-65.9-2.8v133.3l65.9-3.7V1327z"/>
<path fill="#FFFFFF" d="M2150.5,1062.8l-9.3-36.2l-27.9,3.3l-7,103.1l67.3,12.1l-6.5,154.2c0,6.2-4,12.4-12.1,18.6
c-8.1,6.2-15.5,9.3-22.3,9.3h-54.3l-4.2-79.4h27.4l-0.5,40.4l32.5,7.4l7.4-123.5l-62.7-13.9v-149.5l18.6-11.1h72.9l-2.3,65.5
H2150.5z"/>
<path fill="#FFFFFF" d="M2304.7,1003.8l2.3,29.3h-40.9V1327h-39.5l9.3-285.6l-33.4-11.1l6-33L2304.7,1003.8z"/>
</g>
</g>
<g>
<polygon fill="#333333" points="1660.5,2001.3 167.9,2001.3 356,1714.2 167.9,1445.3 1660.5,1445.3 1487.1,1721 "/>
<g>
<path fill="#FFFFFF" d="M462.7,1802.5c0,16.1,0.8,29.1,2.6,39c1.7,9.9,3.9,17.6,6.7,23c2.8,5.4,6,9.1,9.5,10.9
c3.6,1.9,7.2,2.8,10.9,2.8c4.3,0,8-0.5,10.9-1.4c2.9-0.9,5.6-2.2,8.1-3.7l4.6,4.2c-3.4,8-8,14-13.7,17.9
c-5.7,3.9-12.2,5.8-19.3,5.8c-9,0-16.5-1.9-22.5-5.6c-6-3.7-9.1-8.7-9.1-14.9c-12.7,0-21-5.4-24.8-16.3
c-3.9-10.8-5.8-26.8-5.8-47.8v-154.2h-30.6v-21.8h2.8c8.4,0,15.6-1.9,21.6-5.8c6-3.9,11.3-8.9,15.8-15.1
c4.5-6.2,8.4-13.2,11.6-21.1c3.3-7.9,6.3-15.9,9.1-23.9h11.6v65.9c11.1-0.3,20.4-1.2,27.6-2.6c7.3-1.4,12.6-3.8,16-7.2
c7.1,1.2,11.8,3.8,13.9,7.7c2.2,3.9,3.3,7.2,3.3,10c0,3.7-1.2,6.9-3.5,9.5c-2.3,2.6-5.4,4.7-9.3,6.3c-3.9,1.6-8.3,2.6-13.2,3.3
c-5,0.6-9.9,0.9-14.9,0.9c-6.8,0-13.5-0.5-20-1.4V1802.5z"/>
<path fill="#FFFFFF" d="M607.6,1807.1c0,6.2,1,11.3,3,15.3c2,4,4.5,7.3,7.4,9.8c2.9,2.5,6.3,4.3,10.2,5.3
c3.9,1.1,7.7,1.6,11.4,1.6v13.9c-3.7,0-7.8-0.2-12.3-0.7c-4.5-0.5-9.2-1-14.2-1.6c-5-0.6-9.7-1.2-14.2-1.6
c-4.5-0.5-8.6-0.7-12.3-0.7c-3.7,0-7.8,0.2-12.3,0.7c-4.5,0.5-9.2,1-14.2,1.6c-5,0.6-9.7,1.2-14.2,1.6c-4.5,0.5-8.6,0.7-12.3,0.7
v-13.9c8.4,0,15.8-2.3,22.3-7c6.5-4.6,9.8-13,9.8-25.1v-240.5c0-11.4-0.2-21-0.7-28.6c-0.5-7.6-1.8-13.5-3.9-17.6
c-2.2-4.2-5.3-7.1-9.3-8.8c-4-1.7-9.6-2.6-16.7-2.6v-11.6c7.7,0,14.5-0.5,20.2-1.4c5.7-0.9,10.9-2.3,15.6-4.2
c4.6-1.9,8.9-4,12.8-6.5c3.9-2.5,8-5.1,12.3-7.9h11.6v195.5c3.1-4.9,6.8-9.7,11.1-14.2c4.3-4.5,9.4-8.4,15.3-11.8
c5.9-3.4,12.7-6.1,20.4-8.1c7.7-2,16.7-3,26.9-3c13,0,24.6,2,34.8,6c10.2,4,18.8,10.4,25.8,19.3c7,8.8,12.2,20.3,15.8,34.4
c3.6,14.1,5.3,31.2,5.3,51.3v55.3c0,19.8,0.7,35.8,2.1,47.8c1.4,12.1,3.3,21.4,5.6,27.9c2.3,6.5,5.1,10.8,8.4,13
c3.3,2.2,6.6,3.3,10,3.3c3.4,0,6.5-0.2,9.3-0.7c2.8-0.5,5.9-1.9,9.3-4.4l2.3,1.9c-3.4,8.4-8.5,15.1-15.3,20.2
c-6.8,5.1-14.2,7.7-22.3,7.7c-8.1,0-15.2-2.5-21.4-7.4c-6.2-5-9.3-11.6-9.3-20c-4-2.2-7.4-4.4-10-6.7c-2.6-2.3-4.7-5.7-6.3-10
c-1.6-4.3-2.6-10.1-3.3-17.4c-0.6-7.3-0.9-16.9-0.9-29v-71c0-19.5-1.1-35.6-3.2-48.3c-2.2-12.7-5.3-22.8-9.3-30.4
c-4-7.6-8.9-12.9-14.6-16c-5.7-3.1-12-4.6-18.8-4.6c-7.1,0-14.7,1.5-22.8,4.4c-8.1,2.9-15.4,7.7-22.1,14.4
c-6.7,6.7-12.2,15.3-16.5,26c-4.3,10.7-6.5,23.6-6.5,38.8V1807.1z"/>
<path fill="#FFFFFF" d="M883.4,1807.1c0,6.2,1,11.3,3,15.3c2,4,4.5,7.3,7.4,9.8c2.9,2.5,6.3,4.3,10.2,5.3
c3.9,1.1,7.7,1.6,11.4,1.6v13.9c-3.7,0-7.8-0.2-12.3-0.7c-4.5-0.5-9.2-1-14.2-1.6c-5-0.6-9.7-1.2-14.2-1.6
c-4.5-0.5-8.6-0.7-12.3-0.7s-7.8,0.2-12.3,0.7c-4.5,0.5-9.2,1-14.2,1.6c-5,0.6-9.7,1.2-14.2,1.6c-4.5,0.5-8.6,0.7-12.3,0.7v-13.9
c8.4,0,15.8-2.3,22.3-7c6.5-4.6,9.8-13,9.8-25.1v-79.9c0-11.4-0.2-21-0.7-28.6c-0.5-7.6-1.8-13.5-3.9-17.6
c-2.2-4.2-5.3-7.1-9.3-8.8c-4-1.7-9.6-2.6-16.7-2.6v-13.9c7.7,0,14.3-0.5,19.7-1.4c5.4-0.9,10.3-2.3,14.6-4.2
c4.3-1.9,8.4-4,12.1-6.5c3.7-2.5,7.7-5.1,12.1-7.9h13.9V1807.1z M830.9,1567.1c0-9.3,3.3-17.1,9.8-23.5
c6.5-6.3,14.2-9.5,23.2-9.5c9,0,16.6,3.2,23,9.5c6.3,6.3,9.5,14.2,9.5,23.5c0,9.3-3.2,17.1-9.5,23.4c-6.3,6.3-14,9.5-23,9.5
c-9,0-16.7-3.2-23.2-9.5C834.2,1584.2,830.9,1576.4,830.9,1567.1z"/>
<path fill="#FFFFFF" d="M1123.9,1766.3c0-20.7-1-38.1-3-52c-2-13.9-5-25.1-9.1-33.4c-4-8.4-9.1-14.3-15.3-17.9
c-6.2-3.6-13.3-5.3-21.4-5.3c-8.1,0-15.7,1.6-23,4.6c-7.3,3.1-13.7,8-19.3,14.6c-5.6,6.7-10,15.3-13.2,26
c-3.3,10.7-4.9,23.4-4.9,38.3v65.9c0,6.2,1,11.3,3,15.3c2,4,4.5,7.3,7.4,9.8c2.9,2.5,6.3,4.3,10.2,5.3c3.9,1.1,7.7,1.6,11.4,1.6
v13.9c-3.7,0-7.8-0.2-12.3-0.7c-4.5-0.5-9.2-1-14.2-1.6c-5-0.6-9.7-1.2-14.2-1.6c-4.5-0.5-8.6-0.7-12.3-0.7s-7.8,0.2-12.3,0.7
c-4.5,0.5-9.2,1-14.2,1.6c-5,0.6-9.7,1.2-14.2,1.6c-4.5,0.5-8.6,0.7-12.3,0.7v-13.9c8.4,0,15.8-2.3,22.3-7s9.8-13,9.8-25.1v-77.5
c0-11.4-0.2-21-0.7-28.6c-0.5-7.6-1.8-13.5-3.9-17.6c-2.2-4.2-5.3-7.1-9.3-8.8c-4-1.7-9.6-2.6-16.7-2.6v-11.6
c7.7,0,14.5-0.5,20.2-1.4c5.7-0.9,10.9-2.3,15.6-4.2c4.6-1.9,8.9-4,12.8-6.5c3.9-2.5,8-5.1,12.3-7.9h11.6v32.5
c5.9-10.8,14-19.7,24.4-26.7c10.4-7,22.7-10.4,36.9-10.4c30.6,0,53.2,9.3,67.8,27.9c14.5,18.6,21.8,49.4,21.8,92.4v48.8
c0,6.2,1,11.3,3,15.3c2,4,4.5,7.3,7.4,9.8c2.9,2.5,6.3,4.3,10.2,5.3c3.9,1.1,7.7,1.6,11.4,1.6v16.3c-4,0-7.6-0.2-10.7-0.7
c-3.1-0.5-6.3-0.9-9.5-1.4c-3.3-0.5-7-0.9-11.1-1.4c-4.2-0.5-9.2-0.7-15.1-0.7c-4,0-8.6,0.2-13.7,0.7c-5.1,0.5-11.2,1.6-18.3,3.5
l-4.2-7.9c2.2-2.2,3.9-6.1,5.1-11.8c1.2-5.7,2.1-12.3,2.6-19.7c0.5-7.4,0.8-15.3,0.9-23.7
C1123.8,1781.6,1123.9,1773.7,1123.9,1766.3z"/>
<path fill="#FFFFFF" d="M1326.4,1859.6c-16.7,0-31.4-2.8-44.1-8.4c-12.7-5.6-23.4-13.4-32-23.4c-8.7-10.1-15.2-22.1-19.5-36
c-4.3-13.9-6.5-29.3-6.5-46c0-19.5,3-36.1,9.1-49.9c6-13.8,13.9-25.1,23.7-34.1c9.8-9,20.9-15.6,33.4-19.7
c12.5-4.2,25.3-6.3,38.3-6.3c13.9,0,26.3,2.1,37.1,6.3c10.8,4.2,20.9,12.6,30.2,25.3c1.9-6.8,4.8-12,8.8-15.6
c4-3.6,8.7-6.2,13.9-7.9c5.3-1.7,10.8-2.7,16.7-3c5.9-0.3,11.6-0.5,17.2-0.5v13.9c-4,0-7.4,0.9-10,2.6c-2.6,1.7-4.6,6.2-6,13.5
c-1.4,7.3-2.3,18.1-2.8,32.5c-0.5,14.4-0.7,34.3-0.7,59.7v105.9c0,35.3-8.8,60.9-26.2,76.8c-17.5,15.9-45,23.9-82.4,23.9
c-22.9,0-39.9-2.5-50.8-7.4c-11-5-16.5-11.1-16.5-18.6c-8.1,0-13.8-2.7-17.2-8.1c-3.4-5.4-5.1-10.9-5.1-16.5
c0-5.3,1.2-9.8,3.7-13.7c2.5-3.9,5.6-7,9.3-9.5c3.7-2.5,7.7-4.3,11.8-5.6c4.2-1.2,8-1.9,11.4-1.9c0,8.4,1,16.2,3,23.4
c2,7.3,5.3,13.6,10,19c4.6,5.4,10.6,9.8,17.9,13c7.3,3.3,16.2,4.9,26.7,4.9c9.3,0,17.8-1.4,25.5-4.2c7.7-2.8,14.3-7.4,19.7-13.9
c5.4-6.5,9.7-15,12.8-25.5c3.1-10.5,4.6-23.5,4.6-39v-30.2c-10.5,10.2-21.4,16.8-32.5,19.7
C1347.7,1858.1,1336.9,1859.6,1326.4,1859.6z M1333.3,1838.3c10.5,0,19.8-2.4,27.9-7.2c8-4.8,14.6-11.4,19.7-19.7
c5.1-8.4,9-18,11.6-29c2.6-11,3.9-22.8,3.9-35.5c0-12.1-1.2-23.4-3.7-34.1c-2.5-10.7-6.3-20.1-11.6-28.3
c-5.3-8.2-11.8-14.6-19.7-19.3c-7.9-4.6-17.4-7-28.6-7c-12.1,0-22.3,2.2-30.6,6.7c-8.4,4.5-15,10.7-20,18.6
c-5,7.9-8.5,17.2-10.7,27.9c-2.2,10.7-3.3,22.2-3.3,34.6c0,12.1,1,23.7,3,34.8c2,11.1,5.6,21,10.7,29.5
c5.1,8.5,11.8,15.3,20,20.4C1310.2,1835.7,1320.6,1838.3,1333.3,1838.3z"/>
</g>
</g>
<g>
<rect x="1813.5" y="1662.1" fill="#CFD3D2" width="656.6" height="174.5"/>
<g>
<path fill="#333333" d="M2034.1,1630.7c0-6.5,1.7-17.6,5.1-33.4c3.4-15.8,8-30.8,13.9-45c6.2-15.8,12.5-23.7,19-23.7
c5.6,0,8.4,3.4,8.4,10.2c0,13-2.2,27.5-6.7,43.4c-4.5,15.9-10.1,29.5-16.9,40.6c-7.1,10.8-13.5,16.3-19,16.3
C2035.3,1638.4,2034.1,1635.7,2034.1,1630.7z"/>
<path fill="#333333" d="M2542.5,1744c-11.7-13.9-25.5-25.6-38.3-38.3c-5.5-5.4-14,3-8.5,8.5c9.6,9.5,19.7,18.4,29,28.1h-179.6
c-0.1-8.6-0.4-15.7-0.8-21h11.6c3.1,0.6,7.4,0.9,13,0.9c4.3,0,7.9-1.2,10.7-3.5s4.2-5.2,4.2-8.6c0-8.7-7.4-13-22.3-13
c-3.7,0-6.8,0.2-9.3,0.5l-7.4,0.5l-1.4-7.4c0-7.4,0.5-18.6,1.4-33.4c0.3-9.9,0.5-21,0.5-33.4c0-8.7-0.2-15.3-0.5-20
c10.5,1.6,22.3,4.6,35.3,9.3c3.7-1.5,6.9-3.6,9.5-6.3c2.6-2.6,3.9-5.5,3.9-8.6c0-5.6-6.7-10.4-20.2-14.4c-13.5-4-25.3-6-35.5-6
c-13,0-19.5,11-19.5,33c0,4,0.5,10.5,1.4,19.5c0.9,8.7,1.4,15.2,1.4,19.5c0,18.3-0.6,40.9-1.9,67.8c-0.3,8.9-0.5,17.1-0.7,24.7
H2240c0.3-3.6,0.5-7.2,0.8-10.8c1.2-16.7,2.6-28.9,3.9-36.7c1.4-7.7,4.3-19.3,8.6-34.8c5.3-17.9,9.2-33.4,11.8-46.2
c2.6-12.8,3.9-24.8,3.9-36c0-2.8-1.1-5.2-3.2-7.2c-2.2-2-4.6-3-7.4-3h-10.2c-3.4,20.1-9.3,57.7-17.6,112.8
c-3.6,22.5-6.9,43.1-10,61.9h-26.9c-5.2-35.6-9.6-62.2-13.2-79.5c-4-18.6-7.7-34.1-11.1-46.7c-3.4-12.5-7.1-22.5-11.1-29.9
c-4-7.7-8.4-11.6-13-11.6c-2.8,0-5.3,1.1-7.7,3.3c-2.3,2.2-3.5,4.6-3.5,7.4c0,4.6,2.8,15.6,8.4,33c2.2,6.5,3.6,11.3,4.2,14.4
c10.7,41.4,19.2,77.9,25.7,109.7h-233.7c-0.7-12.5-1.4-25.9-2.3-40.1c-4-57.6-6-102.8-6-135.6c0-3.7,0.7-6.3,2.1-7.7
c1.4-1.4,3.6-2.1,6.7-2.1h3.7c1.2,0.3,2.8,0.5,4.6,0.5c3.1,0,5.6-1.2,7.7-3.7c2-2.5,3-5.4,3-8.8c0-3.4-1.3-6.3-3.9-8.8
c-2.6-2.5-5.8-3.7-9.5-3.7c-9,0-20,1.1-33,3.2c-7.1,1.2-12.9,3.2-17.4,6c-4.5,2.8-6.7,6-6.7,9.8c0,7.4,3.6,11.1,10.7,11.1
c3.7,0,7.3-0.6,10.7-1.9c0.9,6.8,1.4,15.3,1.4,25.5l-0.5,23.7c-0.3,7.1-0.5,15-0.5,23.7c0,24.1,1.4,59.9,4.2,107.3
c0,0.5,0.1,1,0.1,1.5h-99.8c-1.9-5.7-4.5-11.6-7.4-16.5c-1.7-2.9-4.4-5.2-7.3-6.8c1.7-4.6-5.2-10.1-10.3-6.1
c-4.9,3.8-7.5,10.6-0.7,14.2c2.5,1.4,5.1,1.9,7.3,3.9c2.7,2.5,3.9,7.8,5.4,11.3h-9.8c-7.1-7.8-12.6-17-20-24.6
c-5.4-5.6-13.8,2.9-8.5,8.5c4.8,5,8.8,10.6,13,16.1h-13.6c-7.7,0-7.7,12,0,12h13.7c-5.7,6.4-11.6,12.7-16.5,19.7
c-4.4,6.4,6,12.4,10.3,6c6.4-9.2,14.5-17.1,21.6-25.8h13.4c0,1.1-0.1,2.1-0.3,3.2c-2.1,8.4-10,16.1-15.3,22.5
c-4.9,5.9,3.5,14.4,8.5,8.5c8.2-9.9,18.8-21,19-34.2h98.2c2.5,39.2,3.8,70.6,3.8,94.2c0,4-0.5,6.8-1.6,8.4
c-1.1,1.6-2.9,2.3-5.3,2.3c-1.6,0-2.9-0.2-4.2-0.5h-5.6c-9.3,0-13.9,3.7-13.9,11.1c0,9.3,13.3,13.9,39.9,13.9
c2.5,0,9-0.3,19.5-0.9c4.6,0,7.7-0.1,9.3-0.2c1.5-0.2,2.5-0.2,2.8-0.2l11.6-7.9v-2.8c0-10.8-6.5-16.3-19.5-16.3
c-4,0-7.1,0.2-9.3,0.5v-17.6c0-20.9-0.9-48.9-2.6-84h235.4c1.2,6.2,2.3,12.3,3.3,18.1c6.7,38.1,10,74.9,10,110.5l8.8,7
c7.1,0,13.5-5.1,19-15.3c5.6-10.2,10.1-24.3,13.5-42.3c4.2-23.6,7.5-49.6,9.9-78h79.2c-0.3,12.5-0.4,22.9-0.4,31.1l0.9,29.7
c0.9,13.3,1.4,23.2,1.4,29.7c0,3.7,0.2,7,0.5,9.8v21.4c0.3,4,2.1,7.4,5.3,10.2c3.2,2.8,6.9,4.2,10.9,4.2h39.5
c5.6,0,10.3-1.2,14.2-3.5c3.9-2.3,5.8-5.6,5.8-10c0-7.4-5.9-11.1-17.6-11.1c-7.4,0-13.8,0.2-19,0.5l-15.3,0.5
c-0.6,0-0.9-8.7-0.9-26c0-9.3,0.5-23.4,1.4-42.3c0.3-12.4,0.5-26.3,0.5-41.8c0-0.8,0-1.5,0-2.3h181.5
c-6.3,9.5-11.7,19.5-17.6,29.3c-4,6.7,6.4,12.7,10.3,6c7.4-12.5,14-25.6,23-37.1C2544.6,1749.7,2544.8,1746.7,2542.5,1744z
M2205.4,1828c-0.9-5-2-13.2-3.3-24.6l-5.6-41.3l-1.2-7.9h23.1C2213.5,1783.9,2209.2,1808.5,2205.4,1828z"/>
</g>
</g>
<g>
<g>
<g>
<path fill="#F39DA3" d="M1303.8,2143.3c23.4,7.7,42.4,21.8,57,42.4c11.6,16.6,19.6,34.6,23.8,54c4.2,19.4,6.4,37.8,6.4,55.3
c0,44.4-8.9,82.1-26.8,112.9c-24.2,41.6-61.6,62.3-112.1,62.3h-144.1V2136H1252C1272.8,2136.3,1290,2138.7,1303.8,2143.3z
M1175.7,2194v218.1h64.5c33,0,56-16.2,69-48.7c7.1-17.8,10.7-39.1,10.7-63.7c0-34-5.3-60.1-16-78.3
c-10.7-18.2-31.9-27.3-63.7-27.3H1175.7z"/>
<path fill="#F39DA3" d="M1700.6,2440.5c-25.2,26-61.7,39-109.5,39c-47.8,0-84.3-13-109.5-39c-33.9-31.9-50.8-77.8-50.8-137.9
c0-61.2,16.9-107.2,50.8-137.9c25.2-26,61.7-39,109.5-39c47.8,0,84.3,13,109.5,39c33.7,30.7,50.6,76.6,50.6,137.9
C1751.2,2362.7,1734.3,2408.6,1700.6,2440.5z M1657,2389.7c16.2-20.4,24.4-49.4,24.4-87.1c0-37.5-8.1-66.5-24.4-86.9
c-16.2-20.5-38.2-30.7-65.9-30.7c-27.7,0-49.7,10.2-66.2,30.6c-16.5,20.4-24.7,49.4-24.7,87.1s8.2,66.7,24.7,87.1
c16.5,20.4,38.5,30.6,66.2,30.6C1618.8,2420.3,1640.7,2410.1,1657,2389.7z"/>
<path fill="#F39DA3" d="M1803.3,2136h73.2l132.7,233v-233h65.1v334.2h-69.8l-136.1-237.1v237.1h-65.1V2136z"/>
<path fill="#F39DA3" d="M2386.9,2195.2h-176.8v71h162.3v58h-162.3v85.9h185v60.1h-253.3V2136h245.1V2195.2z"/>
<path fill="#F39DA3" d="M2465.1,2137.1h71v84.7l-18.4,155.8H2484l-18.8-155.8V2137.1z M2466.7,2404.7h67.8v65.5h-67.8V2404.7z"
/>
</g>
</g>
<path d="M1200.7,2160.8h-69v227.1h69c34.9,0,59.5-17.4,73.2-51.6c7.3-18.3,11-40.3,11-65.4c0-34.7-5.6-61.8-16.6-80.6
C1256.8,2170.7,1234,2160.8,1200.7,2160.8z M1265.5,2333c-12.4,30.9-33.6,45.9-64.9,45.9h-60v-209.1h60c29.9,0,50.1,8.4,59.8,25.1
c10.2,17.4,15.4,43,15.4,76.1C1275.9,2294.9,1272.4,2315.8,1265.5,2333z M1324.9,2154.3c-15-21.3-35-36.1-59.2-44.1
c-14.1-4.7-32-7.2-53.1-7.5h-148.6v343.2h148.6c52,0,91-21.7,116-64.6c18.2-31.4,27.4-70.1,27.4-115.2c0-17.8-2.2-36.7-6.5-56.3
C1345.1,2190,1336.8,2171.3,1324.9,2154.3z M1320.7,2376.8c-11.6,20-26.6,35.2-44.5,45.1c-17.9,10-39.4,15-63.7,15h-139.6v-325.2
h139.5c20.2,0.3,37.1,2.7,50.4,7c22.4,7.4,40.8,21.1,54.7,40.7c11.2,16.1,19,33.7,23.1,52.3c4.1,18.9,6.3,37.2,6.3,54.4
C1346.9,2309.6,1338.1,2346.8,1320.7,2376.8z M1664.2,2132.8c-26-26.7-63.9-40.3-112.6-40.3c-48.7,0-86.6,13.5-112.6,40.3
c-34.6,31.4-52.2,78.9-52.2,141.1c0,61,17.5,108.4,52.1,141.1c26,26.7,63.9,40.3,112.7,40.3c48.8,0,86.7-13.6,112.7-40.3
c34.4-32.6,51.9-80.1,51.9-141.1C1716.1,2211.7,1698.7,2164.2,1664.2,2132.8z M1658,2408.5l-0.1,0.1c-24.2,25-60,37.6-106.3,37.6
c-46.3,0-82-12.7-106.3-37.6l-0.1-0.1c-32.8-30.9-49.4-76.1-49.4-134.6c0-59.6,16.6-104.9,49.3-134.5l0.2-0.2
c24.2-25,60-37.6,106.3-37.6c46.3,0,82,12.7,106.3,37.6l0.2,0.2c32.6,29.7,49.1,74.9,49.1,134.5
C1707.1,2332.3,1690.6,2377.6,1658,2408.5z M1551.6,2151.7c-29,0-52.4,10.9-69.7,32.3c-17.1,21.1-25.7,51.4-25.7,89.9
c0,38.5,8.7,68.8,25.7,89.9c17.3,21.4,40.7,32.3,69.7,32.3c29,0,52.3-10.9,69.4-32.3c16.8-21.1,25.4-51.4,25.4-89.9
c0-38.3-8.5-68.5-25.3-89.7C1603.9,2162.6,1580.5,2151.7,1551.6,2151.7z M1613.9,2358.1c-15.5,19.5-35.9,28.9-62.3,28.9
c-26.5,0-47-9.5-62.7-28.9c-15.7-19.5-23.7-47.8-23.7-84.2s8-64.7,23.7-84.2c15.7-19.5,36.2-28.9,62.7-28.9
c26.5,0,46.8,9.5,62.3,29c15.5,19.6,23.4,47.9,23.4,84.2C1637.3,2310.3,1629.4,2338.6,1613.9,2358.1z M1965.1,2323.3L1840.9,2105
l-1.3-2.3h-80.3v343.2h74.1v-224.7l128.9,224.7h76.9v-343.2h-74.1V2323.3z M1974.1,2111.7h56.1v325.2h-62.7l-143.2-249.5v249.5
h-56.1v-325.2h66.1l139.8,245.5V2111.7z M2175,2299.9h162.3v-67H2175v-62h176.8v-68.2h-254.1v343.2H2360v-69.1h-185V2299.9z
M2351,2385.9v51.1h-244.3v-325.2h236.1v50.2H2166v80h162.3v49H2166v94.9H2351z M2421.1,2103.9v89.2l19.3,160.3h41.8l18.8-159.8
l0-89.7H2421.1z M2492.1,2192.8l-17.9,151.6h-25.8l-18.3-151.6v-79.9h62V2192.8z M2422.7,2445.9h76.8v-74.5h-76.8V2445.9z
M2431.7,2380.4h58.8v56.5h-58.8V2380.4z"/>
</g>
<g>
<rect x="239.8" y="1074.9" fill="#E4DAD8" width="656.6" height="174.5"/>
<g>
<path fill="#333333" d="M458.5,1312.6c0-7.4,4.8-11.1,14.4-11.1h5.1l4.6,0.5c2.5,0,4.2-0.8,5.1-2.3c0.9-1.5,1.4-4.3,1.4-8.4
c0-5.3-0.3-13.5-0.9-24.6c-0.9-7.4-2-20.7-3.2-39.9c-2.8-47.4-4.2-83.1-4.2-107.3c0-8.7,0.2-16.6,0.5-23.7l0.5-23.7
c0-10.2-0.5-18.7-1.4-25.5c-5,1.2-8.5,1.9-10.7,1.9c-7.4,0-11.1-3.7-11.1-11.1c0-3.7,2.3-7,7-9.8c4.6-2.8,10.5-4.8,17.6-6
c12.4-2.5,23.4-3.7,33-3.7c3.7,0,6.9,1.3,9.5,3.9c2.6,2.6,3.9,5.7,3.9,9.1c0,3.4-1,6.3-3,8.8c-2,2.5-4.6,3.7-7.7,3.7
c-1.9,0-3.4-0.2-4.6-0.5h-3.7c-3.1,0-5.3,0.7-6.7,2.1c-1.4,1.4-2.1,3.9-2.1,7.7c0,30,1.9,75.2,5.6,135.6
c0.6,11.1,1.9,27.6,3.7,49.2c1.5,14.2,2.3,28.8,2.3,43.6v17.6c1.9-0.3,4.9-0.5,9.3-0.5c13,0,19.5,5.4,19.5,16.3v2.8l-11.6,7.9
c-0.3,0-1.3,0.1-3,0.2c-1.7,0.2-4.9,0.2-9.5,0.2c-9.9,0.6-16.3,0.9-19,0.9C472,1326.6,458.5,1321.9,458.5,1312.6z"/>
<path fill="#333333" d="M574.8,1327.5c-3.9-3.1-6.1-7.1-6.7-12.1l5.1-7.9c1.9,0,4.8,0.6,8.8,1.9c4.6,0.9,8.2,1.4,10.7,1.4
c5.6,0,10.6-2.5,15.1-7.4c4.5-4.9,7.8-11.4,10-19.5c4-14.9,6-28.2,6-39.9c0-20.4-6.5-41.9-19.5-64.5l-5.1-8.8
c-5.9-10.2-10.8-19.3-14.9-27.4c-4-8-7.4-16.7-10.2-26c-3.7-12.1-5.6-24.1-5.6-36.2c0-13.6,3.1-27.9,9.3-42.7
c3.1-7.1,7.5-12.9,13.2-17.4c5.7-4.5,12.1-6.7,19.3-6.7c5.6,0,10.8,1.8,15.6,5.3c4.8,3.6,7.2,7.8,7.2,12.8c0,2.8-1.1,5-3.3,6.5
c-2.2,1.6-4.8,2.3-7.9,2.3c-3.4,0-6.7-0.9-9.8-2.8c-6.8,0.3-12.2,6.3-16.3,18.1c-3.4,10.8-5.1,19.8-5.1,26.9c0,9,1.4,18,4.2,27.2
c2.8,9.1,6.3,17.4,10.7,24.8l10.2,18.6l16.3,30.6c4.3,8.7,7.8,18.7,10.4,30.2c2.6,11.5,3.9,23.1,3.9,34.8
c0,18.9-4.3,36.8-13,53.9c-4.3,8.7-10.4,15.6-18.3,20.9s-16.6,7.9-26.2,7.9v1.4C583.4,1332.6,578.7,1330.6,574.8,1327.5z"/>
</g>
<path fill="#333333" d="M428,1164c-20.7-23.1-45.4-42.6-64.7-67.1c-4.2-5.3-13.5,1.9-9.4,7.3c1.6,2,1.6,4.1,1.6,6.6
c0,4.9,4.9,6.7,8.4,5.4c16.1,18,34.6,33.8,51.1,51.5c-12.6,9.9-24.9,20.2-36.5,31.2c-11.8,11-24.9,23.5-31.8,38.4
c-3.2,7,7.1,13.1,10.3,6c6.7-14.6,19.6-26.3,31.1-37.1c12.7-11.9,26.1-22.9,39.8-33.6C430.6,1170.4,429.9,1166.2,428,1164z"/>
<path fill="#333333" d="M356.1,1137.6c-9.2-7.5-20.3-13.3-28.8-21.5c-5.6-5.4-14.1,3.1-8.5,8.5c7.6,7.3,17.2,12.6,25.5,18.9
c4.9,3.7,9.7,7.8,13.9,12.4c1.6,1.7,2.9,3.6,3.9,5.7c0.9,1.9,0.5,1.3,0.2,2.3c-1,2.9-5.2,7.1-7.6,9.8c-4.3,4.7-8.9,9.1-13.5,13.6
c-7.5,7.2-16,14-22.4,22.2c-4.7,6,3.7,14.6,8.5,8.5c7.2-9.3,17-17,25.5-25.2c7.5-7.2,18.7-16.3,21.5-26.8
C377.3,1154.7,363.6,1143.7,356.1,1137.6z"/>
<path fill="#333333" d="M659.8,1164c20.7-23.1,45.4-42.6,64.7-67.1c4.2-5.3,13.5,1.9,9.4,7.3c-1.6,2-1.6,4.1-1.6,6.6
c0,4.9-4.9,6.7-8.4,5.4c-16.1,18-34.6,33.8-51.1,51.5c12.6,9.9,24.9,20.2,36.5,31.2c11.8,11,24.9,23.5,31.8,38.4
c3.2,7-7.1,13.1-10.3,6c-6.7-14.6-19.6-26.3-31.1-37.1c-12.7-11.9-26.1-22.9-39.8-33.6C657.1,1170.4,657.8,1166.2,659.8,1164z"/>
<path fill="#333333" d="M731.6,1137.6c9.2-7.5,20.3-13.3,28.8-21.5c5.6-5.4,14.1,3.1,8.5,8.5c-7.6,7.3-17.2,12.6-25.5,18.9
c-4.9,3.7-9.7,7.8-13.9,12.4c-1.6,1.7-2.9,3.6-3.9,5.7c-0.9,1.9-0.5,1.3-0.2,2.3c1,2.9,5.2,7.1,7.6,9.8c4.3,4.7,8.9,9.1,13.5,13.6
c7.5,7.2,16,14,22.4,22.2c4.7,6-3.7,14.6-8.5,8.5c-7.2-9.3-17-17-25.5-25.2c-7.5-7.2-18.7-16.3-21.5-26.8
C710.4,1154.7,724.1,1143.7,731.6,1137.6z"/>
</g>
<g>
<path fill="#F39DA3" d="M2550.7,553.8c-758.8,355.4-1517.7-355.4-2276.5,0c0-59.2,0-53.8,0-113c758.8-355.4,1517.7,355.4,2276.5,0
C2550.7,500.1,2550.7,494.6,2550.7,553.8z"/>
<g>
<g>
<path fill="#333333" d="M344,551.6c0,13,2.6,24.3,7.9,34.1c5.3,9.7,12.2,17.4,20.9,23.1c8.7,5.7,18.6,9.2,29.7,10.7
c11.1,1.5,22.8,0.5,34.8-3c10.8-3.1,19.8-8.4,26.9-16.1c7.1-7.7,11.4-19.1,13-34.3c0.5-0.6,0.9-1.2,1.4-1.7
c10.8,0.2,18.5,2.9,23,7.8c4.5,4.9,6.7,10.8,6.7,17.6c0,8.4-2.4,14.7-7.2,18.9c-4.8,4.3-9.4,7.7-13.7,10.2
c0,5.6-1.4,10.3-4.2,14.2c-2.8,3.9-6.1,7.2-10,9.8c-3.9,2.6-8.1,4.8-12.5,6.4c-4.5,1.6-8.4,2.9-11.8,3.8
c-13,3.5-24.8,4.8-35.5,3.6c-10.7-1.2-20.7-3.3-30-6.6s-18.1-7.2-26.5-12c-8.4-4.7-16.8-8.6-25.3-11.6c-8.5-3-17.3-4.7-26.5-5.2
c-9.1-0.4-19.1,1.9-30,7.2c-4.8,2.3-9.6,4.7-14.4,7.1c0-6.5,0-13,0-19.5c4-2,8.5-4.5,13.5-7.4c4.9-2.9,9.4-6.5,13.5-10.8
c4-4.4,7.4-9.9,10.2-16.5c2.8-6.7,4.2-15,4.2-24.9c0-90.7,0-181.4,0-272.1c0-9.6-3.6-15.3-10.9-17.1c-7.3-1.7-17.4,0.5-30.4,7
c0-5.3,1.9-10.8,5.6-16.5c3.7-5.7,10.2-10.9,19.5-15.2c8-3.8,15.2-5.6,21.6-5.7c6.3,0,11.5,1.2,15.6,3.5
c4-5.7,9.2-11.3,15.6-16.6c6.3-5.3,13.5-9.6,21.6-12.6c9.3-3.5,15.8-3.8,19.5-1.3c3.7,2.6,5.6,6.5,5.6,11.8
c-12.7,4.4-22.8,10.7-30.2,18.6c-7.4,8-11.1,16.8-11.1,26.4C344,361.8,344,456.7,344,551.6z"/>
<path fill="#333333" d="M574.3,544.3c-15.5,2.2-29.8,1.8-43-1.1c-13.2-3-24.7-8.3-34.6-16c-9.9-7.7-17.6-17.8-23.2-30.4
c-5.6-12.6-8.4-27.5-8.4-44.8c0-17.6,2.8-34,8.4-49c5.6-15,13.3-28.4,23.2-40c9.9-11.6,21.4-21.1,34.6-28.3
c13.2-7.2,27.5-12,43-14.2c15.2-2.1,29.4-1.4,42.7,2c13.3,3.5,24.9,9.6,34.8,18.4c9.9,8.8,17.6,19.9,23.2,33.2
c5.6,13.4,8.4,28.9,8.4,46.5c0,17.6-2.8,33.5-8.4,47.8c-5.6,14.2-13.3,26.6-23.2,37.1c-9.9,10.6-21.5,19.1-34.8,25.7
C603.7,537.9,589.5,542.2,574.3,544.3z M574.8,522.9c11.4-1.6,21.2-5.3,29.3-11.1c8-5.9,14.7-13.3,20-22.3
c5.3-9,9.1-19.2,11.6-30.5c2.5-11.4,3.7-23.2,3.7-35.6c0-12.1-1.2-23.4-3.7-34.1c-2.5-10.6-6.3-19.7-11.6-27.1
c-5.3-7.4-12-13-20.2-16.7c-8.2-3.7-18-4.8-29.5-3.2c-11.5,1.6-21.3,5.4-29.5,11.3c-8.2,5.9-14.9,13.3-20.2,22.2
c-5.3,8.9-9.1,19-11.6,30.4c-2.5,11.3-3.7,23.2-3.7,35.6c0,12.4,1.2,23.9,3.7,34.5c2.5,10.6,6.4,19.7,11.8,27.2
c5.4,7.5,12.2,13,20.4,16.5C553.5,523.6,563.3,524.5,574.8,522.9z"/>
<path fill="#333333" d="M820,535.9c-18.3-1.1-32.6-5.3-43-12.9c-10.4-7.6-18.2-16.9-23.4-28.1c-5.3-11.2-8.6-23.3-10-36.3
c-1.4-13-2.1-25.2-2.1-36.7c0-17-0.2-30.4-0.7-40.2c-0.5-9.8-1.7-17.1-3.7-22.1c-2-4.9-5-8.1-9.1-9.5c-4-1.4-9.8-2-17.2-1.9
c0-4.6,0-9.3,0-13.9c7.7-0.2,14.3-0.7,19.7-1.6c5.4-1,10.3-2.3,14.6-4.2c4.3-1.8,8.4-3.9,12.1-6.4c3.7-2.4,7.7-5,12.1-7.6
c4.6,0.1,9.3,0.3,13.9,0.4c0,32.7,0,65.3,0,98c0,7.7,0.3,17.2,0.9,28.4c0.6,11.2,2.5,21.9,5.6,32.2c3.1,10.3,7.7,19.3,13.9,26.9
c6.2,7.6,14.9,11.7,26,12.4c9.6,0.6,18.1-1.6,25.5-6.9c7.4-5.3,13.6-12.5,18.6-21.8c4.9-9.3,8.7-20.3,11.1-33
c2.5-12.7,3.7-26.4,3.7-40.9c0-10.8-0.9-20.8-2.6-29.7c-1.7-9-4.6-16.8-8.8-23.4c-4.2-6.6-9.9-12.2-17.2-16.7
c-7.3-4.5-16.5-7.8-27.6-9.8c3.4-5,8.1-9,14.2-11.7c6-2.8,12.1-3.9,18.3-3.3c2.5,0.2,5.2,0.8,8.1,1.7c2.9,0.9,5.6,2,8.1,3.3
c2.5,1.3,4.6,3,6.3,5c1.7,2,2.6,4.3,2.6,6.8c10.2,1.1,16.8,6.2,19.7,15.2c2.9,9,4.4,23.3,4.4,42.8c0,18.3-1.1,36.4-3.2,54.4
c-2.2,18-6.7,34-13.5,47.9c-6.8,14-16.3,25-28.6,33.1C856.7,533.8,840.4,537.1,820,535.9z"/>
<path fill="#333333" d="M1024.7,508.2c0,6.2,1,11.5,3,15.8c2,4.4,4.5,8.1,7.4,11.1c2.9,3,6.3,5.4,10.2,7.2
c3.9,1.8,7.7,3,11.4,3.7c0,4.6,0,9.3,0,13.9c-3.7-0.7-7.8-1.7-12.3-3c-4.5-1.3-9.2-2.7-14.2-4.2c-5-1.5-9.7-2.8-14.2-4.1
c-4.5-1.2-8.6-2.1-12.3-2.8c-3.7-0.6-7.8-1-12.3-1.3c-4.5-0.2-9.2-0.4-14.2-0.6c-5-0.1-9.7-0.3-14.2-0.5
c-4.5-0.2-8.6-0.5-12.3-1c0-4.6,0-9.3,0-13.9c8.4,1.2,15.8-0.1,22.3-3.8c6.5-3.7,9.8-11.5,9.8-23.6c0-26.6,0-53.2,0-79.9
c0-11.4-0.2-21-0.7-28.7c-0.5-7.7-1.8-13.7-3.9-18.2c-2.2-4.5-5.3-7.9-9.3-10.2c-4-2.3-9.6-4-16.7-5c0-4.6,0-9.3,0-13.9
c7.7,1.1,14.3,1.6,19.7,1.5c5.4-0.1,10.3-0.8,14.6-1.9c4.3-1.2,8.4-2.7,12.1-4.6c3.7-1.9,7.7-3.8,12.1-5.9
c4.6,0.8,9.3,1.6,13.9,2.4C1024.7,394,1024.7,451.1,1024.7,508.2z M972.3,259.6c0-9.3,3.3-16.6,9.8-22
c6.5-5.3,14.2-7.3,23.2-5.8c9,1.5,16.6,6,23,13.4c6.3,7.5,9.5,15.9,9.5,25.1c0,9.3-3.2,16.5-9.5,21.8c-6.3,5.2-14,7.1-23,5.6
c-9-1.5-16.7-5.9-23.2-13.2C975.5,277.2,972.3,268.9,972.3,259.6z"/>
<path fill="#333333" d="M1265.3,518.8c0-20.7-1-38.3-3-52.7c-2-14.4-5-26.3-9.1-35.6c-4-9.3-9.1-16.5-15.3-21.5
c-6.2-5-13.3-8.5-21.4-10.4c-8.1-1.9-15.7-2.1-23-0.7c-7.3,1.4-13.7,4.9-19.3,10.3c-5.6,5.4-10,13.1-13.2,23.1
c-3.3,10-4.9,22.4-4.9,37.2c0,22,0,44,0,65.9c0,6.2,1,11.5,3,16c2,4.5,4.5,8.3,7.4,11.4c2.9,3.1,6.3,5.7,10.2,7.6
c3.9,2,7.7,3.4,11.4,4.2c0,4.6,0,9.3,0,13.9c-3.7-0.8-7.8-2-12.3-3.5c-4.5-1.5-9.2-3.1-14.2-4.8c-5-1.7-9.7-3.3-14.2-4.7
c-4.5-1.4-8.6-2.6-12.3-3.4c-3.7-0.8-7.8-1.4-12.3-1.9c-4.5-0.5-9.2-0.9-14.2-1.3c-5-0.4-9.7-0.8-14.2-1.3
c-4.5-0.4-8.6-1-12.3-1.7c0-4.6,0-9.3,0-13.9c8.4,1.6,15.8,0.8,22.3-2.5c6.5-3.3,9.8-11,9.8-23.1c0-25.8,0-51.7,0-77.5
c0-11.5-0.2-21-0.7-28.7c-0.5-7.7-1.8-13.8-3.9-18.5c-2.2-4.6-5.3-8.2-9.3-10.7c-4-2.5-9.6-4.5-16.7-5.9c0-3.9,0-7.7,0-11.6
c7.7,1.5,14.5,2.4,20.2,2.7c5.7,0.2,10.9-0.1,15.6-1c4.6-0.9,8.9-2.1,12.8-3.8c3.9-1.7,8-3.4,12.3-5.2c3.9,0.8,7.7,1.7,11.6,2.5
c0,10.8,0,21.7,0,32.5c5.9-9.5,14-16.6,24.4-21.3c10.4-4.6,22.7-5.3,36.9-1.9c30.6,7.2,53.2,22,67.8,44.2
c14.5,22.1,21.8,54.8,21.8,97.8c0,16.3,0,32.5,0,48.8c0,6.2,1,11.6,3,16.1c2,4.5,4.5,8.4,7.4,11.6c2.9,3.2,6.3,5.8,10.2,7.9
c3.9,2.1,7.7,3.5,11.4,4.5c0,5.4,0,10.8,0,16.3c-4-1-7.6-2.1-10.7-3.4c-3.1-1.2-6.3-2.5-9.5-3.8c-3.2-1.3-7-2.7-11.1-4.2
c-4.2-1.5-9.2-3-15.1-4.4c-4-1-8.6-1.9-13.7-2.7c-5.1-0.8-11.2-1.1-18.3-1c-1.4-3-2.8-5.9-4.2-8.9c2.2-1.6,3.9-5.2,5.1-10.6
c1.2-5.4,2.1-11.8,2.6-19.1c0.5-7.3,0.8-15.1,0.9-23.5C1265.2,534.1,1265.3,526.2,1265.3,518.8z"/>
<path fill="#333333" d="M1467.7,662.6c-16.7-4.1-31.4-10.6-44.1-19.4c-12.7-8.8-23.4-19.3-32-31.5
c-8.7-12.2-15.2-25.9-19.5-40.9c-4.3-15-6.5-30.9-6.5-47.6c0-19.5,3-35.4,9.1-47.6c6-12.3,13.9-21.6,23.7-28.2
c9.8-6.5,20.9-10.3,33.4-11.3c12.5-1,25.3,0.1,38.3,3.3c13.9,3.4,26.3,8.6,37.1,15.4c10.8,6.8,20.9,17.7,30.2,32.6
c1.9-6.4,4.8-10.9,8.8-13.5c4-2.6,8.7-4.1,13.9-4.6c5.3-0.5,10.8-0.2,16.7,0.9c5.9,1,11.6,2.2,17.2,3.5c0,4.6,0,9.3,0,13.9
c-4-0.9-7.4-0.8-10,0.3c-2.6,1.1-4.6,5.1-6,12.1c-1.4,7-2.3,17.6-2.8,31.9c-0.5,14.3-0.7,34.1-0.7,59.5c0,35.3,0,70.6,0,105.9
c0,35.3-8.8,58.9-26.2,70.7c-17.5,11.8-45,13.2-82.4,3.9c-22.9-5.7-39.9-12.4-50.8-20.1c-11-7.7-16.5-15.3-16.5-22.7
c-8.1-2-13.8-6.2-17.2-12.4c-3.4-6.3-5.1-12.2-5.1-17.8c0-5.3,1.2-9.5,3.7-12.8c2.5-3.3,5.6-5.6,9.3-7.2
c3.7-1.5,7.7-2.4,11.8-2.6c4.2-0.2,8,0.1,11.4,1c0,8.4,1,16.4,3,24.2c2,7.8,5.3,15,10,21.5c4.6,6.6,10.6,12.4,17.9,17.5
c7.3,5.1,16.2,8.9,26.7,11.5c9.3,2.3,17.8,3,25.5,2.1c7.7-0.9,14.3-3.9,19.7-9.1c5.4-5.2,9.7-12.7,12.8-22.5
c3.1-9.8,4.6-22.4,4.6-37.9c0-10.1,0-20.1,0-30.2c-10.5,7.7-21.4,11.7-32.5,11.9C1489.1,666.4,1478.2,665.2,1467.7,662.6z
M1474.7,642.9c10.5,2.6,19.8,2.5,27.9-0.4c8-2.8,14.6-7.8,19.7-15c5.1-7.1,9-15.9,11.6-26.2c2.6-10.4,3.9-21.9,3.9-34.6
c0-12.1-1.2-23.7-3.7-35c-2.5-11.3-6.3-21.6-11.6-31.1c-5.3-9.5-11.8-17.5-19.7-24c-7.9-6.6-17.4-11.2-28.6-14
c-12.1-3-22.3-3.3-30.6-0.9c-8.4,2.4-15,6.9-20,13.6c-5,6.7-8.5,15-10.7,25.2c-2.2,10.1-3.3,21.4-3.3,33.8c0,12.1,1,23.9,3,35.6
c2,11.6,5.6,22.4,10.7,32.2c5.1,9.8,11.8,18.3,20,25.4C1451.5,634.6,1462,639.8,1474.7,642.9z"/>
</g>
<g>
<path fill="#333333" d="M1770,616.1c-0.3-16.8-0.7-30.1-1.2-39.9c-0.5-9.8-1.6-17.4-3.5-22.9c-1.9-5.4-4.8-9.2-8.8-11.2
c-4-2.1-9.8-3.8-17.2-5.1c0-4.6,0-9.3,0-13.9c7.7,1.4,14.3,2,19.7,2c5.4,0,10.3-0.6,14.6-1.8c4.3-1.2,8.4-2.7,12.1-4.6
c3.7-1.9,7.7-3.9,12.1-6c4.6,0.7,9.3,1.4,13.9,2.1c0,32.7,0,65.3,0,98c0,18.6,1.1,34.4,3.2,47.4c2.2,13,5.3,23.7,9.5,32
c4.2,8.3,9.1,14.6,14.9,18.7c5.7,4.2,12.1,6.7,19.3,7.5c6.8,0.8,13.6,0.1,20.4-2.1c6.8-2.2,13-6.4,18.6-12.5
c5.6-6.1,10.1-14.3,13.5-24.5c3.4-10.2,5.1-22.9,5.1-38.1c0-7.6,0-15.2,0-22.8c0-11.4-0.2-21-0.7-28.6c-0.5-7.6-1.8-13.6-3.9-18
c-2.2-4.4-5.3-7.6-9.3-9.7c-4-2.1-9.6-3.5-16.7-4.2c0-4.6,0-9.3,0-13.9c7.7,0.8,14.3,1,19.7,0.5c5.4-0.4,10.3-1.4,14.6-2.9
c4.3-1.5,8.4-3.3,12.1-5.6c3.7-2.2,7.7-4.5,12.1-7c4.6,0.3,9.3,0.6,13.9,0.9c0,76,0,152,0,228c0,35.9-8.2,61.3-24.6,75.7
c-16.4,14.4-42,20.1-76.6,16c-19.8-2.4-34.9-6.5-45.3-12c-10.4-5.5-15.6-11.4-15.6-17.6c-8.1-1.2-13.8-4.8-17.2-10.8
c-3.4-6-5.1-11.7-5.1-17.3c0-5.3,1.2-9.6,3.7-13.1c2.5-3.5,5.6-6.2,9.3-8c3.7-1.9,7.7-3.2,11.8-3.8c4.2-0.6,8-0.7,11.4-0.2
c0,7.7,0.9,15.1,2.8,22c1.9,6.9,4.9,13.2,9.1,18.9c4.2,5.7,9.5,10.4,16,14.2c6.5,3.8,14.4,6.3,23.7,7.3c8.4,1,15.9,0.4,22.5-1.7
c6.7-2.1,12.4-6.2,17.2-12.2c4.8-6.1,8.5-14.2,11.1-24.5c2.6-10.3,3.9-23.2,3.9-38.7c0-14.4,0-28.8,0-43.2
c-3.1,5-6.4,9.6-10,13.8c-3.6,4.2-7.9,7.6-13,10.4c-5.1,2.7-11.1,4.8-18.1,6c-7,1.2-15.2,1.3-24.8,0.1
c-15.2-1.9-27.8-6-37.8-12.3c-10.1-6.2-18.3-14.6-24.6-25c-6.3-10.4-10.8-22.8-13.5-37.2C1771.8,650.3,1770.3,634.1,1770,616.1z
"/>
<path fill="#333333" d="M2122.4,748.3c-15.5,1.1-29.8-0.9-43-5.9c-13.2-5-24.7-12.4-34.6-22.3c-9.9-9.8-17.6-21.8-23.2-35.8
c-5.6-14-8.4-29.7-8.4-47c0-17.6,2.8-33.2,8.4-46.8c5.6-13.6,13.3-25,23.2-34.5c9.9-9.5,21.4-16.8,34.6-22.1
c13.2-5.2,27.5-8.3,43-9.4c15.2-1.1,29.4,0,42.7,3.4c13.3,3.3,24.9,9,34.8,17c9.9,8,17.6,18.3,23.2,31
c5.6,12.7,8.4,27.8,8.4,45.5c0,17.6-2.8,33.9-8.4,48.8c-5.6,14.8-13.3,28-23.2,39.3c-9.9,11.3-21.5,20.4-34.8,27.1
C2151.8,743.3,2137.6,747.3,2122.4,748.3z M2122.9,726.9c11.5-0.8,21.2-4.2,29.3-9.9c8-5.7,14.7-13.2,20-22.3
c5.3-9.1,9.1-19.4,11.6-30.9c2.5-11.5,3.7-23.4,3.7-35.8c0-12.1-1.2-23.4-3.7-33.9c-2.5-10.5-6.3-19.4-11.6-26.7
c-5.3-7.3-12-12.8-20.2-16.7c-8.2-3.8-18-5.3-29.5-4.5c-11.5,0.8-21.3,3.6-29.5,8.4c-8.2,4.9-14.9,11.3-20.2,19.3
c-5.3,8-9.1,17.5-11.6,28.4c-2.5,10.9-3.7,22.5-3.7,34.9c0,12.4,1.2,24.1,3.7,35.2c2.5,11.1,6.4,20.8,11.8,29.2
c5.4,8.4,12.2,14.9,20.4,19.4C2101.6,725.8,2111.4,727.7,2122.9,726.9z"/>
<path fill="#333333" d="M2438.6,548.2c0-11.4-0.2-20.9-0.7-28.3c-0.5-7.4-1.8-12.7-3.9-16c-2.2-3.3-5.3-5-9.3-5.1
c-4-0.1-9.6,1.2-16.7,3.8c0-4.6,0-9.3,0-13.9c7.7-2.9,14.3-5.9,19.7-8.9c5.4-3.1,10.3-6.4,14.6-10.1c4.3-3.6,8.4-7.5,12.1-11.6
c3.7-4.1,7.7-8.4,12.1-13.1c4.6-2.1,9.3-4.2,13.9-6.3c0,54.9,0,109.9,0,164.8c0,6.2,1,10.8,3,13.9c2,3.1,4.5,5.2,7.4,6.3
c2.9,1.1,6.3,1.2,10.2,0.4c3.9-0.8,7.7-2.1,11.4-4c0,5.4,0,10.8,0,16.3c-7.1,2.7-13.2,4.8-18.3,6.4c-5.1,1.7-11.5,4.3-19.3,7.8
c-10.5,4.8-21.1,10.4-31.6,16.9c-1.5-0.9-3.1-1.8-4.6-2.7c0-8.7,0-17.3,0-26c-3.4,6.7-6.9,12.9-10.4,18.8
c-3.6,5.9-7.8,11.4-12.8,16.5c-5,5.1-10.7,9.9-17.2,14.2c-6.5,4.3-14.2,8-23.2,11c-31,10.2-53.1,6.4-66.4-9.2
c-13.3-15.7-20.3-41.7-20.9-77.8c-0.3-16.6-0.7-29.8-1.2-39.4c-0.5-9.6-1.6-16.8-3.5-21.5c-1.9-4.7-4.8-7.3-8.8-7.8
c-4-0.5-9.8,0-17.2,1.5c0-4.6,0-9.3,0-13.9c7.7-1.5,14.3-3.4,19.7-5.5c5.4-2.1,10.3-4.6,14.6-7.5c4.3-2.9,8.4-6,12.1-9.4
c3.7-3.4,7.7-7.1,12.1-11c4.6-1.2,9.3-2.5,13.9-3.8c0,32.7,0,65.3,0,98c0,18.9,1.2,34.3,3.7,46.3c2.5,12,6,21.2,10.4,27.6
c4.5,6.4,9.8,10.3,16,11.6c6.2,1.3,13,0.8,20.4-1.7c8.7-2.9,16.6-8,23.9-15.1c7.3-7.1,13.5-15.8,18.6-25.8
c5.1-10,9.1-21.1,11.8-33.2c2.8-12.1,4.2-24.5,4.2-37.2C2438.6,559,2438.6,553.6,2438.6,548.2z"/>
</g>
</g>
<path fill="#333333" d="M1286.6,691c-61.5,31.3-134.1,13.4-196.7-4.8c-34.3-9.9-68.6-20-102.6-31c-35.5-11.5-71-23.4-106.9-33.8
c-63.9-18.5-130.6-33.9-197.5-25.6c-58.5,7.3-115.3,30.6-159.3,70.3c-10.4,9.3-19.3,19.8-28.5,30.3c-9.7,11-18.6,22.9-25.3,35.9
c-6.3,12-10.3,25.1-12.1,38.5c-0.8,6-2.1,12.5-2,18.6c0,1.6,0.4,3.1,1.1,4.4c0.2,0.4,0.5,0.8,0.8,1.1c2.9,4.6,11.5,3.6,11.1-3
c-0.1-1.4-0.4-2.7-1.1-3.9c0-2.2,0.5-4.4,0.9-6.5c0.7-4.3,0.9-8.7,1.6-13.1c2.5-14.7,8.3-28.3,16.2-40.9
c8.3-13.3,19-25.1,29.5-36.8c9.9-11,21-21,32.8-29.9c47.5-35.9,107.2-53.9,166.3-55.6c32.8-1,65.1,4.2,97.1,11
c36.6,7.8,72.5,18.4,108.2,29.7c68.2,21.6,136.1,45.4,205.7,62.3c54.8,13.3,114.8,19.4,166.7-7
C1299.5,697.8,1293.4,687.5,1286.6,691z"/>
<path fill="#333333" d="M2615.3,700.1c-19.5-21.1-46.2-31.3-74.7-29.9c-31.1,1.5-60.2,16.2-86,32.6c-23.5,15-45.3,32.5-67.9,48.8
c-41.5,30-84.2,58.7-130.4,81c-44,21.3-95.6,39.1-144.9,29c-26.7-5.4-49.6-20.1-67.4-40.4c-5.1-5.8-13.6,2.7-8.5,8.5
c16.4,18.6,37,32.7,60.7,40.3c22.6,7.2,47,7.6,70.4,4.4c52.1-7.3,101-31.8,145.7-58.5c10.4-6.2,20.5-12.7,30.6-19.3
c1.7,1.5,4.1,2.1,6.7,0.6c28.2-16.6,55.8-35.1,87.2-45.2c25.8-8.3,55.9-10.6,80.3,3.2c37.7,21.3,33.5,71.2,13.1,103
c-4.9,7.7-11,14.5-17.7,20.7c-5.7,5.3,2.8,13.7,8.5,8.5c30.4-28.1,48.1-74.8,29.1-114.1c-9-18.6-26.8-30.9-46.3-36.4
c-29.2-8.1-60.8-1.3-88.1,10.3c-2.4,1-4.8,2.1-7.2,3.2c9.6-7,19.1-14,28.7-21c45.9-33.3,112.5-71.5,163.7-26.4
c17.3,15.2,31.2,39.9,18.4,62.2c-3.9,6.7,6.5,12.7,10.3,6C2643.8,746.5,2633.2,719.5,2615.3,700.1z"/>
<path fill="#333333" d="M2337.5,739.8c-8.2,10.5-19.4,19-29.9,27c-16.6,12.6-34.3,24-52.4,34.4c-19.3,11.1-39.5,20.9-60.6,28.2
c-17.6,6.1-36.5,10.7-55.3,8.7c-9.7-1-19-5-25.8-12.1c-5.4-5.5-13.9,2.9-8.5,8.5c26.5,27.2,71.8,14.7,102.5,2.9
c40.1-15.4,77.8-38.2,111.6-64.5c9.5-7.4,19.4-15.2,26.9-24.7C2350.6,742.3,2342.2,733.7,2337.5,739.8z"/>
<path fill="#333333" d="M2477.5,771.9c-7.5-1.9-10.7,9.7-3.2,11.6c26.8,6.8,29.3,48.6,5.8,60.9c-6.8,3.6-0.8,13.9,6,10.3
C2518.8,837.5,2514.2,781.1,2477.5,771.9z"/>
<path fill="#333333" d="M2541.4,704.7c-7.2,2.7-4.1,14.3,3.2,11.6c14.1-5.4,26.8-1.8,36.6,9.6c9.1,10.6,13.1,26.8,11.2,40.5
c-1.1,7.6,10.5,10.8,11.6,3.2C2608.9,734.2,2581.8,689.4,2541.4,704.7z"/>
<path fill="#333333" d="M1268.6,730.3c-2.3,2.6-4.1,5.4-6.1,8.3c-1.4,2.1-4.5,3.3-6.6,4.5c-5,2.8-10.2,5-15.6,6.9
c-11,3.9-22.5,6-34.1,7c-26.3,2.3-52.8-0.8-78.6-5.9c-53.1-10.4-104.3-29.5-154.2-50.2c-16.7-6.9-33.1-14.4-50-20.5
c-18.2-6.6-36.9-12.1-55.8-16.6c-40.9-9.7-84.5-15.2-126.3-7.8c-20.2,3.6-39.6,11.2-55.7,24c-16.6,13.2-27.2,32.5-32.2,52.9
c-1.8,7.5,9.7,10.7,11.6,3.2c21.9-89,136.4-76.2,204.3-59.6c18.5,4.5,36.8,10.2,54.7,16.8c17.4,6.5,34.2,14.2,51.4,21.3
c50.3,20.6,101.9,39.4,155.5,49.3c26.6,4.9,54,7.5,81,4.5c12.1-1.4,23.9-3.9,35.3-8.2c5.4-2.1,10.7-4.5,15.8-7.4
c2.1-1.2,5.2-2.5,6.8-4.4c2.7-3,4.5-6.6,7.2-9.6C1282.2,733,1273.7,724.5,1268.6,730.3z"/>
<path fill="#333333" d="M1186.5,678.2c-63.2-0.3-125.1-22.6-181.5-49.5c-6.9-3.3-13,7-6,10.3c58.4,27.8,122.1,50.9,187.6,51.1
C1194.3,690.2,1194.3,678.2,1186.5,678.2z"/>
<path fill="#333333" d="M863.6,714.9c-60.2-41.2-189.5,1.3-162.2,88.3c2.3,7.3,13.9,4.2,11.6-3.2
c-24.1-76.7,93.2-109.9,144.6-74.7C864,729.7,870,719.3,863.6,714.9z"/>
<path fill="#333333" d="M620.9,663.8c-28.2,1.9-53.6,21.5-72.6,41c-19.1,19.6-38.5,46.7-38.9,75.2c-0.1,7.7,11.9,7.7,12,0
c0.3-24.9,18-48.3,34.2-65.6c16.5-17.5,40.1-37,65.2-38.7C628.6,675.3,628.7,663.3,620.9,663.8z"/>
<path fill="#333333" d="M2644.3,257.2c-65.6-33.2-140.2-35.9-210.5-17.1c-35.4,9.5-69.3,24.4-101,42.7
c-32.2,18.5-63,39.7-94.9,58.7c-12.8,7.6-25.7,15-38.7,22.2c-1,0.3-1.9,0.5-2.9,0.8c-1.8,0.5-3,1.5-3.6,2.8
c-48,26-98,48.4-150.9,62.6c-35.5,9.5-71.9,14.9-108.7,16c-39.5,1.2-79.3-2.6-118.5-7.7c24.6-3.2,48.7-9.5,71.4-19
c27.9-11.7,51.3-28.7,72.8-49.8c24.3-23.8,45.6-50.4,68.4-75.6c17.5-19.3,36.1-37.9,57.1-53.4c17.2-12.7,35.8-23.6,55-33
c20.5-10.1,42.3-18.2,65-22.1c18.6-3.2,39.1-2.6,55.4,8c6.5,4.2,12.5-6.2,6-10.3c-19.6-12.8-43.9-12.8-66.1-9
c-26.2,4.5-51.5,15.2-75,27.4c-21.1,10.9-40.9,24-59.4,38.9c-26.4,21.3-48.6,47.2-70.8,72.7c-18.9,21.7-38,43.4-59.6,62.6
c-19.2,17.1-42.7,29.3-66.8,37.8c-40.7,14.3-85.7,18.6-128.7,12.9c-61.1-11.2-121.6-25.7-182.2-39.4
c-36.8-8.4-73.5-16.8-110.3-25.1c-34-7.7-68.5-15.7-100.1-30.8c-7-3.4-13.8-7.2-20.4-11.4c-6.5-4.2-12.5,6.2-6,10.3
c28.6,18.3,61.8,28.3,94.5,36.6c34.6,8.7,69.5,16.4,104.3,24c63.7,14.1,127.2,29.5,191.2,42.2c0.6,0.4,1.3,0.7,2.1,0.9
c8.9,2,17.9,3.5,27,4.7c10.2,1.9,20.4,3.6,30.7,5.3c78.4,12.8,158.5,20.7,237.2,6.3c69.5-12.7,134.9-41.2,196.5-75
c30.4-8.5,59.3-21.4,88.3-33.7c30.6-13,63.3-26.4,96.6-29.7c45.1-4.5,94.6,1.9,134,25.4c17.6,10.5,32.3,25.1,41.2,43.7
c10,20.9,9.7,45.1,4.6,67.3c-1.7,7.5,9.8,10.7,11.6,3.2c5.3-23.4,5.7-47.9-3.2-70.5c-7.9-19.9-22.2-36-39.4-48.4
c-37.3-26.7-87.1-35.1-132.1-33.7c-51.1,1.5-96.8,23.1-143.2,42.6c13-7.9,25.9-16,38.8-24.1c31.8-20,63.4-39.2,98.6-52.8
c68.2-26.4,144.3-33.3,213.7-7.6c8.6,3.2,17,7,25.2,11.2C2645.1,271,2651.2,260.7,2644.3,257.2z"/>
<path fill="#333333" d="M2477.7,360.2c-6.8,3.7-0.8,14,6,10.3c17.6-9.5,30.5,7.2,37.9,21.4c8.4,16.1,14.3,36.6,13,54.9
c-0.6,7.7,11.4,7.7,12,0C2549,414,2523.5,335.5,2477.7,360.2z"/>
<path fill="#333333" d="M2621.6,279.7c-36.8-35.9-97.1-26.5-139.1-5.7c-6.9,3.4-0.9,13.8,6,10.3c37-18.3,91.9-28,124.6,3.9
C2618.6,293.6,2627.1,285.1,2621.6,279.7z"/>
<path fill="#333333" d="M2247.4,139.1c-31.4-7.7-63.6-7.7-95,0.3c-30.8,7.8-59.4,23.1-85.9,40.4c-11.7,7.6-23.7,15.4-34,24.8
c-8.1,7.3-15.1,15.7-21.9,24.2c-16.1,20-30.5,41.4-46,61.9c-10.6,14-21.9,27.8-34.9,39.7c-10,9.1-22.3,18.1-36.2,19.5
c-7.6,0.8-7.7,12.7,0,12c20.6-2.1,37.4-15.4,51.6-29.7c17.9-18,32.8-39.1,47.6-59.6c14-19.3,27.8-39.3,44.8-56.2
c9.4-9.3,20.7-16.6,31.7-24c13.6-9.1,27.6-17.5,42.3-24.8c41.6-20.7,87.3-28.1,132.7-16.9C2251.8,152.5,2254.9,141,2247.4,139.1z"
/>
<path fill="#333333" d="M1737,390.8c-51-8.9-102.7-13.4-153.6-22.7c-51.4-9.4-103.3-23.7-146.9-53.4c-6.4-4.4-12.4,6-6,10.3
c43.5,29.5,95,44.2,146.1,53.9c52.1,9.9,105.1,14.3,157.4,23.4C1741.3,403.7,1744.6,392.1,1737,390.8z"/>
<path fill="#333333" d="M2170.9,336.3c-26.2,13.2-51.6,28-78.2,40.5c-26.3,12.4-54.8,23.2-84.2,23.4c-7.7,0.1-7.7,12,0,12
c30.3-0.2,59.3-10.9,86.6-23.3c27.9-12.7,54.4-28.4,81.8-42.2C2183.9,343.2,2177.8,332.8,2170.9,336.3z"/>
<path fill="#333333" d="M888.8,272.5c-41.7-34-101-40.2-152.8-41.6c-55.4-1.4-111.3,4.4-165.2,17.5
c-55.4,13.4-111.1,36.7-150.6,79.2c-5.2,5.7,3.2,14.1,8.5,8.5c41.6-44.8,101.1-66.7,159.5-79.4c54-11.7,109.9-16.1,165.1-13.1
c43,2.4,92.6,9.2,127.1,37.4C886.3,285.8,894.8,277.4,888.8,272.5z"/>
<path fill="#333333" d="M904.4,242.8c-103.2-76.8-242-68.2-357.9-27.9c-5.3,1.8-10.6,3.8-15.8,5.8c-7.2,2.7-4.1,14.3,3.2,11.6
c114.9-43.5,254.5-57.4,359.8,17.6c1.6,1.1,3.1,2.3,4.6,3.4C904.5,257.8,910.5,247.4,904.4,242.8z"/>
<path fill="#333333" d="M248.5,441.4c-4.5-25.1-11.1-50.2-9.8-76c0.4-7.7-11.6-7.7-12,0c-1.2,23.8,4.1,47.3,8.7,70.6
c4.7,23.9,7,47.1,4.6,71.4c-4.2,44-20.9,85.7-52.3,117.4c-5.4,5.5,3,14,8.5,8.5c32-32.3,49.1-73.7,54.9-118.4
C254.4,490,253,466,248.5,441.4z"/>
<path fill="#333333" d="M207.3,474.1c-1.6-7.6-13.1-4.4-11.6,3.2c5.7,27.2,3.1,53.4-7.2,79.2c-9.9,24.8-24.6,47.5-35.3,72
c-3.1,7,7.3,13.1,10.3,6c11.2-25.4,26-49.1,36.6-74.8C211.4,532.1,213.4,503.1,207.3,474.1z"/>
</g>
<g>
<rect x="294.3" y="2162.7" fill="#E4DAD8" width="656.6" height="226.5"/>
<g>
<g>
<path fill="#333333" d="M474.5,2441.4h-99.4v-329.7h99.4v28.8l-58-2.8v105.4l58,10.7v22.3l-65.9-2.8v133.3l65.9-3.7V2441.4z"/>
<path fill="#333333" d="M538.1,2441.4l-27.4-329.7h29.3l27.9,318.1h2.3l31.1-313.4h30.6l-45,325H538.1z"/>
<path fill="#333333" d="M758.2,2441.4h-99.4v-329.7h99.4v28.8l-58-2.8v105.4l58,10.7v22.3l-65.9-2.8v133.3l65.9-3.7V2441.4z"/>
<path fill="#333333" d="M828.7,2113.1c12.7-0.9,25.2-1.4,37.6-1.4h20c4.9,0,9,1.9,12.1,5.6c3.1,3.7,4.8,8.5,5.1,14.4l4.6,133.7
l-20.9,27.4l37.1,138.4l-8.8,10.2h-27.4L864.5,2297l-23.7,2.3l-9.8,142.1h-21.4v-324.6C809.7,2115.3,816,2114.1,828.7,2113.1z
M873.8,2262.7c1.9,0,2.8-0.9,2.8-2.8v-115.6l-7-7l-32,3.3l1.4,124L873.8,2262.7z"/>
</g>
<path fill="#333333" d="M941,2512c-7.6-13.9-22.3-21.5-36.7-26.3c-19.3-6.5-40.2-8.4-60.4-9.2c-45-1.9-90.6,2.9-135,10.6
c-19.5,3.4-38.5,7.8-57.3,13.9c-32.6,10.8-63.7,25.7-94.6,40.8c-53,25.9-108.4,54.5-168.2,59.5c-48.3,4.1-102.3-5.3-138-40.4
c-15.9-15.6-29-37.1-31-59.6c-1.9-21.5,5.1-43.4,19.4-59.6c12.6-14.4,30.6-22.8,49.5-24.9c7.6-0.9,7.7-12.9,0-12
c-24,2.7-46.1,13.4-61.3,32.5c-13.8,17.3-20.6,39.4-19.7,61.4c1,23.4,12.3,44,26.8,61.9c15.5,19.1,36.9,32.4,59.7,41.1
c45.6,17.3,99,16,145.4,2.4c64.6-18.9,122.3-54.3,184.1-79.9c42.2-17.5,85.6-26.5,130.8-31.7c43.8-5,90.6-8.5,133.9,1.2
c15.5,3.5,34.1,9.5,42.3,24.3C934.4,2524.8,944.7,2518.8,941,2512z"/>
<path fill="#333333" d="M912.2,2548c-20.9-31.5-61.2-39.1-96.5-39.4c-45.6-0.3-91.6,10.8-134.2,26.3c-23,8.4-45.6,18.5-66.6,31
c-15.6,9.3-31.7,20.2-42.9,34.8c-4.7,6,3.7,14.6,8.5,8.5c9.5-12.3,22.5-21.7,35.6-29.9c17.6-11.1,36.6-20.1,55.9-27.9
c42.3-17,87.9-28.9,133.6-30.6c33.2-1.3,76.1,2.9,96.3,33.3C906.1,2560.4,916.5,2554.4,912.2,2548z"/>
<path fill="#333333" d="M308.2,2541.6c-22.8-4-41.7-17-44.3-41.3c-2.1-18.9,4.3-39,15.5-54.2c4.6-6.2-5.8-12.2-10.3-6
c-13.2,17.8-19.9,42-16.7,64c4.1,27.8,26.1,44.4,52.6,49C312.6,2554.5,315.9,2543,308.2,2541.6z"/>
<path fill="#333333" d="M418.1,2649.3c-48,5.3-98.9,10.1-145.9-3.8c-21.6-6.4-41.3-17.8-56.6-34.4
c-17.8-19.4-27.1-44.5-33.2-69.7c-9.7-40.6-10.8-93.4,24.2-122.7c5.9-5-2.6-13.4-8.5-8.5c-43.5,36.4-37,102.8-22.6,151.3
c7.2,24.4,19.8,47.3,38.4,64.9c16.5,15.6,37.3,25.7,59,31.8c46.9,13.1,97.5,8.4,145.2,3.1
C425.7,2660.4,425.8,2648.4,418.1,2649.3z"/>
</g>
</g>
<g>
<ellipse fill="#CFD3D2" cx="1289.3" cy="1150" rx="177.5" ry="149.3"/>
<g>
<path fill="#333333" d="M1189.4,1082.6v29.6h26.8v14.3h-26.8v55.6c0,12.8,3.6,20,14,20c4.9,0,8.5-0.6,10.9-1.3l0.9,14
c-3.6,1.5-9.4,2.6-16.6,2.6c-8.7,0-15.8-2.8-20.2-7.9c-5.3-5.5-7.2-14.7-7.2-26.8v-56.2h-16v-14.3h16v-24.7L1189.4,1082.6z"/>
<path fill="#333333" d="M1237.3,1064.1h18.7v64.3h0.4c3-5.3,7.7-10,13.4-13.2c5.5-3.2,12.1-5.3,19.2-5.3c13.8,0,36,8.5,36,44.1
v61.3h-18.7v-59.2c0-16.6-6.2-30.7-23.8-30.7c-12.1,0-21.7,8.5-25.1,18.7c-1.1,2.6-1.3,5.3-1.3,8.9v62.2h-18.7V1064.1z"/>
<path fill="#333333" d="M1365.8,1167.1c0.4,25.3,16.6,35.8,35.3,35.8c13.4,0,21.5-2.3,28.5-5.3l3.2,13.4
c-6.6,3-17.9,6.4-34.3,6.4c-31.7,0-50.7-20.9-50.7-51.9c0-31.1,18.3-55.6,48.3-55.6c33.6,0,42.6,29.6,42.6,48.5
c0,3.8-0.4,6.8-0.6,8.7H1365.8z M1420.8,1153.7c0.2-11.9-4.9-30.4-26-30.4c-18.9,0-27.2,17.5-28.7,30.4H1420.8z"/>
</g>
<path fill="#333333" d="M1470.6,1065.4c-20.5-29.4-51-47.3-83.7-60.5c-38.7-15.7-82.3-24.4-124.1-20.2c-24.1,2.4-48.7,5-72.2,11
c-23.1,5.9-46.8,16.6-59.8,37.6c-1.4,2.2-1.1,4.4,0,6.1c-14.6,17.8-25.2,38.9-32,60.9c-10.5,33.8-12.1,72.2,0.4,105.7
c13.5,36.1,43,63.5,78,78.5c18.4,7.9,37.8,12.3,57.5,15.7c21.2,3.7,42.7,5.9,64.2,6.9c21.7,1,43.6,0.5,65.2-1.9
c19.3-2.1,39-5.5,57.1-12.7c27.9-11.1,50.6-31.9,64.1-58.7C1511.7,1181.2,1503.8,1113,1470.6,1065.4z M1427.3,1276.2
c-15.8,8.3-33.8,12.2-51.4,15c-21.1,3.4-42.6,4.2-64,3.9c-21.5-0.3-43.1-2.1-64.4-5.3c-19.7-2.9-39.4-6.8-58.1-13.6
c-34.9-12.8-65.2-38.5-78.7-73.7c-12.6-32.9-9.9-70.4,0.9-103.4c9.7-29.4,27.5-57.7,53.2-75.5c2.5-1.8,3.1-4.5,2.5-6.9
c3.7-1.8,7.5-3.4,11.3-4.9c16.4-6.1,34-9.1,51.3-11.3c17.1-2.2,34.5-4.7,51.7-4.9c21-0.1,42,2.9,62.4,8
c20.8,5.1,41.1,12.5,60.2,22.2c15.3,7.7,29.8,16.8,42,29c20.2,20.3,33,47.2,39,75C1497,1185.1,1479.7,1248.6,1427.3,1276.2z"/>
</g>
<g>
<path fill="#333333" d="M321.7,853.8c-2.6-19.1-21.2-33.7-39.3-36.6c-4-0.6-8-0.8-12-0.5c-0.6,0-1.2,0.2-1.7,0.3
c-1.5-0.6-3.2-0.5-4.9,0.5c-17.3,10-24.9,30.3-20.4,49.4c4.8,20.5,23.9,30.3,43.8,26.9C307.8,890.2,324.7,875.9,321.7,853.8z
M291.3,880.4c-15,4.7-30.5,1.5-35.8-14.7c-4.5-13.9,1-29.4,13.2-37.2c0.5,0.1,1.1,0.1,1.7,0.1c15.9-1.1,30.8,6.5,37.7,21.2
C315,864.2,304.9,876.2,291.3,880.4z"/>
<path fill="#333333" d="M1005.6,918.3c-2.6-19.1-21.2-33.7-39.3-36.6c-4-0.6-8-0.8-12-0.5c-0.6,0-1.2,0.2-1.7,0.3
c-1.5-0.6-3.2-0.5-4.9,0.5c-17.3,10-24.9,30.3-20.4,49.4c4.8,20.5,23.9,30.3,43.8,26.9C991.7,954.7,1008.6,940.4,1005.6,918.3z
M975.2,944.9c-15,4.7-30.5,1.5-35.8-14.7c-4.5-13.9,1-29.4,13.2-37.2c0.5,0.1,1.1,0.1,1.7,0.1c15.9-1.1,30.8,6.5,37.7,21.2
C998.9,928.7,988.8,940.7,975.2,944.9z"/>
<path fill="#333333" d="M1043.5,1324.9c-2.6-19.1-21.2-33.7-39.3-36.6c-4-0.6-8-0.8-12-0.5c-0.6,0-1.2,0.2-1.7,0.3
c-1.5-0.6-3.2-0.5-4.9,0.5c-17.3,10-24.9,30.3-20.4,49.4c4.8,20.5,23.9,30.3,43.8,26.9C1029.5,1361.3,1046.5,1347.1,1043.5,1324.9
z M1013.1,1351.5c-15,4.7-30.5,1.5-35.8-14.7c-4.5-13.9,1-29.4,13.2-37.2c0.5,0.1,1.1,0.1,1.7,0.1c15.9-1.1,30.8,6.5,37.7,21.2
C1036.7,1335.3,1026.7,1347.3,1013.1,1351.5z"/>
<path fill="#333333" d="M1630.6,1138c-2.6-19.1-21.2-33.7-39.3-36.6c-4-0.6-8-0.8-12-0.5c-0.6,0-1.2,0.2-1.7,0.3
c-1.5-0.6-3.2-0.5-4.9,0.5c-17.3,10-24.9,30.3-20.4,49.4c4.8,20.5,23.9,30.3,43.8,26.9C1616.7,1174.4,1633.6,1160.2,1630.6,1138z
M1600.2,1164.6c-15,4.7-30.5,1.5-35.8-14.7c-4.5-13.9,1-29.4,13.2-37.2c0.5,0.1,1.1,0.1,1.7,0.1c15.9-1.1,30.8,6.5,37.7,21.2
C1623.9,1148.5,1613.8,1160.4,1600.2,1164.6z"/>
<path fill="#333333" d="M2610.6,981.9c-2.6-19.1-21.2-33.7-39.3-36.6c-4-0.6-8-0.8-12-0.5c-0.6,0-1.2,0.2-1.7,0.3
c-1.5-0.6-3.2-0.5-4.9,0.5c-17.3,10-24.9,30.3-20.4,49.4c4.8,20.5,23.9,30.3,43.8,26.9C2596.6,1018.3,2613.5,1004.1,2610.6,981.9z
M2580.2,1008.5c-15,4.7-30.5,1.5-35.8-14.7c-4.5-13.9,1-29.4,13.2-37.2c0.5,0.1,1.1,0.1,1.7,0.1c15.9-1.1,30.8,6.5,37.7,21.2
C2603.8,992.4,2593.8,1004.3,2580.2,1008.5z"/>
<path fill="#333333" d="M2504.8,1177c-2.6-19.1-21.2-33.7-39.3-36.6c-4-0.6-8-0.8-12-0.5c-0.6,0-1.2,0.2-1.7,0.3
c-1.5-0.6-3.2-0.5-4.9,0.5c-17.3,10-24.9,30.3-20.4,49.4c4.8,20.5,23.9,30.3,43.8,26.9C2490.8,1213.4,2507.8,1199.1,2504.8,1177z
M2474.4,1203.6c-15,4.7-30.5,1.5-35.8-14.7c-4.5-13.9,1-29.4,13.2-37.2c0.5,0.1,1.1,0.1,1.7,0.1c15.9-1.1,30.8,6.5,37.7,21.2
C2498,1187.4,2488,1199.3,2474.4,1203.6z"/>
<path fill="#333333" d="M2586.4,1443.7c-2.6-19.1-21.2-33.7-39.3-36.6c-4-0.6-8-0.8-12-0.5c-0.6,0-1.2,0.2-1.7,0.3
c-1.5-0.6-3.2-0.5-4.9,0.5c-17.3,10-24.9,30.3-20.4,49.4c4.8,20.5,23.9,30.3,43.8,26.9C2572.5,1480.1,2589.4,1465.8,2586.4,1443.7
z M2556,1470.3c-15,4.7-30.5,1.5-35.8-14.7c-4.5-13.9,1-29.4,13.2-37.2c0.5,0.1,1.1,0.1,1.7,0.1c15.9-1.1,30.8,6.5,37.7,21.2
C2579.7,1454.1,2569.6,1466,2556,1470.3z"/>
<path fill="#333333" d="M2482.2,1049.5c-1-1-2-2-3-3c-2.9-2.9-7.7-2.9-10.6,0c-2.9,2.9-2.9,7.7,0,10.6c1,1,2,2,3,3
c2.9,2.9,7.7,2.9,10.6,0C2485.1,1057.2,2485.1,1052.4,2482.2,1049.5z"/>
<path fill="#333333" d="M2635.9,1038.3c-9.7,0-9.7,15,0,15S2645.6,1038.3,2635.9,1038.3z"/>
<path fill="#333333" d="M2656.9,894.3c-9.7,0-9.7,15,0,15S2666.6,894.3,2656.9,894.3z"/>
<path fill="#333333" d="M2515.2,1277.5c-2.9-2.9-7.7-2.9-10.6,0c-1,1-2,2-3,3c-2.9,2.9-2.9,7.7,0,10.6c2.9,2.9,7.7,2.9,10.6,0
c1-1,2-2,3-3C2518.1,1285.2,2518.1,1280.4,2515.2,1277.5z"/>
<path fill="#333333" d="M2593.9,1188.3c-9.7,0-9.7,15,0,15S2603.6,1188.3,2593.9,1188.3z"/>
<path fill="#333333" d="M2662.2,1331.5c-1-1-2-2-3-3c-2.9-2.9-7.7-2.9-10.6,0c-2.9,2.9-2.9,7.7,0,10.6c1,1,2,2,3,3
c2.9,2.9,7.7,2.9,10.6,0C2665.1,1339.2,2665.1,1334.4,2662.2,1331.5z"/>
<path fill="#333333" d="M2290.9,1455.3c-9.7,0-9.7,15,0,15S2300.6,1455.3,2290.9,1455.3z"/>
<path fill="#333333" d="M2563.9,1563.3c-9.7,0-9.7,15,0,15S2573.6,1563.3,2563.9,1563.3z"/>
<path fill="#333333" d="M139.7,951.3h-5.1c-4.1,0-7.5,3.4-7.5,7.5s3.4,7.5,7.5,7.5h5.1c4.1,0,7.5-3.4,7.5-7.5
S143.8,951.3,139.7,951.3z"/>
<path fill="#333333" d="M226.7,753.3c-9.7,0-9.7,15,0,15S236.4,753.3,226.7,753.3z"/>
<path fill="#333333" d="M376.7,978.3c-9.7,0-9.7,15,0,15S386.4,978.3,376.7,978.3z"/>
<path fill="#333333" d="M515.3,886.2c-1.3-2.3-3.8-4-6.6-4c-4.1,0-7.5,3.4-7.5,7.5c0,1.9,0.6,3.7,1.4,5.4c1.7,3.3,5.5,5.1,9.1,5.1
c4.1,0.1,7.5-3.5,7.5-7.5C519.2,889.9,517.6,887.5,515.3,886.2z"/>
<path fill="#333333" d="M726.3,970.8c0.2-4.1-3.5-7.5-7.5-7.5c-3.6,0-6.4,2.5-7.2,5.7c-0.5,0.6-1,1.1-1.5,1.8
c-1.3,1.7-1.7,3.9-1.8,6c-0.2,4.1,3.5,7.5,7.5,7.5c3.6,0,6.4-2.5,7.2-5.7c0.5-0.6,1-1.1,1.5-1.8
C725.7,975.1,726.2,972.8,726.3,970.8z"/>
<path fill="#333333" d="M775.8,861.3c-9.7,0-9.7,15,0,15S785.4,861.3,775.8,861.3z"/>
<path fill="#333333" d="M134.5,1249.3c-4.6-2.2-9.8-3.2-14.4-0.2c-4.8,3-6.9,8.6-8.7,13.7c-1.3,3.9,1.5,8.2,5.2,9.2
c4.1,1.1,7.9-1.4,9.2-5.2c0.3-0.8,0.5-1.5,0.8-2.2c0-0.1,0.1-0.2,0.1-0.3c0-0.1,0.1-0.2,0.2-0.4c0.2-0.4,0.4-0.8,0.6-1.2
c3.5,1.3,7.5,0.5,9.5-3C139.1,1256.3,138.2,1251.1,134.5,1249.3z"/>
<path fill="#333333" d="M334.7,1359.3c-9.7,0-9.7,15,0,15S344.4,1359.3,334.7,1359.3z"/>
<path fill="#333333" d="M778.8,1308.3c-9.7,0-9.7,15,0,15S788.4,1308.3,778.8,1308.3z"/>
<path fill="#333333" d="M979.8,1176.3c-9.7,0-9.7,15,0,15S989.5,1176.3,979.8,1176.3z"/>
<path fill="#333333" d="M1165.8,891.3c-4.1,0-7.5,3.4-7.5,7.5v3c0,4.1,3.4,7.5,7.5,7.5s7.5-3.4,7.5-7.5v-3
C1173.3,894.7,1169.9,891.3,1165.8,891.3z"/>
<path fill="#333333" d="M1372.8,924.3c-9.7,0-9.7,15,0,15S1382.5,924.3,1372.8,924.3z"/>
<path fill="#333333" d="M1510.1,851.5c-1-1-2-2-3-3c-2.9-2.9-7.7-2.9-10.6,0c-2.9,2.9-2.9,7.7,0,10.6c1,1,2,2,3,3
c2.9,2.9,7.7,2.9,10.6,0S1513,854.4,1510.1,851.5z"/>
<path fill="#333333" d="M1561.8,975.3c-9.7,0-9.7,15,0,15S1571.5,975.3,1561.8,975.3z"/>
<path fill="#333333" d="M1445.3,1369c-2.2-3.7-6.6-4.5-10.3-2.7c-4.8,2.4-10.1,3.6-15,6c-3.7,1.8-4.6,6.9-2.7,10.3
c2.2,3.7,6.6,4.5,10.3,2.7c4.8-2.4,10.1-3.6,15-6C1446.3,1377.5,1447.2,1372.4,1445.3,1369z"/>
<path fill="#333333" d="M1564.8,1278.3c-9.7,0-9.7,15,0,15S1574.5,1278.3,1564.8,1278.3z"/>
<path fill="#333333" d="M1771.9,867.3c-9.7,0-9.7,15,0,15S1781.5,867.3,1771.9,867.3z"/>
<path fill="#333333" d="M2027.4,922.2c-1.3-2.3-3.7-3.9-6.5-3.9c-4,0-7.6,3.4-7.5,7.5c0.1,3.7,1.8,7.2,5.1,9.1
c1.6,0.9,3.5,1.4,5.4,1.4c4.1,0,7.5-3.4,7.5-7.5C2031.4,925.9,2029.8,923.5,2027.4,922.2z"/>
<path fill="#333333" d="M2368.9,879.3c-9.7,0-9.7,15,0,15S2378.6,879.3,2368.9,879.3z"/>
<path fill="#333333" d="M1573.8,1725.4h-9c-4.1,0-7.5,3.4-7.5,7.5s3.4,7.5,7.5,7.5h9c4.1,0,7.5-3.4,7.5-7.5
S1577.9,1725.4,1573.8,1725.4z"/>
<path fill="#333333" d="M1768.9,1589.5c-4.1,0-7.5,3.4-7.5,7.5v3.8c0,4.1,3.4,7.5,7.5,7.5s7.5-3.4,7.5-7.5v-3.8
C1776.4,1592.9,1772.9,1589.5,1768.9,1589.5z"/>
<path fill="#333333" d="M1741.9,1473.3c-9.7,0-9.7,15,0,15S1751.5,1473.3,1741.9,1473.3z"/>
<path fill="#333333" d="M2020.9,1437.3c-9.7,0-9.7,15,0,15S2030.6,1437.3,2020.9,1437.3z"/>
<path fill="#333333" d="M1753.9,1929.4c-9.7,0-9.7,15,0,15S1763.5,1929.4,1753.9,1929.4z"/>
<path fill="#333333" d="M1888.9,2025.4c-1.1,0-2.1,0.2-3,0.7c-2.7-1.2-6-0.7-8.3,1.5c-2.8,2.8-2.9,7.8,0,10.6
c2.5,2.4,6.1,4.8,9.8,4.4c2.4-0.2,4.8-0.9,6.4-2.9c1.7-2.1,2.5-4.1,2.6-6.9C1896.5,2028.8,1892.8,2025.4,1888.9,2025.4z"/>
<path fill="#333333" d="M2077.9,1926.4c-9.7,0-9.7,15,0,15S2087.6,1926.4,2077.9,1926.4z"/>
<path fill="#333333" d="M2182.9,2022.4c-9.7,0-9.7,15,0,15S2192.6,2022.4,2182.9,2022.4z"/>
<path fill="#333333" d="M2389.9,1932.4c-9.7,0-9.7,15,0,15S2399.6,1932.4,2389.9,1932.4z"/>
<path fill="#333333" d="M2551.9,2004.4c-4.1,0-7.5,3.4-7.5,7.5v3c0,4.1,3.4,7.5,7.5,7.5s7.5-3.4,7.5-7.5v-3
C2559.4,2007.8,2556,2004.4,2551.9,2004.4z"/>
<path fill="#333333" d="M201,165.5c-3.1,0-5.7,1.9-6.9,4.6c-2.7,1.1-4.6,3.8-4.6,6.9c0,4.1,3.4,7.5,7.5,7.5c2.1,0,4-0.6,5.9-1.6
c3.6-1.9,5.5-6,5.6-9.9C208.6,168.9,205,165.5,201,165.5z"/>
<path fill="#333333" d="M577,57.5c-2.6,0-5.5,0-8,1c-4.7,1.9-7.3,5.4-7.5,10.5c-0.2,4.1,3.5,7.5,7.5,7.5c2.9,0,5.3-1.6,6.6-4
c0.5,0,1,0,1.4,0c4.1,0,7.5-3.4,7.5-7.5C584.5,60.9,581.1,57.5,577,57.5z"/>
<path fill="#333333" d="M1169,253.5h-4c-4.1,0-7.5,3.4-7.5,7.5s3.4,7.5,7.5,7.5h4c4.1,0,7.5-3.4,7.5-7.5S1173.1,253.5,1169,253.5z
"/>
<path fill="#333333" d="M985,137.5c-9.7,0-9.7,15,0,15S994.7,137.5,985,137.5z"/>
<path fill="#333333" d="M1381,141.5c-9.7,0-9.7,15,0,15S1390.7,141.5,1381,141.5z"/>
<path fill="#333333" d="M1577,277.5c-9.7,0-9.7,15,0,15S1586.7,277.5,1577,277.5z"/>
<path fill="#333333" d="M1762.3,203.7c-1.3-1.3-2.7-2.7-4-4c-2.9-2.9-7.7-2.9-10.6,0c-2.9,2.9-2.9,7.7,0,10.6c1.3,1.3,2.7,2.7,4,4
c2.9,2.9,7.7,2.9,10.6,0C1765.2,211.4,1765.2,206.6,1762.3,203.7z"/>
<path fill="#333333" d="M2193,257.5c-9.7,0-9.7,15,0,15S2202.7,257.5,2193,257.5z"/>
<path fill="#333333" d="M2349,405.5c-9.7,0-9.7,15,0,15S2358.7,405.5,2349,405.5z"/>
<path fill="#333333" d="M2417,169.5c-9.7,0-9.7,15,0,15S2426.7,169.5,2417,169.5z"/>
<path fill="#333333" d="M2621,513.5c-9.7,0-9.7,15,0,15S2630.7,513.5,2621,513.5z"/>
<path fill="#333333" d="M141,1649.5c-9.7,0-9.7,15,0,15S150.7,1649.5,141,1649.5z"/>
<path fill="#333333" d="M241,1709.5c-9.7,0-9.7,15,0,15S250.7,1709.5,241,1709.5z"/>
<path fill="#333333" d="M121,1917.5c-9.7,0-9.7,15,0,15S130.7,1917.5,121,1917.5z"/>
<path fill="#333333" d="M165,2177.5c-9.7,0-9.7,15,0,15S174.7,2177.5,165,2177.5z"/>
<path fill="#333333" d="M621,2689.5c-9.7,0-9.7,15,0,15S630.7,2689.5,621,2689.5z"/>
<path fill="#333333" d="M1009,2601.5h-8c-4.1,0-7.5,3.4-7.5,7.5s3.4,7.5,7.5,7.5h8c4.1,0,7.5-3.4,7.5-7.5
S1013.1,2601.5,1009,2601.5z"/>
<path fill="#333333" d="M1397,2057.5h-8c-4.1,0-7.5,3.4-7.5,7.5s3.4,7.5,7.5,7.5h8c4.1,0,7.5-3.4,7.5-7.5
S1401.1,2057.5,1397,2057.5z"/>
<path fill="#333333" d="M1421,2561.5c-9.7,0-9.7,15,0,15S1430.7,2561.5,1421,2561.5z"/>
<path fill="#333333" d="M1821,2561.5c-9.7,0-9.7,15,0,15S1830.7,2561.5,1821,2561.5z"/>
<path fill="#333333" d="M2028.6,2613c0.1-0.1,0.1-0.1,0.2-0.2c0.1-0.1,0.3-0.2,0.4-0.3c4-0.3,7.3-3.4,7.3-7.5c0-4-3.4-7.6-7.5-7.5
c-8.3,0.3-15.2,7.2-15.5,15.5c-0.1,4.1,3.5,7.5,7.5,7.5c4.1,0,7.2-3.3,7.5-7.2c0,0,0,0,0-0.1
C2028.5,2613.1,2028.6,2613.1,2028.6,2613z"/>
<path fill="#333333" d="M2301,2549.5c-9.7,0-9.7,15,0,15S2310.7,2549.5,2301,2549.5z"/>
<path fill="#333333" d="M2521,2569.5c-9.7,0-9.7,15,0,15S2530.7,2569.5,2521,2569.5z"/>
<path fill="#333333" d="M2613,2289.5c-9.7,0-9.7,15,0,15S2622.7,2289.5,2613,2289.5z"/>
<path fill="#333333" d="M1217,2577.5c-9.7,0-9.7,15,0,15S1226.7,2577.5,1217,2577.5z"/>
<path fill="#333333" d="M1621,2673.5c-9.7,0-9.7,15,0,15S1630.7,2673.5,1621,2673.5z"/>
<path fill="#333333" d="M989,2081.5c-9.7,0-9.7,15,0,15S998.7,2081.5,989,2081.5z"/>
<path fill="#333333" d="M1013,2293.5c-9.7,0-9.7,15,0,15S1022.7,2293.5,1013,2293.5z"/>
<path fill="#333333" d="M658.3,2043.7c-1.3-1.3-2.7-2.7-4-4c-2.9-2.9-7.7-2.9-10.6,0c-2.9,2.9-2.9,7.7,0,10.6c1.3,1.3,2.7,2.7,4,4
c2.9,2.9,7.7,2.9,10.6,0C661.2,2051.4,661.2,2046.6,658.3,2043.7z"/>
<path fill="#333333" d="M206.3,2303.7c-2.9-2.9-7.7-2.9-10.6,0c-1.3,1.3-2.7,2.7-4,4c-2.9,2.9-2.9,7.7,0,10.6
c2.9,2.9,7.7,2.9,10.6,0c1.3-1.3,2.7-2.7,4-4C209.2,2311.4,209.2,2306.6,206.3,2303.7z"/>
<path fill="#333333" d="M93,2377.5c-4.1,0-7.5,3.4-7.5,7.5v4c0,4.1,3.4,7.5,7.5,7.5s7.5-3.4,7.5-7.5v-4
C100.5,2380.9,97.1,2377.5,93,2377.5z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 52 KiB

+32
View File
@@ -0,0 +1,32 @@
[
{
"src": "assets/samples/K1_drawing.jpg",
"source": "https://commons.wikimedia.org/wiki/File:K1_drawing.jpg",
"credit": "<a href=\"https://commons.wikimedia.org/\">Wikimedia</a>"
},
{
"src": "assets/samples/Cityscape Sunset_DFM3-01.jpg",
"source": "https://www.vecteezy.com/vector-art/227400-beautiful-cityscape-at-sunset",
"credit": "<a href=\"https://www.vecteezy.com/free-vector/building\">Building Vectors by Vecteezy</a>"
},
{
"src": "assets/samples/Gum Tree Vector.jpg",
"source": "https://www.vecteezy.com/vector-art/172177-gum-tree-vector",
"credit": "<a href=\"https://www.vecteezy.com/free-vector/nature\">Nature Vectors by Vecteezy</a>"
},
{
"src": "assets/samples/vectorstock_31191940.png",
"source": "https://www.vectorstock.com/royalty-free-vector/dessert-poster-design-with-chocolate-cake-mousses-vector-31191940",
"credit": "<a href=\"https://www.vectorstock.com/royalty-free-vector/dessert-poster-design-with-chocolate-cake-mousses-vector-31191940\">Vector image by VectorStock / vectorstock</a>"
},
{
"src": "assets/samples/angel-luciano-LATYeZyw88c-unsplash-s.jpg",
"source": "https://unsplash.com/photos/LATYeZyw88c",
"credit": "<span>Photo by <a href=\"https://unsplash.com/@roaming_angel?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Angel Luciano</a> on <a href=\"https://unsplash.com/s/photos/dog?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText\">Unsplash</a></span>"
},
{
"src": "assets/samples/tank-unit-preview.png",
"source": "https://opengameart.org/content/sideview-sci-fi-patreon-collection",
"credit": "<span>Artwork by <a href=\"https://opengameart.org/content/sideview-sci-fi-patreon-collection\">Luis Zuno</a> on <a href=\"https://opengameart.org/\">opengameart.org</a></span>"
}
]
Generated Vendored
-366
View File
@@ -1,366 +0,0 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // install a JSONP callback for chunk loading
/******/ function webpackJsonpCallback(data) {
/******/ var chunkIds = data[0];
/******/ var moreModules = data[1];
/******/
/******/
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0, resolves = [];
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ resolves.push(installedChunks[chunkId][0]);
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ for(moduleId in moreModules) {
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
/******/ modules[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(parentJsonpFunction) parentJsonpFunction(data);
/******/
/******/ while(resolves.length) {
/******/ resolves.shift()();
/******/ }
/******/
/******/ };
/******/
/******/
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // object to store loaded and loading chunks
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
/******/ // Promise = chunk loading, 0 = chunk loaded
/******/ var installedChunks = {
/******/ "main": 0
/******/ };
/******/
/******/
/******/
/******/ // script path function
/******/ function jsonpScriptSrc(chunkId) {
/******/ return __webpack_require__.p + "" + chunkId + ".bootstrap.js"
/******/ }
/******/
/******/ // object to store loaded and loading wasm modules
/******/ var installedWasmModules = {};
/******/
/******/ function promiseResolve() { return Promise.resolve(); }
/******/
/******/ var wasmImportObjects = {
/******/ "../pkg/vtracer_webapp_bg.wasm": function() {
/******/ return {
/******/ "./vtracer_webapp_bg.js": {
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbg_new_59cb74e423758ede": function() {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_new_59cb74e423758ede"]();
/******/ },
/******/ "__wbg_stack_558ba5917b466edd": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_stack_558ba5917b466edd"](p0i32,p1i32);
/******/ },
/******/ "__wbg_error_4bb6c2a97407129a": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_error_4bb6c2a97407129a"](p0i32,p1i32);
/******/ },
/******/ "__wbg_instanceof_Window_adf3196bdc02b386": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_instanceof_Window_adf3196bdc02b386"](p0i32);
/******/ },
/******/ "__wbg_document_6cc8d0b87c0a99b9": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_document_6cc8d0b87c0a99b9"](p0i32);
/******/ },
/******/ "__wbg_createElementNS_ea14cb45a87a0719": function(p0i32,p1i32,p2i32,p3i32,p4i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_createElementNS_ea14cb45a87a0719"](p0i32,p1i32,p2i32,p3i32,p4i32);
/******/ },
/******/ "__wbg_getElementById_0cb6ad9511b1efc0": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_getElementById_0cb6ad9511b1efc0"](p0i32,p1i32,p2i32);
/******/ },
/******/ "__wbg_setAttribute_727bdb9763037624": function(p0i32,p1i32,p2i32,p3i32,p4i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_setAttribute_727bdb9763037624"](p0i32,p1i32,p2i32,p3i32,p4i32);
/******/ },
/******/ "__wbg_prepend_fa995bb42f6e2983": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_prepend_fa995bb42f6e2983"](p0i32,p1i32);
/******/ },
/******/ "__wbg_debug_d101e002eb92f20b": function(p0i32,p1i32,p2i32,p3i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_debug_d101e002eb92f20b"](p0i32,p1i32,p2i32,p3i32);
/******/ },
/******/ "__wbg_error_cb872335132b1ef7": function(p0i32,p1i32,p2i32,p3i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_error_cb872335132b1ef7"](p0i32,p1i32,p2i32,p3i32);
/******/ },
/******/ "__wbg_info_a25afde0ff8cd04a": function(p0i32,p1i32,p2i32,p3i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_info_a25afde0ff8cd04a"](p0i32,p1i32,p2i32,p3i32);
/******/ },
/******/ "__wbg_log_3bafd82835c6de6d": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_log_3bafd82835c6de6d"](p0i32);
/******/ },
/******/ "__wbg_log_64f566ae90a6c43c": function(p0i32,p1i32,p2i32,p3i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_log_64f566ae90a6c43c"](p0i32,p1i32,p2i32,p3i32);
/******/ },
/******/ "__wbg_warn_f632d7d3f55682b6": function(p0i32,p1i32,p2i32,p3i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_warn_f632d7d3f55682b6"](p0i32,p1i32,p2i32,p3i32);
/******/ },
/******/ "__wbg_instanceof_CanvasRenderingContext2d_5b86ec94bce38d5b": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_instanceof_CanvasRenderingContext2d_5b86ec94bce38d5b"](p0i32);
/******/ },
/******/ "__wbg_getImageData_888c08c04395524a": function(p0i32,p1f64,p2f64,p3f64,p4f64) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_getImageData_888c08c04395524a"](p0i32,p1f64,p2f64,p3f64,p4f64);
/******/ },
/******/ "__wbg_instanceof_HtmlCanvasElement_4f5b5ec6cd53ccf3": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_instanceof_HtmlCanvasElement_4f5b5ec6cd53ccf3"](p0i32);
/******/ },
/******/ "__wbg_width_a22f9855caa54b53": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_width_a22f9855caa54b53"](p0i32);
/******/ },
/******/ "__wbg_height_9a404a6b3c61c7ef": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_height_9a404a6b3c61c7ef"](p0i32);
/******/ },
/******/ "__wbg_getContext_37ca0870acb096d9": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_getContext_37ca0870acb096d9"](p0i32,p1i32,p2i32);
/******/ },
/******/ "__wbg_data_c2cd7a48734589b2": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_data_c2cd7a48734589b2"](p0i32,p1i32);
/******/ },
/******/ "__wbg_call_8e95613cc6524977": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_call_8e95613cc6524977"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_object_clone_ref"](p0i32);
/******/ },
/******/ "__wbg_newnoargs_f3b8a801d5d4b079": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_newnoargs_f3b8a801d5d4b079"](p0i32,p1i32);
/******/ },
/******/ "__wbg_self_07b2f89e82ceb76d": function() {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_self_07b2f89e82ceb76d"]();
/******/ },
/******/ "__wbg_window_ba85d88572adc0dc": function() {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_window_ba85d88572adc0dc"]();
/******/ },
/******/ "__wbg_globalThis_b9277fc37e201fe5": function() {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_globalThis_b9277fc37e201fe5"]();
/******/ },
/******/ "__wbg_global_e16303fe83e1d57f": function() {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbg_global_e16303fe83e1d57f"]();
/******/ },
/******/ "__wbindgen_is_undefined": function(p0i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_is_undefined"](p0i32);
/******/ },
/******/ "__wbindgen_debug_string": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_debug_string"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
/******/ return installedModules["../pkg/vtracer_webapp_bg.js"].exports["__wbindgen_throw"](p0i32,p1i32);
/******/ }
/******/ }
/******/ };
/******/ },
/******/ };
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = function requireEnsure(chunkId) {
/******/ var promises = [];
/******/
/******/
/******/ // JSONP chunk loading for javascript
/******/
/******/ var installedChunkData = installedChunks[chunkId];
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
/******/
/******/ // a Promise means "currently loading".
/******/ if(installedChunkData) {
/******/ promises.push(installedChunkData[2]);
/******/ } else {
/******/ // setup Promise in chunk cache
/******/ var promise = new Promise(function(resolve, reject) {
/******/ installedChunkData = installedChunks[chunkId] = [resolve, reject];
/******/ });
/******/ promises.push(installedChunkData[2] = promise);
/******/
/******/ // start chunk loading
/******/ var script = document.createElement('script');
/******/ var onScriptComplete;
/******/
/******/ script.charset = 'utf-8';
/******/ script.timeout = 120;
/******/ if (__webpack_require__.nc) {
/******/ script.setAttribute("nonce", __webpack_require__.nc);
/******/ }
/******/ script.src = jsonpScriptSrc(chunkId);
/******/
/******/ // create error before stack unwound to get useful stacktrace later
/******/ var error = new Error();
/******/ onScriptComplete = function (event) {
/******/ // avoid mem leaks in IE.
/******/ script.onerror = script.onload = null;
/******/ clearTimeout(timeout);
/******/ var chunk = installedChunks[chunkId];
/******/ if(chunk !== 0) {
/******/ if(chunk) {
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
/******/ var realSrc = event && event.target && event.target.src;
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
/******/ error.name = 'ChunkLoadError';
/******/ error.type = errorType;
/******/ error.request = realSrc;
/******/ chunk[1](error);
/******/ }
/******/ installedChunks[chunkId] = undefined;
/******/ }
/******/ };
/******/ var timeout = setTimeout(function(){
/******/ onScriptComplete({ type: 'timeout', target: script });
/******/ }, 120000);
/******/ script.onerror = script.onload = onScriptComplete;
/******/ document.head.appendChild(script);
/******/ }
/******/ }
/******/
/******/ // Fetch + compile chunk loading for webassembly
/******/
/******/ var wasmModules = {"0":["../pkg/vtracer_webapp_bg.wasm"]}[chunkId] || [];
/******/
/******/ wasmModules.forEach(function(wasmModuleId) {
/******/ var installedWasmModuleData = installedWasmModules[wasmModuleId];
/******/
/******/ // a Promise means "currently loading" or "already loaded".
/******/ if(installedWasmModuleData)
/******/ promises.push(installedWasmModuleData);
/******/ else {
/******/ var importObject = wasmImportObjects[wasmModuleId]();
/******/ var req = fetch(__webpack_require__.p + "" + {"../pkg/vtracer_webapp_bg.wasm":"589cb57662b50620abca"}[wasmModuleId] + ".module.wasm");
/******/ var promise;
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {
/******/ return WebAssembly.instantiate(items[0], items[1]);
/******/ });
/******/ } else if(typeof WebAssembly.instantiateStreaming === 'function') {
/******/ promise = WebAssembly.instantiateStreaming(req, importObject);
/******/ } else {
/******/ var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });
/******/ promise = bytesPromise.then(function(bytes) {
/******/ return WebAssembly.instantiate(bytes, importObject);
/******/ });
/******/ }
/******/ promises.push(installedWasmModules[wasmModuleId] = promise.then(function(res) {
/******/ return __webpack_require__.w[wasmModuleId] = (res.instance || res).exports;
/******/ }));
/******/ }
/******/ });
/******/ return Promise.all(promises);
/******/ };
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // on error function for async loading
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
/******/
/******/ // object with all WebAssembly.instance exports
/******/ __webpack_require__.w = {};
/******/
/******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
/******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
/******/ jsonpArray.push = webpackJsonpCallback;
/******/ jsonpArray = jsonpArray.slice();
/******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
/******/ var parentJsonpFunction = oldJsonpFunction;
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./bootstrap.js");
/******/ })
/************************************************************************/
/******/ ({
/***/ "./bootstrap.js":
/*!**********************!*\
!*** ./bootstrap.js ***!
\**********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
eval("// A dependency graph that contains any wasm must all be imported\n// asynchronously. This `bootstrap.js` file does the single async import, so\n// that no one else needs to worry about it again.\n__webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./index.js */ \"./index.js\"))\n .catch(e => console.error(\"Error importing `index.js`:\", e));\n\n\n//# sourceURL=webpack:///./bootstrap.js?");
/***/ })
/******/ });
-150
View File
@@ -1,150 +0,0 @@
# Stacked-Mode Equivalence Report
**Question:** does the rewritten 1.0 pipeline (`crates/vtracer`) reproduce the
shipping 0.6.x pipeline (`cmdapp/`) in **stacked** mode, byte-for-byte?
**Verdict:** **Yes.** Across a systematic sweep of **475 parameter
configurations**, every fitted path is geometrically identical (worst
coordinate deviation **1e-8 px** — float-serialization noise). The only
differences are two intentional, visually-invisible ones (documented below).
Date: 2026-07-24. Comparison target: `pixel`, `polygon`, `spline` fitters;
`color` and `bw` color modes.
---
## Scope
- **Stacked only.** Old `--hierarchical cutout` is the *fake* cutout (re-render
the clustered image, re-cluster, retrace); new `cutout` is the topological
mosaic. They are deliberately different algorithms and are **not** expected to
match. Mosaic is verified separately (pixel round-trip + seam tests).
- **Geometry, not pixels.** Comparison parses each SVG's `<path d>` (applying
any `transform="translate()"`) into absolute coordinates and compares those
directly. This is stronger than a raster diff (no antialiasing fuzz) and
isolates the pipeline from the SVG writer.
- **`--path-precision 8`.** High precision so writer rounding can never mask a
real geometry difference. (At the default precision 2, the two writers round
slightly differently — see *Known differences*.)
## Reference oracle
`cmdapp/` (0.6.x) is built with **matched dependencies** — the same local
`visioncortex` 0.9.0 and `image` 0.25 as the new crates — so the comparison
isolates *pipeline logic* from library drift:
- Same `visioncortex` ⇒ identical clustering and curve fitting primitives.
- Same `image` ⇒ identical decoding (JPEG decoding is decoder-version
dependent; PNG is lossless either way).
New is run with `--optimize 0` (no optimizer passes, absolute writer) so the
comparison reflects the tracing/fitting pipeline, not the optimizer. The
optimizer is verified lossless separately.
## Parameter space
| Parameter | Range swept | Affects |
|---|---|---|
| `colormode` | color, bw | frontend |
| `mode` | pixel, polygon, spline | curve fitter |
| `filter_speckle` | 0 16 | frontend (min area) |
| `color_precision` | 1 8 | color clustering |
| `gradient_step` | 0 255 | color layer difference |
| `corner_threshold` | 0 180 | spline |
| `segment_length` | 3.5 10 | spline |
| `splice_threshold` | 0 180 | spline |
The full Cartesian product is ~10¹²; instead the sweep uses a layered strategy
that touches every value of every parameter plus randomized interactions.
## Coverage & results
475 configurations, tank-unit-preview.png (PNG) plus a Gum Tree (JPEG) baseline set:
| Group | Configs | Geometry failures | Worst Δ |
|---|---:|---:|---:|
| Categorical cross (colormode × mode) | 6 | 0 | 1e-8 |
| `filter_speckle` 016 × mode × colormode | 102 | 0 | 1e-8 |
| `color_precision` 18 × mode | 24 | 0 | 1e-8 |
| `gradient_step` 0255 × mode | 39 | 0 | 1e-8 |
| `corner_threshold` 0180 (spline) | 26 | 0 | 1e-8 |
| `segment_length` 3.510 (spline) | 9 | 0 | 1e-8 |
| `splice_threshold` 0180 (spline) | 13 | 0 | 1e-8 |
| Random joint combinations | 250 | 0 | 1e-8 |
| Second image (Gum Tree, JPEG) | 6 | 0 | 1e-8 |
| **Total** | **475** | **0** | **1e-8** |
- **Geometry mismatches (> 1e-6 px): 0.**
- **Empty-path-count divergences: 10** (cosmetic; see below).
By fitter: `pixel` and `polygon` are byte-for-byte identical in both color and
bw. `spline` geometry is identical to 1e-8; the sub-pixel deltas visible at low
`--path-precision` are writer rounding, not geometry.
## Known differences (intentional, invisible)
1. **SVG encoding.** The new writer uses compact relative/shorthand commands
with offsets baked into coordinates; 0.6.x used absolute coordinates plus a
per-path `transform="translate()"`. Same geometry, different bytes — by
design (the new writer is smaller). Verified equal after parsing to absolute
coordinates.
2. **Empty paths.** At `filter_speckle = 0`, tiny (≈1px) clusters survive
filtering; their spline fit is empty. 0.6.x emits a degenerate
`<path d="">` for each (e.g. 67 of them in one bw/spline case); the new
pipeline omits them. They render nothing, so output is visually identical.
This accounts for all 10 "empty-path divergences" and appears only at the
nonsensical `filter_speckle = 0`.
## Bugs found and fixed during this verification
This report's process surfaced two real bugs (both fixed, both now
regression-guarded):
1. **Stacked layers had holes/seams.** The color frontend traced clusters with
holes punched (`to_image_with_hole(.., true)`); stacked mode must trace
*solid* layers and rely on paint-order overdraw (`false`). Symptom: hairline
seams (partial-alpha jumped 4.86% → 0.36% after the fix).
Guard: `stacked_has_no_seams` (a full-coverage image must render fully
opaque — zero backdrop show-through).
2. **Relative writer placed holes wrong.** After `Z`, SVG resets the current
point to the subpath start; the emitter left it at the last vertex, so a
relative `m` for a hole/second subpath was offset. Only visible on
multi-subpath shapes at `optimize=1/2`.
Guard: `relative_and_absolute_encode_same_geometry` (a holed shape must
encode identically absolute vs relative).
## Harness caveats (for reproduction)
- 0.6.x accepts only `--mode` (no `-m`) and treats `--colormode` as binary
**only for the value `bw`**`binary` silently falls through to color. Use
`bw` for both binaries.
- 0.6.x spline mode `pixel` maps to `PathSimplifyMode::None`.
## Reproduction
`cmdapp/` (0.6.x) was removed from the tree after this verification; restore it
from git history (the commit before "Remove the 0.6.x cmdapp crate") to
reproduce.
1. Temporarily point `cmdapp/Cargo.toml` at the matched dependencies
(`image = "0.25"`, `visioncortex = { version = "0.9", path = "../../visioncortex" }`)
and build both binaries:
```sh
cargo build --release --manifest-path cmdapp/Cargo.toml
cargo build --release -p vtracer-cli
```
2. For each configuration, run both binaries in stacked mode with
`--path-precision 8` (new also with `--optimize 0`), remembering the harness
caveats above (`--mode` not `-m`; `--colormode bw`).
3. Parse each SVG's `<path d>` into absolute coordinates (apply any
`transform="translate()"`), drop empty paths, and compare the coordinate
sequences. Equivalent ⇔ per-coordinate deviation < 1e-6.
## Conclusion
In stacked mode the new pipeline is a **byte-for-byte-faithful reimplementation**
of 0.6.x across the full parameter space for `pixel` and `polygon`, and
geometrically identical for `spline`. Remaining differences are limited to the
intentional compact SVG encoding and the omission of degenerate empty paths.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

-320
View File
@@ -1,320 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>VTracer</title>
<link rel="apple-touch-icon" sizes="192x192" href="./assets/apple-icon.png">
<link rel="icon" type="image/png" sizes="192x192" href="./assets/apple-icon.png">
<!-- UIkit CSS -->
<link rel="stylesheet" href="./uikit/css/uikit.min.css" />
<!-- UIkit JS -->
<script src="./uikit/js/uikit.min.js"></script>
<script src="./uikit/js/uikit-icons.min.js"></script>
<script type="text/javascript">
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "403biw7tra");
</script>
<style>
html, body {
width: 100%;
height: 100%;
}
.uk-dark body,
.uk-dark .container {
background: #fff;
}
.uk-dark #vc-logo-light {
display: none;
}
.uk-light #vc-logo {
display: none;
}
.uk-light body,
.uk-light .container,
.uk-light .uk-modal-dialog {
background: #2e2e2e;
}
@media screen and (prefers-color-scheme: dark) {
html {
background: #2e2e2e;
}
}
#droptext {
background: #00275D;
border: 2px dashed #CC972E;
}
#droptext.hovering {
border: 2px dashed #fff;
}
.uk-navbar-right.uk-padding-small {
padding-top: 0;
padding-bottom: 0;
}
#export,
.uk-button-group .uk-button.selected {
color: #fff;
background: #00275D;
border-color: #CC972E;
}
.uk-dark #export,
.uk-dark .uk-button-group .uk-button.selected {
border-width: 2px;
}
.uk-dark #droptext {
border-width: 4px;
}
.uk-button-group > button {
padding-left: 10px;
padding-right: 10px;
}
@media only screen and (min-width: 1280px) {
.uk-button-group > button {
padding-left: 25px;
padding-right: 25px;
}
}
#canvas-container {
position: relative;
height: max-content;
}
#svg, #frame {
position: absolute;
width: 100%;
margin-bottom: 50px;
}
#svg > path:hover {
stroke: #ff0;
}
#droptext {
height: 480px;
color: #CC972E;
}
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
background: #00275D;
border-color: #CC972E;
}
input[type=range]::-moz-range-thumb {
background: #00275D;
border-color: #CC972E;
}
input[type=range]::-ms-thumb {
background: #00275D;
border-color: #CC972E;
}
#drop, #gallery, #options {
border-top: 1px solid #686868;
}
#gallery {
padding-bottom: 0;
}
.galleryitem {
cursor: pointer;
padding: 2px;
margin: 1px;
}
.galleryitem:hover {
padding: 0px;
margin: 0px;
border: 2px solid #CC972E;
}
.galleryitem img {
max-height: 120px;
}
.uk-text-meta {
font-size: 12px;
}
</style>
</head>
<body class="uk-dark">
<input type="file" id="imageInput" accept="image/*" style="display: none;">
<div class="container uk-padding" uk-grid>
<div class="uk-width-1-1 uk-navbar-container uk-navbar-transparent" uk-navbar>
<div class="uk-navbar-left uk-text-large uk-text-bolder">
<a id="vc-logo" class="uk-logo" href="//www.visioncortex.org"><img style="height: 50px; margin: -30px 0 -25px 0;" src="./assets/visioncortex-logo.svg"></a>
<a id="vc-logo-light" class="uk-logo" href="//www.visioncortex.org"><img style="height: 50px; margin: -30px 0 -25px 0;" src="./assets/visioncortex-logo-light.svg"></a>
&nbsp;
/ VTracer
</div>
<div class="uk-navbar-right uk-padding-small">
<a class="uk-button uk-button-default" href="//www.visioncortex.org/vtracer-docs">Article</a>
&nbsp;&nbsp;
<a class="uk-button uk-button-default" href="//github.com/visioncortex/vtracer">GitHub</a>
&nbsp;&nbsp;
<a id="export" class="uk-button uk-button-primary">Download as SVG</a>
</div>
</div>
<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>
</div>
<div class="uk-width-3-4">
<div id="drop" class="uk-padding uk-flex uk-flex-center">
<div id="canvas-container" class="uk-width-1-1">
<div id="droptext" class="uk-flex uk-flex-middle uk-flex-center">
<p>Drag an image here, Cmd-V to paste or <a href="#" id="imageSelect">Select file</a></p>
</div>
<canvas id="frame"></canvas>
<svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg"></svg>
</div>
</div>
<div id="gallery" class="uk-padding">
<div class="uk-inline" uk-slider>
<ul id="galleryslider" class="uk-slider-items uk-child-width-1-6 uk-grid uk-grid-small">
</ul>
<a class="uk-position-center-left uk-position-small uk-hidden-hover" href="#" uk-slidenav-previous uk-slider-item="previous"></a>
<a class="uk-position-center-right uk-position-small uk-hidden-hover" href="#" uk-slidenav-next uk-slider-item="next"></a>
</div>
<a class="uk-align-right uk-text-meta" style="margin:-5px;" uk-toggle="target: #credits-modal">Photo Credits</a>
</div>
</div>
<div id="options" class="uk-width-1-4 uk-height-1-1 uk-grid-small uk-flex uk-flex-center" uk-grid>
<div class="uk-width-1-1 uk-flex uk-flex-right">
&nbsp;
</div>
<p></p>
<div class="uk-width-1-1 uk-flex uk-flex-right">
<div class="uk-text-bold" uk-tooltip="pos:left; title: Algorithm for segmentation and grouping of pixel clusters">
Clustering
</div>
</div>
<div class="uk-width-1-1 uk-flex uk-flex-right">
<div class="uk-button-group">
<button id="clustering-binary" class="uk-button uk-button-default" uk-tooltip="Black & White (Binary Image)">B/W</button>
<button id="clustering-color" class="selected uk-button uk-button-default" uk-tooltip="True Color Image">Color</button>
</div>
</div>
<div class="clustering-color-options uk-width-1-1 uk-flex uk-flex-right">
<div class="uk-button-group">
<button id="clustering-cutout" class="uk-button uk-button-default uk-button-small" uk-tooltip="Shapes disjoint with others">Cutout</button>
<button id="clustering-stacked" class="selected uk-button uk-button-default uk-button-small" uk-tooltip="Stack shapes on top of another">Stacked</button>
</div>
</div>
<div class="uk-width-1-1 uk-flex uk-flex-right">
<div uk-tooltip="pos: left; title: Discard patches small than X px in size">
Filter Speckle <span class="uk-text-meta">(Cleaner)</span>
</div>
</div>
<div id="filterspecklevalue" class="uk-width-1-6">
4
</div>
<div class="uk-width-5-6">
<input id="filterspeckle" class="uk-range" type="range" min="0" max="128" step="1" value="4">
</div>
<div class="clustering-color-options uk-width-1-1 uk-flex uk-flex-right">
<div uk-tooltip="pos: left; title: Number of significant bits to use in a RGB channel">
Color Precision <span class="uk-text-meta">(More accurate)</span>
</div>
</div>
<div id="colorprecisionvalue" class="clustering-color-options uk-width-1-6">
6
</div>
<div class="clustering-color-options uk-width-5-6">
<input id="colorprecision" class="uk-range" type="range" min="1" max="8" step="1" value="6">
</div>
<div class="clustering-color-options uk-width-1-1 uk-flex uk-flex-right">
<div uk-tooltip="pos: left; title: Color difference between gradient layers">
Gradient Step <span class="uk-text-meta">(Less layers)</span>
</div>
</div>
<div id="layerdifferencevalue" class="clustering-color-options uk-width-1-6">
16
</div>
<div class="clustering-color-options uk-width-5-6">
<input id="layerdifference" class="uk-range" type="range" min="0" max="128" step="1" value="16">
</div>
<div class="uk-width-1-1 uk-flex uk-flex-right">
<div class="uk-text-bold" uk-tooltip="pos: left; title: Algorithm for converting clusters to shapes">
Curve Fitting
</div>
</div>
<div class="uk-width-1-1 uk-flex uk-flex-right">
<div class="uk-button-group">
<button id="none" class="uk-button uk-button-default" uk-tooltip="Exact cluster boundary">PIXEL</button>
<button id="polygon" class="uk-button uk-button-default" uk-tooltip="Simplify to Polygon">Polygon</button>
<button id="spline" class="selected uk-button uk-button-default" uk-tooltip="Smooth and Curve-fit">Spline</button>
</div>
</div>
<div class="spline-options uk-width-1-1 uk-flex uk-flex-right">
<div uk-tooltip="pos: left; title: Minimum Momentary Angle (in degrees) to be considered a corner (to be kept after smoothing)">
Corner Threshold <span class="uk-text-meta">(Smoother)</span>
</div>
</div>
<div id="cornervalue" class="spline-options uk-width-1-6">
60
</div>
<div class="spline-options uk-width-5-6">
<input id="corner" class="uk-range" type="range" min="0" max="180" step="1" value="60">
</div>
<div class="spline-options uk-width-1-1 uk-flex uk-flex-right">
<div uk-tooltip="pos: left; title: Perform Iterative Subdivide Smooth until all segments are shorter than this length">
Segment Length <span class="uk-text-meta">(More coarse)</span>
</div>
</div>
<div id="lengthvalue" class="spline-options uk-width-1-6">
4
</div>
<div class="spline-options uk-width-5-6">
<input id="length" class="uk-range" type="range" min="3.5" max="10" step="0.5" value="4">
</div>
<div class="spline-options uk-width-1-1 uk-flex uk-flex-right">
<div uk-tooltip="pos: left; title: Minimum Angle Displacement (in degrees) to be considered a cutting point between curves">
Splice Threshold <span class="uk-text-meta">(Less accurate)</span>
</div>
</div>
<div id="splicevalue" class="spline-options uk-width-1-6">
45
</div>
<div class="spline-options uk-width-5-6">
<input id="splice" class="uk-range" type="range" min="0" max="180" step="1" value="45">
</div>
<div style="display: none">
<div class="spline-options uk-width-1-1 uk-flex uk-flex-right">
<div uk-tooltip="pos: left; title: Number of decimal places used in svg path string">
Path Precision <span class="uk-text-meta">(More digits)</span>
</div>
</div>
<div id="pathprecisionvalue" class="spline-options uk-width-1-6">
8
</div>
<div class="spline-options uk-width-5-6">
<input id="pathprecision" class="uk-range" type="range" min="0" max="16" step="1" value="8">
</div>
</div>
</div>
</div>
<div id="credits-modal" uk-modal>
<div id="credits-modal-content" class="uk-modal-dialog uk-modal-body">
<p>Image Credits</p>
</div>
</div>
<script>
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.body.classList.remove('uk-dark');
document.body.classList.add('uk-light');
}
</script>
<script src="./bootstrap.js"></script>
</body>
</html>
-12503
View File
File diff suppressed because it is too large Load Diff
-1
View File
File diff suppressed because one or more lines are too long
-12503
View File
File diff suppressed because it is too large Load Diff
-1
View File
File diff suppressed because one or more lines are too long
-167
View File
@@ -1,167 +0,0 @@
/*! UIkit 3.5.8 | https://www.getuikit.com | (c) 2014 - 2020 YOOtheme | MIT License */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define('uikiticons', factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.UIkitIcons = factory());
}(this, (function () { 'use strict';
function plugin(UIkit) {
if (plugin.installed) {
return;
}
UIkit.icon.add({
"500px": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M9.624,11.866c-0.141,0.132,0.479,0.658,0.662,0.418c0.051-0.046,0.607-0.61,0.662-0.664c0,0,0.738,0.719,0.814,0.719 c0.1,0,0.207-0.055,0.322-0.17c0.27-0.269,0.135-0.416,0.066-0.495l-0.631-0.616l0.658-0.668c0.146-0.156,0.021-0.314-0.1-0.449 c-0.182-0.18-0.359-0.226-0.471-0.125l-0.656,0.654l-0.654-0.654c-0.033-0.034-0.08-0.045-0.124-0.045 c-0.079,0-0.191,0.068-0.307,0.181c-0.202,0.202-0.247,0.351-0.133,0.462l0.665,0.665L9.624,11.866z\"/><path d=\"M11.066,2.884c-1.061,0-2.185,0.248-3.011,0.604c-0.087,0.034-0.141,0.106-0.15,0.205C7.893,3.784,7.919,3.909,7.982,4.066 c0.05,0.136,0.187,0.474,0.452,0.372c0.844-0.326,1.779-0.507,2.633-0.507c0.963,0,1.9,0.191,2.781,0.564 c0.695,0.292,1.357,0.719,2.078,1.34c0.051,0.044,0.105,0.068,0.164,0.068c0.143,0,0.273-0.137,0.389-0.271 c0.191-0.214,0.324-0.395,0.135-0.575c-0.686-0.654-1.436-1.138-2.363-1.533C13.24,3.097,12.168,2.884,11.066,2.884z\"/><path d=\"M16.43,15.747c-0.092-0.028-0.242,0.05-0.309,0.119l0,0c-0.652,0.652-1.42,1.169-2.268,1.521 c-0.877,0.371-1.814,0.551-2.779,0.551c-0.961,0-1.896-0.189-2.775-0.564c-0.848-0.36-1.612-0.879-2.268-1.53 c-0.682-0.688-1.196-1.455-1.529-2.268c-0.325-0.799-0.471-1.643-0.471-1.643c-0.045-0.24-0.258-0.249-0.567-0.203 c-0.128,0.021-0.519,0.079-0.483,0.36v0.01c0.105,0.644,0.289,1.284,0.545,1.895c0.417,0.969,1.002,1.849,1.756,2.604 c0.757,0.754,1.636,1.34,2.604,1.757C8.901,18.785,9.97,19,11.088,19c1.104,0,2.186-0.215,3.188-0.645 c1.838-0.896,2.604-1.757,2.604-1.757c0.182-0.204,0.227-0.317-0.1-0.643C16.779,15.956,16.525,15.774,16.43,15.747z\"/><path d=\"M5.633,13.287c0.293,0.71,0.723,1.341,1.262,1.882c0.54,0.54,1.172,0.971,1.882,1.264c0.731,0.303,1.509,0.461,2.298,0.461 c0.801,0,1.578-0.158,2.297-0.461c0.711-0.293,1.344-0.724,1.883-1.264c0.543-0.541,0.971-1.172,1.264-1.882 c0.314-0.721,0.463-1.5,0.463-2.298c0-0.79-0.148-1.569-0.463-2.289c-0.293-0.699-0.721-1.329-1.264-1.881 c-0.539-0.541-1.172-0.959-1.867-1.263c-0.721-0.303-1.5-0.461-2.299-0.461c-0.802,0-1.613,0.159-2.322,0.461 c-0.577,0.25-1.544,0.867-2.119,1.454v0.012V2.108h8.16C15.1,2.104,15.1,1.69,15.1,1.552C15.1,1.417,15.1,1,14.809,1H5.915 C5.676,1,5.527,1.192,5.527,1.384v6.84c0,0.214,0.273,0.372,0.529,0.428c0.5,0.105,0.614-0.056,0.737-0.224l0,0 c0.18-0.273,0.776-0.884,0.787-0.894c0.901-0.905,2.117-1.408,3.416-1.408c1.285,0,2.5,0.501,3.412,1.408 c0.914,0.914,1.408,2.122,1.408,3.405c0,1.288-0.508,2.496-1.408,3.405c-0.9,0.896-2.152,1.406-3.438,1.406 c-0.877,0-1.711-0.229-2.433-0.671v-4.158c0-0.553,0.237-1.151,0.643-1.614c0.462-0.519,1.094-0.799,1.782-0.799 c0.664,0,1.293,0.253,1.758,0.715c0.459,0.459,0.709,1.071,0.709,1.723c0,1.385-1.094,2.468-2.488,2.468 c-0.273,0-0.769-0.121-0.781-0.125c-0.281-0.087-0.405,0.306-0.438,0.436c-0.159,0.496,0.079,0.585,0.123,0.607 c0.452,0.137,0.743,0.157,1.129,0.157c1.973,0,3.572-1.6,3.572-3.57c0-1.964-1.6-3.552-3.572-3.552c-0.97,0-1.872,0.36-2.546,1.038 c-0.656,0.631-1.027,1.487-1.027,2.322v3.438v-0.011c-0.372-0.42-0.732-1.041-0.981-1.682c-0.102-0.248-0.315-0.202-0.607-0.113 c-0.135,0.035-0.519,0.157-0.44,0.439C5.372,12.799,5.577,13.164,5.633,13.287z\"/></svg>",
"album": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"5\" y=\"2\" width=\"10\" height=\"1\"/><rect x=\"3\" y=\"4\" width=\"14\" height=\"1\"/><rect fill=\"none\" stroke=\"#000\" x=\"1.5\" y=\"6.5\" width=\"17\" height=\"11\"/></svg>",
"arrow-down": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"10.5,16.08 5.63,10.66 6.37,10 10.5,14.58 14.63,10 15.37,10.66\"/><line fill=\"none\" stroke=\"#000\" x1=\"10.5\" y1=\"4\" x2=\"10.5\" y2=\"15\"/></svg>",
"arrow-left": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"10 14 5 9.5 10 5\"/><line fill=\"none\" stroke=\"#000\" x1=\"16\" y1=\"9.5\" x2=\"5\" y2=\"9.52\"/></svg>",
"arrow-right": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"10 5 15 9.5 10 14\"/><line fill=\"none\" stroke=\"#000\" x1=\"4\" y1=\"9.5\" x2=\"15\" y2=\"9.5\"/></svg>",
"arrow-up": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"10.5,4 15.37,9.4 14.63,10.08 10.5,5.49 6.37,10.08 5.63,9.4\"/><line fill=\"none\" stroke=\"#000\" x1=\"10.5\" y1=\"16\" x2=\"10.5\" y2=\"5\"/></svg>",
"ban": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10\" cy=\"10\" r=\"9\"/><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" x1=\"4\" y1=\"3.5\" x2=\"16\" y2=\"16.5\"/></svg>",
"behance": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M9.5,10.6c-0.4-0.5-0.9-0.9-1.6-1.1c1.7-1,2.2-3.2,0.7-4.7C7.8,4,6.3,4,5.2,4C3.5,4,1.7,4,0,4v12c1.7,0,3.4,0,5.2,0 c1,0,2.1,0,3.1-0.5C10.2,14.6,10.5,12.3,9.5,10.6L9.5,10.6z M5.6,6.1c1.8,0,1.8,2.7-0.1,2.7c-1,0-2,0-2.9,0V6.1H5.6z M2.6,13.8v-3.1 c1.1,0,2.1,0,3.2,0c2.1,0,2.1,3.2,0.1,3.2L2.6,13.8z\"/><path d=\"M19.9,10.9C19.7,9.2,18.7,7.6,17,7c-4.2-1.3-7.3,3.4-5.3,7.1c0.9,1.7,2.8,2.3,4.7,2.1c1.7-0.2,2.9-1.3,3.4-2.9h-2.2 c-0.4,1.3-2.4,1.5-3.5,0.6c-0.4-0.4-0.6-1.1-0.6-1.7H20C20,11.7,19.9,10.9,19.9,10.9z M13.5,10.6c0-1.6,2.3-2.7,3.5-1.4 c0.4,0.4,0.5,0.9,0.6,1.4H13.5L13.5,10.6z\"/><rect x=\"13\" y=\"4\" width=\"5\" height=\"1.4\"/></svg>",
"bell": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M17,15.5 L3,15.5 C2.99,14.61 3.79,13.34 4.1,12.51 C4.58,11.3 4.72,10.35 5.19,7.01 C5.54,4.53 5.89,3.2 7.28,2.16 C8.13,1.56 9.37,1.5 9.81,1.5 L9.96,1.5 C9.96,1.5 11.62,1.41 12.67,2.17 C14.08,3.2 14.42,4.54 14.77,7.02 C15.26,10.35 15.4,11.31 15.87,12.52 C16.2,13.34 17.01,14.61 17,15.5 L17,15.5 Z\"/><path fill=\"none\" stroke=\"#000\" d=\"M12.39,16 C12.39,17.37 11.35,18.43 9.91,18.43 C8.48,18.43 7.42,17.37 7.42,16\"/></svg>",
"bold": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M5,15.3 C5.66,15.3 5.9,15 5.9,14.53 L5.9,5.5 C5.9,4.92 5.56,4.7 5,4.7 L5,4 L8.95,4 C12.6,4 13.7,5.37 13.7,6.9 C13.7,7.87 13.14,9.17 10.86,9.59 L10.86,9.7 C13.25,9.86 14.29,11.28 14.3,12.54 C14.3,14.47 12.94,16 9,16 L5,16 L5,15.3 Z M9,9.3 C11.19,9.3 11.8,8.5 11.85,7 C11.85,5.65 11.3,4.8 9,4.8 L7.67,4.8 L7.67,9.3 L9,9.3 Z M9.185,15.22 C11.97,15 12.39,14 12.4,12.58 C12.4,11.15 11.39,10 9,10 L7.67,10 L7.67,15 L9.18,15 Z\"/></svg>",
"bolt": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M4.74,20 L7.73,12 L3,12 L15.43,1 L12.32,9 L17.02,9 L4.74,20 L4.74,20 L4.74,20 Z M9.18,11 L7.1,16.39 L14.47,10 L10.86,10 L12.99,4.67 L5.61,11 L9.18,11 L9.18,11 L9.18,11 Z\"/></svg>",
"bookmark": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon fill=\"none\" stroke=\"#000\" points=\"5.5 1.5 15.5 1.5 15.5 17.5 10.5 12.5 5.5 17.5\"/></svg>",
"calendar": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M 2,3 2,17 18,17 18,3 2,3 Z M 17,16 3,16 3,8 17,8 17,16 Z M 17,7 3,7 3,4 17,4 17,7 Z\"/><rect width=\"1\" height=\"3\" x=\"6\" y=\"2\"/><rect width=\"1\" height=\"3\" x=\"13\" y=\"2\"/></svg>",
"camera": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10\" cy=\"10.8\" r=\"3.8\"/><path fill=\"none\" stroke=\"#000\" d=\"M1,4.5 C0.7,4.5 0.5,4.7 0.5,5 L0.5,17 C0.5,17.3 0.7,17.5 1,17.5 L19,17.5 C19.3,17.5 19.5,17.3 19.5,17 L19.5,5 C19.5,4.7 19.3,4.5 19,4.5 L13.5,4.5 L13.5,2.9 C13.5,2.6 13.3,2.5 13,2.5 L7,2.5 C6.7,2.5 6.5,2.6 6.5,2.9 L6.5,4.5 L1,4.5 L1,4.5 Z\"/></svg>",
"cart": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"7.3\" cy=\"17.3\" r=\"1.4\"/><circle cx=\"13.3\" cy=\"17.3\" r=\"1.4\"/><polyline fill=\"none\" stroke=\"#000\" points=\"0 2 3.2 4 5.3 12.5 16 12.5 18 6.5 8 6.5\"/></svg>",
"check": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" points=\"4,10 8,15 17,4\"/></svg>",
"chevron-double-left": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.03\" points=\"10 14 6 10 10 6\"/><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.03\" points=\"14 14 10 10 14 6\"/></svg>",
"chevron-double-right": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.03\" points=\"10 6 14 10 10 14\"/><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.03\" points=\"6 6 10 10 6 14\"/></svg>",
"chevron-down": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.03\" points=\"16 7 10 13 4 7\"/></svg>",
"chevron-left": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.03\" points=\"13 16 7 10 13 4\"/></svg>",
"chevron-right": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.03\" points=\"7 4 13 10 7 16\"/></svg>",
"chevron-up": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.03\" points=\"4 13 10 7 16 13\"/></svg>",
"clock": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10\" cy=\"10\" r=\"9\"/><rect x=\"9\" y=\"4\" width=\"1\" height=\"7\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M13.018,14.197 L9.445,10.625\"/></svg>",
"close": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.06\" d=\"M16,16 L4,4\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.06\" d=\"M16,4 L4,16\"/></svg>",
"cloud-download": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M6.5,14.61 L3.75,14.61 C1.96,14.61 0.5,13.17 0.5,11.39 C0.5,9.76 1.72,8.41 3.3,8.2 C3.38,5.31 5.75,3 8.68,3 C11.19,3 13.31,4.71 13.89,7.02 C14.39,6.8 14.93,6.68 15.5,6.68 C17.71,6.68 19.5,8.45 19.5,10.64 C19.5,12.83 17.71,14.6 15.5,14.6 L12.5,14.6\"/><polyline fill=\"none\" stroke=\"#000\" points=\"11.75 16 9.5 18.25 7.25 16\"/><path fill=\"none\" stroke=\"#000\" d=\"M9.5,18 L9.5,9.5\"/></svg>",
"cloud-upload": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M6.5,14.61 L3.75,14.61 C1.96,14.61 0.5,13.17 0.5,11.39 C0.5,9.76 1.72,8.41 3.31,8.2 C3.38,5.31 5.75,3 8.68,3 C11.19,3 13.31,4.71 13.89,7.02 C14.39,6.8 14.93,6.68 15.5,6.68 C17.71,6.68 19.5,8.45 19.5,10.64 C19.5,12.83 17.71,14.6 15.5,14.6 L12.5,14.6\"/><polyline fill=\"none\" stroke=\"#000\" points=\"7.25 11.75 9.5 9.5 11.75 11.75\"/><path fill=\"none\" stroke=\"#000\" d=\"M9.5,18 L9.5,9.5\"/></svg>",
"code": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.01\" points=\"13,4 19,10 13,16\"/><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.01\" points=\"7,4 1,10 7,16\"/></svg>",
"cog": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" cx=\"9.997\" cy=\"10\" r=\"3.31\"/><path fill=\"none\" stroke=\"#000\" d=\"M18.488,12.285 L16.205,16.237 C15.322,15.496 14.185,15.281 13.303,15.791 C12.428,16.289 12.047,17.373 12.246,18.5 L7.735,18.5 C7.938,17.374 7.553,16.299 6.684,15.791 C5.801,15.27 4.655,15.492 3.773,16.237 L1.5,12.285 C2.573,11.871 3.317,10.999 3.317,9.991 C3.305,8.98 2.573,8.121 1.5,7.716 L3.765,3.784 C4.645,4.516 5.794,4.738 6.687,4.232 C7.555,3.722 7.939,2.637 7.735,1.5 L12.263,1.5 C12.072,2.637 12.441,3.71 13.314,4.22 C14.206,4.73 15.343,4.516 16.225,3.794 L18.487,7.714 C17.404,8.117 16.661,8.988 16.67,10.009 C16.672,11.018 17.415,11.88 18.488,12.285 L18.488,12.285 Z\"/></svg>",
"comment": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6,18.71 L6,14 L1,14 L1,1 L19,1 L19,14 L10.71,14 L6,18.71 L6,18.71 Z M2,13 L7,13 L7,16.29 L10.29,13 L18,13 L18,2 L2,2 L2,13 L2,13 Z\"/></svg>",
"commenting": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon fill=\"none\" stroke=\"#000\" points=\"1.5,1.5 18.5,1.5 18.5,13.5 10.5,13.5 6.5,17.5 6.5,13.5 1.5,13.5\"/><circle cx=\"10\" cy=\"8\" r=\"1\"/><circle cx=\"6\" cy=\"8\" r=\"1\"/><circle cx=\"14\" cy=\"8\" r=\"1\"/></svg>",
"comments": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"2 0.5 19.5 0.5 19.5 13\"/><path d=\"M5,19.71 L5,15 L0,15 L0,2 L18,2 L18,15 L9.71,15 L5,19.71 L5,19.71 L5,19.71 Z M1,14 L6,14 L6,17.29 L9.29,14 L17,14 L17,3 L1,3 L1,14 L1,14 L1,14 Z\"/></svg>",
"copy": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"2.5\" width=\"12\" height=\"16\"/><polyline fill=\"none\" stroke=\"#000\" points=\"5 0.5 17.5 0.5 17.5 17\"/></svg>",
"credit-card": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"1.5\" y=\"4.5\" width=\"17\" height=\"12\"/><rect x=\"1\" y=\"7\" width=\"18\" height=\"3\"/></svg>",
"database": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><ellipse fill=\"none\" stroke=\"#000\" cx=\"10\" cy=\"4.64\" rx=\"7.5\" ry=\"3.14\"/><path fill=\"none\" stroke=\"#000\" d=\"M17.5,8.11 C17.5,9.85 14.14,11.25 10,11.25 C5.86,11.25 2.5,9.84 2.5,8.11\"/><path fill=\"none\" stroke=\"#000\" d=\"M17.5,11.25 C17.5,12.99 14.14,14.39 10,14.39 C5.86,14.39 2.5,12.98 2.5,11.25\"/><path fill=\"none\" stroke=\"#000\" d=\"M17.49,4.64 L17.5,14.36 C17.5,16.1 14.14,17.5 10,17.5 C5.86,17.5 2.5,16.09 2.5,14.36 L2.5,4.64\"/></svg>",
"desktop": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"8\" y=\"15\" width=\"1\" height=\"2\"/><rect x=\"11\" y=\"15\" width=\"1\" height=\"2\"/><rect x=\"5\" y=\"16\" width=\"10\" height=\"1\"/><rect fill=\"none\" stroke=\"#000\" x=\"1.5\" y=\"3.5\" width=\"17\" height=\"11\"/></svg>",
"download": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"14,10 9.5,14.5 5,10\"/><rect x=\"3\" y=\"17\" width=\"13\" height=\"1\"/><line fill=\"none\" stroke=\"#000\" x1=\"9.5\" y1=\"13.91\" x2=\"9.5\" y2=\"3\"/></svg>",
"dribbble": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" d=\"M1.3,8.9c0,0,5,0.1,8.6-1c1.4-0.4,2.6-0.9,4-1.9 c1.4-1.1,2.5-2.5,2.5-2.5\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" d=\"M3.9,16.6c0,0,1.7-2.8,3.5-4.2 c1.8-1.3,4-2,5.7-2.2C16,10,19,10.6,19,10.6\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" d=\"M6.9,1.6c0,0,3.3,4.6,4.2,6.8 c0.4,0.9,1.3,3.1,1.9,5.2c0.6,2,0.9,4.4,0.9,4.4\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.4\" cx=\"10\" cy=\"10\" r=\"9\"/></svg>",
"etsy": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 20 20\"><path d=\"M8,4.26C8,4.07,8,4,8.31,4h4.46c.79,0,1.22.67,1.53,1.91l.25,1h.76c.14-2.82.26-4,.26-4S13.65,3,12.52,3H6.81L3.75,2.92v.84l1,.2c.73.11.9.27,1,1,0,0,.06,2,.06,5.17s-.06,5.14-.06,5.14c0,.59-.23.81-1,.94l-1,.2v.84l3.06-.1h5.11c1.15,0,3.82.1,3.82.1,0-.7.45-3.88.51-4.22h-.73l-.76,1.69a2.25,2.25,0,0,1-2.45,1.47H9.4c-1,0-1.44-.4-1.44-1.24V10.44s2.16,0,2.86.06c.55,0,.85.19,1.06,1l.23,1H13L12.9,9.94,13,7.41h-.85l-.28,1.13c-.16.74-.28.84-1,1-1,.1-2.89.09-2.89.09Z\"/></svg>",
"expand": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"13 2 18 2 18 7 17 7 17 3 13 3\"/><polygon points=\"2 13 3 13 3 17 7 17 7 18 2 18\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M11,9 L17,3\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M3,17 L9,11\"/></svg>",
"facebook": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M11,10h2.6l0.4-3H11V5.3c0-0.9,0.2-1.5,1.5-1.5H14V1.1c-0.3,0-1-0.1-2.1-0.1C9.6,1,8,2.4,8,5v2H5.5v3H8v8h3V10z\"/></svg>",
"file-edit": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M18.65,1.68 C18.41,1.45 18.109,1.33 17.81,1.33 C17.499,1.33 17.209,1.45 16.98,1.68 L8.92,9.76 L8,12.33 L10.55,11.41 L18.651,3.34 C19.12,2.87 19.12,2.15 18.65,1.68 L18.65,1.68 L18.65,1.68 Z\"/><polyline fill=\"none\" stroke=\"#000\" points=\"16.5 8.482 16.5 18.5 3.5 18.5 3.5 1.5 14.211 1.5\"/></svg>",
"file-pdf": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" width=\"13\" height=\"17\" x=\"3.5\" y=\"1.5\"/><path d=\"M14.65 11.67c-.48.3-1.37-.19-1.79-.37a4.65 4.65 0 0 1 1.49.06c.35.1.36.28.3.31zm-6.3.06l.43-.79a14.7 14.7 0 0 0 .75-1.64 5.48 5.48 0 0 0 1.25 1.55l.2.15a16.36 16.36 0 0 0-2.63.73zM9.5 5.32c.2 0 .32.5.32.97a1.99 1.99 0 0 1-.23 1.04 5.05 5.05 0 0 1-.17-1.3s0-.71.08-.71zm-3.9 9a4.35 4.35 0 0 1 1.21-1.46l.24-.22a4.35 4.35 0 0 1-1.46 1.68zm9.23-3.3a2.05 2.05 0 0 0-1.32-.3 11.07 11.07 0 0 0-1.58.11 4.09 4.09 0 0 1-.74-.5 5.39 5.39 0 0 1-1.32-2.06 10.37 10.37 0 0 0 .28-2.62 1.83 1.83 0 0 0-.07-.25.57.57 0 0 0-.52-.4H9.4a.59.59 0 0 0-.6.38 6.95 6.95 0 0 0 .37 3.14c-.26.63-1 2.12-1 2.12-.3.58-.57 1.08-.82 1.5l-.8.44A3.11 3.11 0 0 0 5 14.16a.39.39 0 0 0 .15.42l.24.13c1.15.56 2.28-1.74 2.66-2.42a23.1 23.1 0 0 1 3.59-.85 4.56 4.56 0 0 0 2.91.8.5.5 0 0 0 .3-.21 1.1 1.1 0 0 0 .12-.75.84.84 0 0 0-.14-.25z\"/></svg>",
"file-text": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" width=\"13\" height=\"17\" x=\"3.5\" y=\"1.5\"/><line fill=\"none\" stroke=\"#000\" x1=\"6\" x2=\"12\" y1=\"12.5\" y2=\"12.5\"/><line fill=\"none\" stroke=\"#000\" x1=\"6\" x2=\"14\" y1=\"8.5\" y2=\"8.5\"/><line fill=\"none\" stroke=\"#000\" x1=\"6\" x2=\"14\" y1=\"6.5\" y2=\"6.5\"/><line fill=\"none\" stroke=\"#000\" x1=\"6\" x2=\"14\" y1=\"10.5\" y2=\"10.5\"/></svg>",
"file": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"1.5\" width=\"13\" height=\"17\"/></svg>",
"flickr": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"5.5\" cy=\"9.5\" r=\"3.5\"/><circle cx=\"14.5\" cy=\"9.5\" r=\"3.5\"/></svg>",
"folder": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon fill=\"none\" stroke=\"#000\" points=\"9.5 5.5 8.5 3.5 1.5 3.5 1.5 16.5 18.5 16.5 18.5 5.5\"/></svg>",
"forward": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.47,13.11 C4.02,10.02 6.27,7.85 9.04,6.61 C9.48,6.41 10.27,6.13 11,5.91 L11,2 L18.89,9 L11,16 L11,12.13 C9.25,12.47 7.58,13.19 6.02,14.25 C3.03,16.28 1.63,18.54 1.63,18.54 C1.63,18.54 1.38,15.28 2.47,13.11 L2.47,13.11 Z M5.3,13.53 C6.92,12.4 9.04,11.4 12,10.92 L12,13.63 L17.36,9 L12,4.25 L12,6.8 C11.71,6.86 10.86,7.02 9.67,7.49 C6.79,8.65 4.58,10.96 3.49,13.08 C3.18,13.7 2.68,14.87 2.49,16 C3.28,15.05 4.4,14.15 5.3,13.53 L5.3,13.53 Z\"/></svg>",
"foursquare": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.23,2 C15.96,2 16.4,2.41 16.5,2.86 C16.57,3.15 16.56,3.44 16.51,3.73 C16.46,4.04 14.86,11.72 14.75,12.03 C14.56,12.56 14.16,12.82 13.61,12.83 C13.03,12.84 11.09,12.51 10.69,13 C10.38,13.38 7.79,16.39 6.81,17.53 C6.61,17.76 6.4,17.96 6.08,17.99 C5.68,18.04 5.29,17.87 5.17,17.45 C5.12,17.28 5.1,17.09 5.1,16.91 C5.1,12.4 4.86,7.81 5.11,3.31 C5.17,2.5 5.81,2.12 6.53,2 L15.23,2 L15.23,2 Z M9.76,11.42 C9.94,11.19 10.17,11.1 10.45,11.1 L12.86,11.1 C13.12,11.1 13.31,10.94 13.36,10.69 C13.37,10.64 13.62,9.41 13.74,8.83 C13.81,8.52 13.53,8.28 13.27,8.28 C12.35,8.29 11.42,8.28 10.5,8.28 C9.84,8.28 9.83,7.69 9.82,7.21 C9.8,6.85 10.13,6.55 10.5,6.55 C11.59,6.56 12.67,6.55 13.76,6.55 C14.03,6.55 14.23,6.4 14.28,6.14 C14.34,5.87 14.67,4.29 14.67,4.29 C14.67,4.29 14.82,3.74 14.19,3.74 L7.34,3.74 C7,3.75 6.84,4.02 6.84,4.33 C6.84,7.58 6.85,14.95 6.85,14.99 C6.87,15 8.89,12.51 9.76,11.42 L9.76,11.42 Z\"/></svg>",
"future": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline points=\"19 2 18 2 18 6 14 6 14 7 19 7 19 2\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M18,6.548 C16.709,3.29 13.354,1 9.6,1 C4.6,1 0.6,5 0.6,10 C0.6,15 4.6,19 9.6,19 C14.6,19 18.6,15 18.6,10\"/><rect x=\"9\" y=\"4\" width=\"1\" height=\"7\"/><path d=\"M13.018,14.197 L9.445,10.625\" fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\"/></svg>",
"git-branch": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" cx=\"7\" cy=\"3\" r=\"2\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" cx=\"14\" cy=\"6\" r=\"2\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" cx=\"7\" cy=\"17\" r=\"2\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"2\" d=\"M14,8 C14,10.41 12.43,10.87 10.56,11.25 C9.09,11.54 7,12.06 7,15 L7,5\"/></svg>",
"git-fork": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" cx=\"5.79\" cy=\"2.79\" r=\"1.79\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" cx=\"14.19\" cy=\"2.79\" r=\"1.79\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" cx=\"10.03\" cy=\"16.79\" r=\"1.79\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"2\" d=\"M5.79,4.57 L5.79,6.56 C5.79,9.19 10.03,10.22 10.03,13.31 C10.03,14.86 10.04,14.55 10.04,14.55 C10.04,14.37 10.04,14.86 10.04,13.31 C10.04,10.22 14.2,9.19 14.2,6.56 L14.2,4.57\"/></svg>",
"github-alt": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10,0.5 C4.75,0.5 0.5,4.76 0.5,10.01 C0.5,15.26 4.75,19.51 10,19.51 C15.24,19.51 19.5,15.26 19.5,10.01 C19.5,4.76 15.25,0.5 10,0.5 L10,0.5 Z M12.81,17.69 C12.81,17.69 12.81,17.7 12.79,17.69 C12.47,17.75 12.35,17.59 12.35,17.36 L12.35,16.17 C12.35,15.45 12.09,14.92 11.58,14.56 C12.2,14.51 12.77,14.39 13.26,14.21 C13.87,13.98 14.36,13.69 14.74,13.29 C15.42,12.59 15.76,11.55 15.76,10.17 C15.76,9.25 15.45,8.46 14.83,7.8 C15.1,7.08 15.07,6.29 14.75,5.44 L14.51,5.42 C14.34,5.4 14.06,5.46 13.67,5.61 C13.25,5.78 12.79,6.03 12.31,6.35 C11.55,6.16 10.81,6.05 10.09,6.05 C9.36,6.05 8.61,6.15 7.88,6.35 C7.28,5.96 6.75,5.68 6.26,5.54 C6.07,5.47 5.9,5.44 5.78,5.44 L5.42,5.44 C5.06,6.29 5.04,7.08 5.32,7.8 C4.7,8.46 4.4,9.25 4.4,10.17 C4.4,11.94 4.96,13.16 6.08,13.84 C6.53,14.13 7.05,14.32 7.69,14.43 C8.03,14.5 8.32,14.54 8.55,14.55 C8.07,14.89 7.82,15.42 7.82,16.16 L7.82,17.51 C7.8,17.69 7.7,17.8 7.51,17.8 C4.21,16.74 1.82,13.65 1.82,10.01 C1.82,5.5 5.49,1.83 10,1.83 C14.5,1.83 18.17,5.5 18.17,10.01 C18.18,13.53 15.94,16.54 12.81,17.69 L12.81,17.69 Z\"/></svg>",
"github": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10,1 C5.03,1 1,5.03 1,10 C1,13.98 3.58,17.35 7.16,18.54 C7.61,18.62 7.77,18.34 7.77,18.11 C7.77,17.9 7.76,17.33 7.76,16.58 C5.26,17.12 4.73,15.37 4.73,15.37 C4.32,14.33 3.73,14.05 3.73,14.05 C2.91,13.5 3.79,13.5 3.79,13.5 C4.69,13.56 5.17,14.43 5.17,14.43 C5.97,15.8 7.28,15.41 7.79,15.18 C7.87,14.6 8.1,14.2 8.36,13.98 C6.36,13.75 4.26,12.98 4.26,9.53 C4.26,8.55 4.61,7.74 5.19,7.11 C5.1,6.88 4.79,5.97 5.28,4.73 C5.28,4.73 6.04,4.49 7.75,5.65 C8.47,5.45 9.24,5.35 10,5.35 C10.76,5.35 11.53,5.45 12.25,5.65 C13.97,4.48 14.72,4.73 14.72,4.73 C15.21,5.97 14.9,6.88 14.81,7.11 C15.39,7.74 15.73,8.54 15.73,9.53 C15.73,12.99 13.63,13.75 11.62,13.97 C11.94,14.25 12.23,14.8 12.23,15.64 C12.23,16.84 12.22,17.81 12.22,18.11 C12.22,18.35 12.38,18.63 12.84,18.54 C16.42,17.35 19,13.98 19,10 C19,5.03 14.97,1 10,1 L10,1 Z\"/></svg>",
"gitter": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"3.5\" y=\"1\" width=\"1.531\" height=\"11.471\"/><rect x=\"7.324\" y=\"4.059\" width=\"1.529\" height=\"15.294\"/><rect x=\"11.148\" y=\"4.059\" width=\"1.527\" height=\"15.294\"/><rect x=\"14.971\" y=\"4.059\" width=\"1.529\" height=\"8.412\"/></svg>",
"google-plus": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M12.9,9c0,2.7-0.6,5-3.2,6.3c-3.7,1.8-8.1,0.2-9.4-3.6C-1.1,7.6,1.9,3.3,6.1,3c1.7-0.1,3.2,0.3,4.6,1.3 c0.1,0.1,0.3,0.2,0.4,0.4c-0.5,0.5-1.2,1-1.7,1.6c-1-0.8-2.1-1.1-3.5-0.9C5,5.6,4.2,6,3.6,6.7c-1.3,1.3-1.5,3.4-0.5,5 c1,1.7,2.6,2.3,4.6,1.9c1.4-0.3,2.4-1.2,2.6-2.6H6.9V9H12.9z\"/><polygon points=\"20,9 20,11 18,11 18,13 16,13 16,11 14,11 14,9 16,9 16,7 18,7 18,9\"/></svg>",
"google": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.86,9.09 C18.46,12.12 17.14,16.05 13.81,17.56 C9.45,19.53 4.13,17.68 2.47,12.87 C0.68,7.68 4.22,2.42 9.5,2.03 C11.57,1.88 13.42,2.37 15.05,3.65 C15.22,3.78 15.37,3.93 15.61,4.14 C14.9,4.81 14.23,5.45 13.5,6.14 C12.27,5.08 10.84,4.72 9.28,4.98 C8.12,5.17 7.16,5.76 6.37,6.63 C4.88,8.27 4.62,10.86 5.76,12.82 C6.95,14.87 9.17,15.8 11.57,15.25 C13.27,14.87 14.76,13.33 14.89,11.75 L10.51,11.75 L10.51,9.09 L17.86,9.09 L17.86,9.09 Z\"/></svg>",
"grid": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"2\" y=\"2\" width=\"3\" height=\"3\"/><rect x=\"8\" y=\"2\" width=\"3\" height=\"3\"/><rect x=\"14\" y=\"2\" width=\"3\" height=\"3\"/><rect x=\"2\" y=\"8\" width=\"3\" height=\"3\"/><rect x=\"8\" y=\"8\" width=\"3\" height=\"3\"/><rect x=\"14\" y=\"8\" width=\"3\" height=\"3\"/><rect x=\"2\" y=\"14\" width=\"3\" height=\"3\"/><rect x=\"8\" y=\"14\" width=\"3\" height=\"3\"/><rect x=\"14\" y=\"14\" width=\"3\" height=\"3\"/></svg>",
"happy": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"13\" cy=\"7\" r=\"1\"/><circle cx=\"7\" cy=\"7\" r=\"1\"/><circle fill=\"none\" stroke=\"#000\" cx=\"10\" cy=\"10\" r=\"8.5\"/><path fill=\"none\" stroke=\"#000\" d=\"M14.6,11.4 C13.9,13.3 12.1,14.5 10,14.5 C7.9,14.5 6.1,13.3 5.4,11.4\"/></svg>",
"hashtag": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.431,8 L15.661,7 L12.911,7 L13.831,3 L12.901,3 L11.98,7 L9.29,7 L10.21,3 L9.281,3 L8.361,7 L5.23,7 L5,8 L8.13,8 L7.21,12 L4.23,12 L4,13 L6.98,13 L6.061,17 L6.991,17 L7.911,13 L10.601,13 L9.681,17 L10.611,17 L11.531,13 L14.431,13 L14.661,12 L11.76,12 L12.681,8 L15.431,8 Z M10.831,12 L8.141,12 L9.061,8 L11.75,8 L10.831,12 Z\"/></svg>",
"heart": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.03\" d=\"M10,4 C10,4 8.1,2 5.74,2 C3.38,2 1,3.55 1,6.73 C1,8.84 2.67,10.44 2.67,10.44 L10,18 L17.33,10.44 C17.33,10.44 19,8.84 19,6.73 C19,3.55 16.62,2 14.26,2 C11.9,2 10,4 10,4 L10,4 Z\"/></svg>",
"history": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"#000\" points=\"1 2 2 2 2 6 6 6 6 7 1 7 1 2\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M2.1,6.548 C3.391,3.29 6.746,1 10.5,1 C15.5,1 19.5,5 19.5,10 C19.5,15 15.5,19 10.5,19 C5.5,19 1.5,15 1.5,10\"/><rect x=\"9\" y=\"4\" width=\"1\" height=\"7\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M13.018,14.197 L9.445,10.625\"/></svg>",
"home": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"18.65 11.35 10 2.71 1.35 11.35 0.65 10.65 10 1.29 19.35 10.65\"/><polygon points=\"15 4 18 4 18 7 17 7 17 5 15 5\"/><polygon points=\"3 11 4 11 4 18 7 18 7 12 12 12 12 18 16 18 16 11 17 11 17 19 11 19 11 13 8 13 8 19 3 19\"/></svg>",
"image": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"16.1\" cy=\"6.1\" r=\"1.1\"/><rect fill=\"none\" stroke=\"#000\" x=\".5\" y=\"2.5\" width=\"19\" height=\"15\"/><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.01\" points=\"4,13 8,9 13,14\"/><polyline fill=\"none\" stroke=\"#000\" stroke-width=\"1.01\" points=\"11,12 12.5,10.5 16,14\"/></svg>",
"info": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M12.13,11.59 C11.97,12.84 10.35,14.12 9.1,14.16 C6.17,14.2 9.89,9.46 8.74,8.37 C9.3,8.16 10.62,7.83 10.62,8.81 C10.62,9.63 10.12,10.55 9.88,11.32 C8.66,15.16 12.13,11.15 12.14,11.18 C12.16,11.21 12.16,11.35 12.13,11.59 C12.08,11.95 12.16,11.35 12.13,11.59 L12.13,11.59 Z M11.56,5.67 C11.56,6.67 9.36,7.15 9.36,6.03 C9.36,5 11.56,4.54 11.56,5.67 L11.56,5.67 Z\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10\" cy=\"10\" r=\"9\"/></svg>",
"instagram": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M13.55,1H6.46C3.45,1,1,3.44,1,6.44v7.12c0,3,2.45,5.44,5.46,5.44h7.08c3.02,0,5.46-2.44,5.46-5.44V6.44 C19.01,3.44,16.56,1,13.55,1z M17.5,14c0,1.93-1.57,3.5-3.5,3.5H6c-1.93,0-3.5-1.57-3.5-3.5V6c0-1.93,1.57-3.5,3.5-3.5h8 c1.93,0,3.5,1.57,3.5,3.5V14z\"/><circle cx=\"14.87\" cy=\"5.26\" r=\"1.09\"/><path d=\"M10.03,5.45c-2.55,0-4.63,2.06-4.63,4.6c0,2.55,2.07,4.61,4.63,4.61c2.56,0,4.63-2.061,4.63-4.61 C14.65,7.51,12.58,5.45,10.03,5.45L10.03,5.45L10.03,5.45z M10.08,13c-1.66,0-3-1.34-3-2.99c0-1.65,1.34-2.99,3-2.99s3,1.34,3,2.99 C13.08,11.66,11.74,13,10.08,13L10.08,13L10.08,13z\"/></svg>",
"italic": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M12.63,5.48 L10.15,14.52 C10,15.08 10.37,15.25 11.92,15.3 L11.72,16 L6,16 L6.2,15.31 C7.78,15.26 8.19,15.09 8.34,14.53 L10.82,5.49 C10.97,4.92 10.63,4.76 9.09,4.71 L9.28,4 L15,4 L14.81,4.69 C13.23,4.75 12.78,4.91 12.63,5.48 L12.63,5.48 Z\"/></svg>",
"joomla": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7.8,13.4l1.7-1.7L5.9,8c-0.6-0.5-0.6-1.5,0-2c0.6-0.6,1.4-0.6,2,0l1.7-1.7c-1-1-2.3-1.3-3.6-1C5.8,2.2,4.8,1.4,3.7,1.4 c-1.3,0-2.3,1-2.3,2.3c0,1.1,0.8,2,1.8,2.3c-0.4,1.3-0.1,2.8,1,3.8L7.8,13.4L7.8,13.4z\"/><path d=\"M10.2,4.3c1-1,2.5-1.4,3.8-1c0.2-1.1,1.1-2,2.3-2c1.3,0,2.3,1,2.3,2.3c0,1.2-0.9,2.2-2,2.3c0.4,1.3,0,2.8-1,3.8L13.9,8 c0.6-0.5,0.6-1.5,0-2c-0.5-0.6-1.5-0.6-2,0L8.2,9.7L6.5,8\"/><path d=\"M14.1,16.8c-1.3,0.4-2.8,0.1-3.8-1l1.7-1.7c0.6,0.6,1.5,0.6,2,0c0.5-0.6,0.6-1.5,0-2l-3.7-3.7L12,6.7l3.7,3.7 c1,1,1.3,2.4,1,3.6c1.1,0.2,2,1.1,2,2.3c0,1.3-1,2.3-2.3,2.3C15.2,18.6,14.3,17.8,14.1,16.8\"/><path d=\"M13.2,12.2l-3.7,3.7c-1,1-2.4,1.3-3.6,1c-0.2,1-1.2,1.8-2.2,1.8c-1.3,0-2.3-1-2.3-2.3c0-1.1,0.8-2,1.8-2.3 c-0.3-1.3,0-2.7,1-3.7l1.7,1.7c-0.6,0.6-0.6,1.5,0,2c0.6,0.6,1.4,0.6,2,0l3.7-3.7\"/></svg>",
"laptop": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect y=\"16\" width=\"20\" height=\"1\"/><rect fill=\"none\" stroke=\"#000\" x=\"2.5\" y=\"4.5\" width=\"15\" height=\"10\"/></svg>",
"lifesaver": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10,0.5 C4.76,0.5 0.5,4.76 0.5,10 C0.5,15.24 4.76,19.5 10,19.5 C15.24,19.5 19.5,15.24 19.5,10 C19.5,4.76 15.24,0.5 10,0.5 L10,0.5 Z M10,1.5 C11.49,1.5 12.89,1.88 14.11,2.56 L11.85,4.82 C11.27,4.61 10.65,4.5 10,4.5 C9.21,4.5 8.47,4.67 7.79,4.96 L5.58,2.75 C6.87,1.95 8.38,1.5 10,1.5 L10,1.5 Z M4.96,7.8 C4.67,8.48 4.5,9.21 4.5,10 C4.5,10.65 4.61,11.27 4.83,11.85 L2.56,14.11 C1.88,12.89 1.5,11.49 1.5,10 C1.5,8.38 1.95,6.87 2.75,5.58 L4.96,7.79 L4.96,7.8 L4.96,7.8 Z M10,18.5 C8.25,18.5 6.62,17.97 5.27,17.06 L7.46,14.87 C8.22,15.27 9.08,15.5 10,15.5 C10.79,15.5 11.53,15.33 12.21,15.04 L14.42,17.25 C13.13,18.05 11.62,18.5 10,18.5 L10,18.5 Z M10,14.5 C7.52,14.5 5.5,12.48 5.5,10 C5.5,7.52 7.52,5.5 10,5.5 C12.48,5.5 14.5,7.52 14.5,10 C14.5,12.48 12.48,14.5 10,14.5 L10,14.5 Z M15.04,12.21 C15.33,11.53 15.5,10.79 15.5,10 C15.5,9.08 15.27,8.22 14.87,7.46 L17.06,5.27 C17.97,6.62 18.5,8.25 18.5,10 C18.5,11.62 18.05,13.13 17.25,14.42 L15.04,12.21 L15.04,12.21 Z\"/></svg>",
"link": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M10.625,12.375 L7.525,15.475 C6.825,16.175 5.925,16.175 5.225,15.475 L4.525,14.775 C3.825,14.074 3.825,13.175 4.525,12.475 L7.625,9.375\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M9.325,7.375 L12.425,4.275 C13.125,3.575 14.025,3.575 14.724,4.275 L15.425,4.975 C16.125,5.675 16.125,6.575 15.425,7.275 L12.325,10.375\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M7.925,11.875 L11.925,7.975\"/></svg>",
"linkedin": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M5.77,17.89 L5.77,7.17 L2.21,7.17 L2.21,17.89 L5.77,17.89 L5.77,17.89 Z M3.99,5.71 C5.23,5.71 6.01,4.89 6.01,3.86 C5.99,2.8 5.24,2 4.02,2 C2.8,2 2,2.8 2,3.85 C2,4.88 2.77,5.7 3.97,5.7 L3.99,5.7 L3.99,5.71 L3.99,5.71 Z\"/><path d=\"M7.75,17.89 L11.31,17.89 L11.31,11.9 C11.31,11.58 11.33,11.26 11.43,11.03 C11.69,10.39 12.27,9.73 13.26,9.73 C14.55,9.73 15.06,10.71 15.06,12.15 L15.06,17.89 L18.62,17.89 L18.62,11.74 C18.62,8.45 16.86,6.92 14.52,6.92 C12.6,6.92 11.75,7.99 11.28,8.73 L11.3,8.73 L11.3,7.17 L7.75,7.17 C7.79,8.17 7.75,17.89 7.75,17.89 L7.75,17.89 L7.75,17.89 Z\"/></svg>",
"list": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"6\" y=\"4\" width=\"12\" height=\"1\"/><rect x=\"6\" y=\"9\" width=\"12\" height=\"1\"/><rect x=\"6\" y=\"14\" width=\"12\" height=\"1\"/><rect x=\"2\" y=\"4\" width=\"2\" height=\"1\"/><rect x=\"2\" y=\"9\" width=\"2\" height=\"1\"/><rect x=\"2\" y=\"14\" width=\"2\" height=\"1\"/></svg>",
"location": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.01\" d=\"M10,0.5 C6.41,0.5 3.5,3.39 3.5,6.98 C3.5,11.83 10,19 10,19 C10,19 16.5,11.83 16.5,6.98 C16.5,3.39 13.59,0.5 10,0.5 L10,0.5 Z\"/><circle fill=\"none\" stroke=\"#000\" cx=\"10\" cy=\"6.8\" r=\"2.3\"/></svg>",
"lock": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" height=\"10\" width=\"13\" y=\"8.5\" x=\"3.5\"/><path fill=\"none\" stroke=\"#000\" d=\"M6.5,8 L6.5,4.88 C6.5,3.01 8.07,1.5 10,1.5 C11.93,1.5 13.5,3.01 13.5,4.88 L13.5,8\"/></svg>",
"mail": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"1.4,6.5 10,11 18.6,6.5\"/><path d=\"M 1,4 1,16 19,16 19,4 1,4 Z M 18,15 2,15 2,5 18,5 18,15 Z\"/></svg>",
"menu": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"2\" y=\"4\" width=\"16\" height=\"1\"/><rect x=\"2\" y=\"9\" width=\"16\" height=\"1\"/><rect x=\"2\" y=\"14\" width=\"16\" height=\"1\"/></svg>",
"microphone": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><line fill=\"none\" stroke=\"#000\" x1=\"10\" x2=\"10\" y1=\"16.44\" y2=\"18.5\"/><line fill=\"none\" stroke=\"#000\" x1=\"7\" x2=\"13\" y1=\"18.5\" y2=\"18.5\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M13.5 4.89v5.87a3.5 3.5 0 0 1-7 0V4.89a3.5 3.5 0 0 1 7 0z\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M15.5 10.36V11a5.5 5.5 0 0 1-11 0v-.6\"/></svg>",
"minus-circle": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"9.5\" cy=\"9.5\" r=\"9\"/><line fill=\"none\" stroke=\"#000\" x1=\"5\" y1=\"9.5\" x2=\"14\" y2=\"9.5\"/></svg>",
"minus": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect height=\"1\" width=\"18\" y=\"9\" x=\"1\"/></svg>",
"more-vertical": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"10\" cy=\"3\" r=\"2\"/><circle cx=\"10\" cy=\"10\" r=\"2\"/><circle cx=\"10\" cy=\"17\" r=\"2\"/></svg>",
"more": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"3\" cy=\"10\" r=\"2\"/><circle cx=\"10\" cy=\"10\" r=\"2\"/><circle cx=\"17\" cy=\"10\" r=\"2\"/></svg>",
"move": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"4,5 1,5 1,9 2,9 2,6 4,6\"/><polygon points=\"1,16 2,16 2,18 4,18 4,19 1,19\"/><polygon points=\"14,16 14,19 11,19 11,18 13,18 13,16\"/><rect fill=\"none\" stroke=\"#000\" x=\"5.5\" y=\"1.5\" width=\"13\" height=\"13\"/><rect x=\"1\" y=\"11\" width=\"1\" height=\"3\"/><rect x=\"6\" y=\"18\" width=\"3\" height=\"1\"/></svg>",
"nut": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon fill=\"none\" stroke=\"#000\" points=\"2.5,5.7 10,1.3 17.5,5.7 17.5,14.3 10,18.7 2.5,14.3\"/><circle fill=\"none\" stroke=\"#000\" cx=\"10\" cy=\"10\" r=\"3.5\"/></svg>",
"pagekit": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"3,1 17,1 17,16 10,16 10,13 14,13 14,4 6,4 6,16 10,16 10,19 3,19\"/></svg>",
"paint-bucket": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10.21,1 L0,11.21 L8.1,19.31 L18.31,9.1 L10.21,1 L10.21,1 Z M16.89,9.1 L15,11 L1.7,11 L10.21,2.42 L16.89,9.1 Z\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M6.42,2.33 L11.7,7.61\"/><path d=\"M18.49,12 C18.49,12 20,14.06 20,15.36 C20,16.28 19.24,17 18.49,17 L18.49,17 C17.74,17 17,16.28 17,15.36 C17,14.06 18.49,12 18.49,12 L18.49,12 Z\"/></svg>",
"pencil": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M17.25,6.01 L7.12,16.1 L3.82,17.2 L5.02,13.9 L15.12,3.88 C15.71,3.29 16.66,3.29 17.25,3.88 C17.83,4.47 17.83,5.42 17.25,6.01 L17.25,6.01 Z\"/><path fill=\"none\" stroke=\"#000\" d=\"M15.98,7.268 L13.851,5.148\"/></svg>",
"phone-landscape": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M17,5.5 C17.8,5.5 18.5,6.2 18.5,7 L18.5,14 C18.5,14.8 17.8,15.5 17,15.5 L3,15.5 C2.2,15.5 1.5,14.8 1.5,14 L1.5,7 C1.5,6.2 2.2,5.5 3,5.5 L17,5.5 L17,5.5 L17,5.5 Z\"/><circle cx=\"3.8\" cy=\"10.5\" r=\".8\"/></svg>",
"phone": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M15.5,17 C15.5,17.8 14.8,18.5 14,18.5 L7,18.5 C6.2,18.5 5.5,17.8 5.5,17 L5.5,3 C5.5,2.2 6.2,1.5 7,1.5 L14,1.5 C14.8,1.5 15.5,2.2 15.5,3 L15.5,17 L15.5,17 L15.5,17 Z\"/><circle cx=\"10.5\" cy=\"16.5\" r=\".8\"/></svg>",
"pinterest": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10.21,1 C5.5,1 3,4.16 3,7.61 C3,9.21 3.85,11.2 5.22,11.84 C5.43,11.94 5.54,11.89 5.58,11.69 C5.62,11.54 5.8,10.8 5.88,10.45 C5.91,10.34 5.89,10.24 5.8,10.14 C5.36,9.59 5,8.58 5,7.65 C5,5.24 6.82,2.91 9.93,2.91 C12.61,2.91 14.49,4.74 14.49,7.35 C14.49,10.3 13,12.35 11.06,12.35 C9.99,12.35 9.19,11.47 9.44,10.38 C9.75,9.08 10.35,7.68 10.35,6.75 C10.35,5.91 9.9,5.21 8.97,5.21 C7.87,5.21 6.99,6.34 6.99,7.86 C6.99,8.83 7.32,9.48 7.32,9.48 C7.32,9.48 6.24,14.06 6.04,14.91 C5.7,16.35 6.08,18.7 6.12,18.9 C6.14,19.01 6.26,19.05 6.33,18.95 C6.44,18.81 7.74,16.85 8.11,15.44 C8.24,14.93 8.79,12.84 8.79,12.84 C9.15,13.52 10.19,14.09 11.29,14.09 C14.58,14.09 16.96,11.06 16.96,7.3 C16.94,3.7 14,1 10.21,1\"/></svg>",
"play-circle": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" points=\"8.5 7 13.5 10 8.5 13\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10\" cy=\"10\" r=\"9\"/></svg>",
"play": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon fill=\"none\" stroke=\"#000\" points=\"6.5,5 14.5,10 6.5,15\"/></svg>",
"plus-circle": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"9.5\" cy=\"9.5\" r=\"9\"/><line fill=\"none\" stroke=\"#000\" x1=\"9.5\" y1=\"5\" x2=\"9.5\" y2=\"14\"/><line fill=\"none\" stroke=\"#000\" x1=\"5\" y1=\"9.5\" x2=\"14\" y2=\"9.5\"/></svg>",
"plus": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"9\" y=\"1\" width=\"1\" height=\"17\"/><rect x=\"1\" y=\"9\" width=\"17\" height=\"1\"/></svg>",
"print": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"4.5 13.5 1.5 13.5 1.5 6.5 18.5 6.5 18.5 13.5 15.5 13.5\"/><polyline fill=\"none\" stroke=\"#000\" points=\"15.5 6.5 15.5 2.5 4.5 2.5 4.5 6.5\"/><rect fill=\"none\" stroke=\"#000\" width=\"11\" height=\"6\" x=\"4.5\" y=\"11.5\"/><rect width=\"8\" height=\"1\" x=\"6\" y=\"13\"/><rect width=\"8\" height=\"1\" x=\"6\" y=\"15\"/></svg>",
"pull": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"6.85,8 9.5,10.6 12.15,8 12.85,8.7 9.5,12 6.15,8.7\"/><line fill=\"none\" stroke=\"#000\" x1=\"9.5\" y1=\"11\" x2=\"9.5\" y2=\"2\"/><polyline fill=\"none\" stroke=\"#000\" points=\"6,5.5 3.5,5.5 3.5,18.5 15.5,18.5 15.5,5.5 13,5.5\"/></svg>",
"push": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"12.15,4 9.5,1.4 6.85,4 6.15,3.3 9.5,0 12.85,3.3\"/><line fill=\"none\" stroke=\"#000\" x1=\"9.5\" y1=\"10\" x2=\"9.5\" y2=\"1\"/><polyline fill=\"none\" stroke=\"#000\" points=\"6 5.5 3.5 5.5 3.5 18.5 15.5 18.5 15.5 5.5 13 5.5\"/></svg>",
"question": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10\" cy=\"10\" r=\"9\"/><circle cx=\"10.44\" cy=\"14.42\" r=\"1.05\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.2\" d=\"M8.17,7.79 C8.17,4.75 12.72,4.73 12.72,7.72 C12.72,8.67 11.81,9.15 11.23,9.75 C10.75,10.24 10.51,10.73 10.45,11.4 C10.44,11.53 10.43,11.64 10.43,11.75\"/></svg>",
"quote-right": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.27,7.79 C17.27,9.45 16.97,10.43 15.99,12.02 C14.98,13.64 13,15.23 11.56,15.97 L11.1,15.08 C12.34,14.2 13.14,13.51 14.02,11.82 C14.27,11.34 14.41,10.92 14.49,10.54 C14.3,10.58 14.09,10.6 13.88,10.6 C12.06,10.6 10.59,9.12 10.59,7.3 C10.59,5.48 12.06,4 13.88,4 C15.39,4 16.67,5.02 17.05,6.42 C17.19,6.82 17.27,7.27 17.27,7.79 L17.27,7.79 Z\"/><path d=\"M8.68,7.79 C8.68,9.45 8.38,10.43 7.4,12.02 C6.39,13.64 4.41,15.23 2.97,15.97 L2.51,15.08 C3.75,14.2 4.55,13.51 5.43,11.82 C5.68,11.34 5.82,10.92 5.9,10.54 C5.71,10.58 5.5,10.6 5.29,10.6 C3.47,10.6 2,9.12 2,7.3 C2,5.48 3.47,4 5.29,4 C6.8,4 8.08,5.02 8.46,6.42 C8.6,6.82 8.68,7.27 8.68,7.79 L8.68,7.79 Z\"/></svg>",
"receiver": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.01\" d=\"M6.189,13.611C8.134,15.525 11.097,18.239 13.867,18.257C16.47,18.275 18.2,16.241 18.2,16.241L14.509,12.551L11.539,13.639L6.189,8.29L7.313,5.355L3.76,1.8C3.76,1.8 1.732,3.537 1.7,6.092C1.667,8.809 4.347,11.738 6.189,13.611\"/></svg>",
"reddit": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19 9.05a2.56 2.56 0 0 0-2.56-2.56 2.59 2.59 0 0 0-1.88.82 10.63 10.63 0 0 0-4.14-1v-.08c.58-1.62 1.58-3.89 2.7-4.1.38-.08.77.12 1.19.57a1.15 1.15 0 0 0-.06.37 1.48 1.48 0 1 0 1.51-1.45 1.43 1.43 0 0 0-.76.19A2.29 2.29 0 0 0 12.91 1c-2.11.43-3.39 4.38-3.63 5.19 0 0 0 .11-.06.11a10.65 10.65 0 0 0-3.75 1A2.56 2.56 0 0 0 1 9.05a2.42 2.42 0 0 0 .72 1.76A5.18 5.18 0 0 0 1.24 13c0 3.66 3.92 6.64 8.73 6.64s8.74-3 8.74-6.64a5.23 5.23 0 0 0-.46-2.13A2.58 2.58 0 0 0 19 9.05zm-16.88 0a1.44 1.44 0 0 1 2.27-1.19 7.68 7.68 0 0 0-2.07 1.91 1.33 1.33 0 0 1-.2-.72zM10 18.4c-4.17 0-7.55-2.4-7.55-5.4S5.83 7.53 10 7.53 17.5 10 17.5 13s-3.38 5.4-7.5 5.4zm7.69-8.61a7.62 7.62 0 0 0-2.09-1.91 1.41 1.41 0 0 1 .84-.28 1.47 1.47 0 0 1 1.44 1.45 1.34 1.34 0 0 1-.21.72z\"/><path d=\"M6.69 12.58a1.39 1.39 0 1 1 1.39-1.39 1.38 1.38 0 0 1-1.38 1.39z\"/><path d=\"M14.26 11.2a1.39 1.39 0 1 1-1.39-1.39 1.39 1.39 0 0 1 1.39 1.39z\"/><path d=\"M13.09 14.88a.54.54 0 0 1-.09.77 5.3 5.3 0 0 1-3.26 1.19 5.61 5.61 0 0 1-3.4-1.22.55.55 0 1 1 .73-.83 4.09 4.09 0 0 0 5.25 0 .56.56 0 0 1 .77.09z\"/></svg>",
"refresh": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M17.08,11.15 C17.09,11.31 17.1,11.47 17.1,11.64 C17.1,15.53 13.94,18.69 10.05,18.69 C6.16,18.68 3,15.53 3,11.63 C3,7.74 6.16,4.58 10.05,4.58 C10.9,4.58 11.71,4.73 12.46,5\"/><polyline fill=\"none\" stroke=\"#000\" points=\"9.9 2 12.79 4.89 9.79 7.9\"/></svg>",
"reply": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.7,13.11 C16.12,10.02 13.84,7.85 11.02,6.61 C10.57,6.41 9.75,6.13 9,5.91 L9,2 L1,9 L9,16 L9,12.13 C10.78,12.47 12.5,13.19 14.09,14.25 C17.13,16.28 18.56,18.54 18.56,18.54 C18.56,18.54 18.81,15.28 17.7,13.11 L17.7,13.11 Z M14.82,13.53 C13.17,12.4 11.01,11.4 8,10.92 L8,13.63 L2.55,9 L8,4.25 L8,6.8 C8.3,6.86 9.16,7.02 10.37,7.49 C13.3,8.65 15.54,10.96 16.65,13.08 C16.97,13.7 17.48,14.86 17.68,16 C16.87,15.05 15.73,14.15 14.82,13.53 L14.82,13.53 Z\"/></svg>",
"rss": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"3.12\" cy=\"16.8\" r=\"1.85\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M1.5,8.2 C1.78,8.18 2.06,8.16 2.35,8.16 C7.57,8.16 11.81,12.37 11.81,17.57 C11.81,17.89 11.79,18.19 11.76,18.5\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M1.5,2.52 C1.78,2.51 2.06,2.5 2.35,2.5 C10.72,2.5 17.5,9.24 17.5,17.57 C17.5,17.89 17.49,18.19 17.47,18.5\"/></svg>",
"search": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"9\" cy=\"9\" r=\"7\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M14,14 L18,18 L14,14 Z\"/></svg>",
"server": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"3\" y=\"3\" width=\"1\" height=\"2\"/><rect x=\"5\" y=\"3\" width=\"1\" height=\"2\"/><rect x=\"7\" y=\"3\" width=\"1\" height=\"2\"/><rect x=\"16\" y=\"3\" width=\"1\" height=\"1\"/><rect x=\"16\" y=\"10\" width=\"1\" height=\"1\"/><circle fill=\"none\" stroke=\"#000\" cx=\"9.9\" cy=\"17.4\" r=\"1.4\"/><rect x=\"3\" y=\"10\" width=\"1\" height=\"2\"/><rect x=\"5\" y=\"10\" width=\"1\" height=\"2\"/><rect x=\"9.5\" y=\"14\" width=\"1\" height=\"2\"/><rect x=\"3\" y=\"17\" width=\"6\" height=\"1\"/><rect x=\"11\" y=\"17\" width=\"6\" height=\"1\"/><rect fill=\"none\" stroke=\"#000\" x=\"1.5\" y=\"1.5\" width=\"17\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"1.5\" y=\"8.5\" width=\"17\" height=\"5\"/></svg>",
"settings": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><ellipse fill=\"none\" stroke=\"#000\" cx=\"6.11\" cy=\"3.55\" rx=\"2.11\" ry=\"2.15\"/><ellipse fill=\"none\" stroke=\"#000\" cx=\"6.11\" cy=\"15.55\" rx=\"2.11\" ry=\"2.15\"/><circle fill=\"none\" stroke=\"#000\" cx=\"13.15\" cy=\"9.55\" r=\"2.15\"/><rect x=\"1\" y=\"3\" width=\"3\" height=\"1\"/><rect x=\"10\" y=\"3\" width=\"8\" height=\"1\"/><rect x=\"1\" y=\"9\" width=\"8\" height=\"1\"/><rect x=\"15\" y=\"9\" width=\"3\" height=\"1\"/><rect x=\"1\" y=\"15\" width=\"3\" height=\"1\"/><rect x=\"10\" y=\"15\" width=\"8\" height=\"1\"/></svg>",
"shrink": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"11 4 12 4 12 8 16 8 16 9 11 9\"/><polygon points=\"4 11 9 11 9 16 8 16 8 12 4 12\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M12,8 L18,2\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M2,18 L8,12\"/></svg>",
"sign-in": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"7 2 17 2 17 17 7 17 7 16 16 16 16 3 7 3\"/><polygon points=\"9.1 13.4 8.5 12.8 11.28 10 4 10 4 9 11.28 9 8.5 6.2 9.1 5.62 13 9.5\"/></svg>",
"sign-out": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"13.1 13.4 12.5 12.8 15.28 10 8 10 8 9 15.28 9 12.5 6.2 13.1 5.62 17 9.5\"/><polygon points=\"13 2 3 2 3 17 13 17 13 16 4 16 4 3 13 3\"/></svg>",
"social": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" x1=\"13.4\" y1=\"14\" x2=\"6.3\" y2=\"10.7\"/><line fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" x1=\"13.5\" y1=\"5.5\" x2=\"6.5\" y2=\"8.8\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"15.5\" cy=\"4.6\" r=\"2.3\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"15.5\" cy=\"14.8\" r=\"2.3\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"4.5\" cy=\"9.8\" r=\"2.3\"/></svg>",
"soundcloud": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.2,9.4c-0.4,0-0.8,0.1-1.101,0.2c-0.199-2.5-2.399-4.5-5-4.5c-0.6,0-1.2,0.1-1.7,0.3C9.2,5.5,9.1,5.6,9.1,5.6V15h8 c1.601,0,2.801-1.2,2.801-2.8C20,10.7,18.7,9.4,17.2,9.4L17.2,9.4z\"/><rect x=\"6\" y=\"6.5\" width=\"1.5\" height=\"8.5\"/><rect x=\"3\" y=\"8\" width=\"1.5\" height=\"7\"/><rect y=\"10\" width=\"1.5\" height=\"5\"/></svg>",
"star": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon fill=\"none\" stroke=\"#000\" stroke-width=\"1.01\" points=\"10 2 12.63 7.27 18.5 8.12 14.25 12.22 15.25 18 10 15.27 4.75 18 5.75 12.22 1.5 8.12 7.37 7.27\"/></svg>",
"strikethrough": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6,13.02 L6.65,13.02 C7.64,15.16 8.86,16.12 10.41,16.12 C12.22,16.12 12.92,14.93 12.92,13.89 C12.92,12.55 11.99,12.03 9.74,11.23 C8.05,10.64 6.23,10.11 6.23,7.83 C6.23,5.5 8.09,4.09 10.4,4.09 C11.44,4.09 12.13,4.31 12.72,4.54 L13.33,4 L13.81,4 L13.81,7.59 L13.16,7.59 C12.55,5.88 11.52,4.89 10.07,4.89 C8.84,4.89 7.89,5.69 7.89,7.03 C7.89,8.29 8.89,8.78 10.88,9.45 C12.57,10.03 14.38,10.6 14.38,12.91 C14.38,14.75 13.27,16.93 10.18,16.93 C9.18,16.93 8.17,16.69 7.46,16.39 L6.52,17 L6,17 L6,13.02 L6,13.02 Z\"/><rect x=\"3\" y=\"10\" width=\"15\" height=\"1\"/></svg>",
"table": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"1\" y=\"3\" width=\"18\" height=\"1\"/><rect x=\"1\" y=\"7\" width=\"18\" height=\"1\"/><rect x=\"1\" y=\"11\" width=\"18\" height=\"1\"/><rect x=\"1\" y=\"15\" width=\"18\" height=\"1\"/></svg>",
"tablet-landscape": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M1.5,5 C1.5,4.2 2.2,3.5 3,3.5 L17,3.5 C17.8,3.5 18.5,4.2 18.5,5 L18.5,16 C18.5,16.8 17.8,17.5 17,17.5 L3,17.5 C2.2,17.5 1.5,16.8 1.5,16 L1.5,5 L1.5,5 L1.5,5 Z\"/><circle cx=\"3.7\" cy=\"10.5\" r=\".8\"/></svg>",
"tablet": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M5,18.5 C4.2,18.5 3.5,17.8 3.5,17 L3.5,3 C3.5,2.2 4.2,1.5 5,1.5 L16,1.5 C16.8,1.5 17.5,2.2 17.5,3 L17.5,17 C17.5,17.8 16.8,18.5 16,18.5 L5,18.5 L5,18.5 L5,18.5 Z\"/><circle cx=\"10.5\" cy=\"16.3\" r=\".8\"/></svg>",
"tag": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M17.5,3.71 L17.5,7.72 C17.5,7.96 17.4,8.2 17.21,8.39 L8.39,17.2 C7.99,17.6 7.33,17.6 6.93,17.2 L2.8,13.07 C2.4,12.67 2.4,12.01 2.8,11.61 L11.61,2.8 C11.81,2.6 12.08,2.5 12.34,2.5 L16.19,2.5 C16.52,2.5 16.86,2.63 17.11,2.88 C17.35,3.11 17.48,3.4 17.5,3.71 L17.5,3.71 Z\"/><circle cx=\"14\" cy=\"6\" r=\"1\"/></svg>",
"thumbnails": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"3.5\" width=\"5\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"11.5\" y=\"3.5\" width=\"5\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"11.5\" y=\"11.5\" width=\"5\" height=\"5\"/><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"11.5\" width=\"5\" height=\"5\"/></svg>",
"trash": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"6.5 3 6.5 1.5 13.5 1.5 13.5 3\"/><polyline fill=\"none\" stroke=\"#000\" points=\"4.5 4 4.5 18.5 15.5 18.5 15.5 4\"/><rect x=\"8\" y=\"7\" width=\"1\" height=\"9\"/><rect x=\"11\" y=\"7\" width=\"1\" height=\"9\"/><rect x=\"2\" y=\"3\" width=\"16\" height=\"1\"/></svg>",
"triangle-down": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"5 7 15 7 10 12\"/></svg>",
"triangle-left": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"12 5 7 10 12 15\"/></svg>",
"triangle-right": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"8 5 13 10 8 15\"/></svg>",
"triangle-up": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"5 13 10 8 15 13\"/></svg>",
"tripadvisor": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19.021,7.866C19.256,6.862,20,5.854,20,5.854h-3.346C14.781,4.641,12.504,4,9.98,4C7.363,4,4.999,4.651,3.135,5.876H0\tc0,0,0.738,0.987,0.976,1.988c-0.611,0.837-0.973,1.852-0.973,2.964c0,2.763,2.249,5.009,5.011,5.009\tc1.576,0,2.976-0.737,3.901-1.879l1.063,1.599l1.075-1.615c0.475,0.611,1.1,1.111,1.838,1.451c1.213,0.547,2.574,0.612,3.825,0.15\tc2.589-0.963,3.913-3.852,2.964-6.439c-0.175-0.463-0.4-0.876-0.675-1.238H19.021z M16.38,14.594\tc-1.002,0.371-2.088,0.328-3.06-0.119c-0.688-0.317-1.252-0.817-1.657-1.438c-0.164-0.25-0.313-0.52-0.417-0.811\tc-0.124-0.328-0.186-0.668-0.217-1.014c-0.063-0.689,0.037-1.396,0.339-2.043c0.448-0.971,1.251-1.71,2.25-2.079\tc2.075-0.765,4.375,0.3,5.14,2.366c0.762,2.066-0.301,4.37-2.363,5.134L16.38,14.594L16.38,14.594z M8.322,13.066\tc-0.72,1.059-1.935,1.76-3.309,1.76c-2.207,0-4.001-1.797-4.001-3.996c0-2.203,1.795-4.002,4.001-4.002\tc2.204,0,3.999,1.8,3.999,4.002c0,0.137-0.024,0.261-0.04,0.396c-0.067,0.678-0.284,1.313-0.648,1.853v-0.013H8.322z M2.472,10.775\tc0,1.367,1.112,2.479,2.476,2.479c1.363,0,2.472-1.11,2.472-2.479c0-1.359-1.11-2.468-2.472-2.468\tC3.584,8.306,2.473,9.416,2.472,10.775L2.472,10.775z M12.514,10.775c0,1.367,1.104,2.479,2.471,2.479\tc1.363,0,2.474-1.108,2.474-2.479c0-1.359-1.11-2.468-2.474-2.468c-1.364,0-2.477,1.109-2.477,2.468H12.514z M3.324,10.775\tc0-0.893,0.726-1.618,1.614-1.618c0.889,0,1.625,0.727,1.625,1.618c0,0.898-0.725,1.627-1.625,1.627\tc-0.901,0-1.625-0.729-1.625-1.627H3.324z M13.354,10.775c0-0.893,0.726-1.618,1.627-1.618c0.886,0,1.61,0.727,1.61,1.618\tc0,0.898-0.726,1.627-1.626,1.627s-1.625-0.729-1.625-1.627H13.354z M9.977,4.875c1.798,0,3.425,0.324,4.849,0.968\tc-0.535,0.015-1.061,0.108-1.586,0.3c-1.264,0.463-2.264,1.388-2.815,2.604c-0.262,0.551-0.398,1.133-0.448,1.72\tC9.79,7.905,7.677,5.873,5.076,5.82C6.501,5.208,8.153,4.875,9.94,4.875H9.977z\"/></svg>",
"tumblr": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6.885,8.598c0,0,0,3.393,0,4.996c0,0.282,0,0.66,0.094,0.942c0.377,1.509,1.131,2.545,2.545,3.11 c1.319,0.472,2.356,0.472,3.676,0c0.565-0.188,1.132-0.659,1.132-0.659l-0.849-2.263c0,0-1.036,0.378-1.603,0.283 c-0.565-0.094-1.226-0.66-1.226-1.508c0-1.603,0-4.902,0-4.902h2.828V5.771h-2.828V2H8.205c0,0-0.094,0.66-0.188,0.942 C7.828,3.791,7.262,4.733,6.603,5.394C5.848,6.147,5,6.43,5,6.43v2.168H6.885z\"/></svg>",
"tv": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect x=\"7\" y=\"16\" width=\"6\" height=\"1\"/><rect fill=\"none\" stroke=\"#000\" x=\".5\" y=\"3.5\" width=\"19\" height=\"11\"/></svg>",
"twitter": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19,4.74 C18.339,5.029 17.626,5.229 16.881,5.32 C17.644,4.86 18.227,4.139 18.503,3.28 C17.79,3.7 17.001,4.009 16.159,4.17 C15.485,3.45 14.526,3 13.464,3 C11.423,3 9.771,4.66 9.771,6.7 C9.771,6.99 9.804,7.269 9.868,7.539 C6.795,7.38 4.076,5.919 2.254,3.679 C1.936,4.219 1.754,4.86 1.754,5.539 C1.754,6.82 2.405,7.95 3.397,8.61 C2.79,8.589 2.22,8.429 1.723,8.149 L1.723,8.189 C1.723,9.978 2.997,11.478 4.686,11.82 C4.376,11.899 4.049,11.939 3.713,11.939 C3.475,11.939 3.245,11.919 3.018,11.88 C3.49,13.349 4.852,14.419 6.469,14.449 C5.205,15.429 3.612,16.019 1.882,16.019 C1.583,16.019 1.29,16.009 1,15.969 C2.635,17.019 4.576,17.629 6.662,17.629 C13.454,17.629 17.17,12 17.17,7.129 C17.17,6.969 17.166,6.809 17.157,6.649 C17.879,6.129 18.504,5.478 19,4.74\"/></svg>",
"uikit": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon points=\"14.4,3.1 11.3,5.1 15,7.3 15,12.9 10,15.7 5,12.9 5,8.5 2,6.8 2,14.8 9.9,19.5 18,14.8 18,5.3\"/><polygon points=\"9.8,4.2 6.7,2.4 9.8,0.4 12.9,2.3\"/></svg>",
"unlock": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><rect fill=\"none\" stroke=\"#000\" x=\"3.5\" y=\"8.5\" width=\"13\" height=\"10\"/><path fill=\"none\" stroke=\"#000\" d=\"M6.5,8.5 L6.5,4.9 C6.5,3 8.1,1.5 10,1.5 C11.9,1.5 13.5,3 13.5,4.9\"/></svg>",
"upload": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polyline fill=\"none\" stroke=\"#000\" points=\"5 8 9.5 3.5 14 8\"/><rect x=\"3\" y=\"17\" width=\"13\" height=\"1\"/><line fill=\"none\" stroke=\"#000\" x1=\"9.5\" y1=\"15\" x2=\"9.5\" y2=\"4\"/></svg>",
"user": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"9.9\" cy=\"6.4\" r=\"4.4\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M1.5,19 C2.3,14.5 5.8,11.2 10,11.2 C14.2,11.2 17.7,14.6 18.5,19.2\"/></svg>",
"users": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"7.7\" cy=\"8.6\" r=\"3.5\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M1,18.1 C1.7,14.6 4.4,12.1 7.6,12.1 C10.9,12.1 13.7,14.8 14.3,18.3\"/><path fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" d=\"M11.4,4 C12.8,2.4 15.4,2.8 16.3,4.7 C17.2,6.6 15.7,8.9 13.6,8.9 C16.5,8.9 18.8,11.3 19.2,14.1\"/></svg>",
"video-camera": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><polygon fill=\"none\" stroke=\"#000\" points=\"17.5 6.9 17.5 13.1 13.5 10.4 13.5 14.5 2.5 14.5 2.5 5.5 13.5 5.5 13.5 9.6 17.5 6.9\"/></svg>",
"vimeo": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M2.065,7.59C1.84,7.367,1.654,7.082,1.468,6.838c-0.332-0.42-0.137-0.411,0.274-0.772c1.026-0.91,2.004-1.896,3.127-2.688 c1.017-0.713,2.365-1.173,3.286-0.039c0.849,1.045,0.869,2.629,1.084,3.891c0.215,1.309,0.421,2.648,0.88,3.901 c0.127,0.352,0.37,1.018,0.81,1.074c0.567,0.078,1.145-0.917,1.408-1.289c0.684-0.987,1.611-2.317,1.494-3.587 c-0.115-1.349-1.572-1.095-2.482-0.773c0.146-1.514,1.555-3.216,2.912-3.792c1.439-0.597,3.579-0.587,4.302,1.036 c0.772,1.759,0.078,3.802-0.763,5.396c-0.918,1.731-2.1,3.333-3.363,4.829c-1.114,1.329-2.432,2.787-4.093,3.422 c-1.897,0.723-3.021-0.686-3.667-2.318c-0.705-1.777-1.056-3.771-1.565-5.621C4.898,8.726,4.644,7.836,4.136,7.191 C3.473,6.358,2.72,7.141,2.065,7.59C1.977,7.502,2.115,7.551,2.065,7.59L2.065,7.59z\"/></svg>",
"warning": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"10\" cy=\"14\" r=\"1\"/><circle fill=\"none\" stroke=\"#000\" stroke-width=\"1.1\" cx=\"10\" cy=\"10\" r=\"9\"/><path d=\"M10.97,7.72 C10.85,9.54 10.56,11.29 10.56,11.29 C10.51,11.87 10.27,12 9.99,12 C9.69,12 9.49,11.87 9.43,11.29 C9.43,11.29 9.16,9.54 9.03,7.72 C8.96,6.54 9.03,6 9.03,6 C9.03,5.45 9.46,5.02 9.99,5 C10.53,5.01 10.97,5.44 10.97,6 C10.97,6 11.04,6.54 10.97,7.72 L10.97,7.72 Z\"/></svg>",
"whatsapp": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M16.7,3.3c-1.8-1.8-4.1-2.8-6.7-2.8c-5.2,0-9.4,4.2-9.4,9.4c0,1.7,0.4,3.3,1.3,4.7l-1.3,4.9l5-1.3c1.4,0.8,2.9,1.2,4.5,1.2 l0,0l0,0c5.2,0,9.4-4.2,9.4-9.4C19.5,7.4,18.5,5,16.7,3.3 M10.1,17.7L10.1,17.7c-1.4,0-2.8-0.4-4-1.1l-0.3-0.2l-3,0.8l0.8-2.9 l-0.2-0.3c-0.8-1.2-1.2-2.7-1.2-4.2c0-4.3,3.5-7.8,7.8-7.8c2.1,0,4.1,0.8,5.5,2.3c1.5,1.5,2.3,3.4,2.3,5.5 C17.9,14.2,14.4,17.7,10.1,17.7 M14.4,11.9c-0.2-0.1-1.4-0.7-1.6-0.8c-0.2-0.1-0.4-0.1-0.5,0.1c-0.2,0.2-0.6,0.8-0.8,0.9 c-0.1,0.2-0.3,0.2-0.5,0.1c-0.2-0.1-1-0.4-1.9-1.2c-0.7-0.6-1.2-1.4-1.3-1.6c-0.1-0.2,0-0.4,0.1-0.5C8,8.8,8.1,8.7,8.2,8.5 c0.1-0.1,0.2-0.2,0.2-0.4c0.1-0.2,0-0.3,0-0.4C8.4,7.6,7.9,6.5,7.7,6C7.5,5.5,7.3,5.6,7.2,5.6c-0.1,0-0.3,0-0.4,0 c-0.2,0-0.4,0.1-0.6,0.3c-0.2,0.2-0.8,0.8-0.8,2c0,1.2,0.8,2.3,1,2.4c0.1,0.2,1.7,2.5,4,3.5c0.6,0.2,1,0.4,1.3,0.5 c0.6,0.2,1.1,0.2,1.5,0.1c0.5-0.1,1.4-0.6,1.6-1.1c0.2-0.5,0.2-1,0.1-1.1C14.8,12.1,14.6,12,14.4,11.9\"/></svg>",
"wordpress": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M10,0.5c-5.2,0-9.5,4.3-9.5,9.5s4.3,9.5,9.5,9.5c5.2,0,9.5-4.3,9.5-9.5S15.2,0.5,10,0.5L10,0.5L10,0.5z M15.6,3.9h-0.1 c-0.8,0-1.4,0.7-1.4,1.5c0,0.7,0.4,1.3,0.8,1.9c0.3,0.6,0.7,1.3,0.7,2.3c0,0.7-0.3,1.5-0.6,2.7L14.1,15l-3-8.9 c0.5,0,0.9-0.1,0.9-0.1C12.5,6,12.5,5.3,12,5.4c0,0-1.3,0.1-2.2,0.1C9,5.5,7.7,5.4,7.7,5.4C7.2,5.3,7.2,6,7.6,6c0,0,0.4,0.1,0.9,0.1 l1.3,3.5L8,15L5,6.1C5.5,6.1,5.9,6,5.9,6C6.4,6,6.3,5.3,5.9,5.4c0,0-1.3,0.1-2.2,0.1c-0.2,0-0.3,0-0.5,0c1.5-2.2,4-3.7,6.9-3.7 C12.2,1.7,14.1,2.6,15.6,3.9L15.6,3.9L15.6,3.9z M2.5,6.6l3.9,10.8c-2.7-1.3-4.6-4.2-4.6-7.4C1.8,8.8,2,7.6,2.5,6.6L2.5,6.6L2.5,6.6 z M10.2,10.7l2.5,6.9c0,0,0,0.1,0.1,0.1C11.9,18,11,18.2,10,18.2c-0.8,0-1.6-0.1-2.3-0.3L10.2,10.7L10.2,10.7L10.2,10.7z M14.2,17.1 l2.5-7.3c0.5-1.2,0.6-2.1,0.6-2.9c0-0.3,0-0.6-0.1-0.8c0.6,1.2,1,2.5,1,4C18.3,13,16.6,15.7,14.2,17.1L14.2,17.1L14.2,17.1z\"/></svg>",
"world": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"none\" stroke=\"#000\" d=\"M1,10.5 L19,10.5\"/><path fill=\"none\" stroke=\"#000\" d=\"M2.35,15.5 L17.65,15.5\"/><path fill=\"none\" stroke=\"#000\" d=\"M2.35,5.5 L17.523,5.5\"/><path fill=\"none\" stroke=\"#000\" d=\"M10,19.46 L9.98,19.46 C7.31,17.33 5.61,14.141 5.61,10.58 C5.61,7.02 7.33,3.83 10,1.7 C10.01,1.7 9.99,1.7 10,1.7 L10,1.7 C12.67,3.83 14.4,7.02 14.4,10.58 C14.4,14.141 12.67,17.33 10,19.46 L10,19.46 L10,19.46 L10,19.46 Z\"/><circle fill=\"none\" stroke=\"#000\" cx=\"10\" cy=\"10.5\" r=\"9\"/></svg>",
"xing": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M4.4,4.56 C4.24,4.56 4.11,4.61 4.05,4.72 C3.98,4.83 3.99,4.97 4.07,5.12 L5.82,8.16 L5.82,8.17 L3.06,13.04 C2.99,13.18 2.99,13.33 3.06,13.44 C3.12,13.55 3.24,13.62 3.4,13.62 L6,13.62 C6.39,13.62 6.57,13.36 6.71,13.12 C6.71,13.12 9.41,8.35 9.51,8.16 C9.49,8.14 7.72,5.04 7.72,5.04 C7.58,4.81 7.39,4.56 6.99,4.56 L4.4,4.56 L4.4,4.56 Z\"/><path d=\"M15.3,1 C14.91,1 14.74,1.25 14.6,1.5 C14.6,1.5 9.01,11.42 8.82,11.74 C8.83,11.76 12.51,18.51 12.51,18.51 C12.64,18.74 12.84,19 13.23,19 L15.82,19 C15.98,19 16.1,18.94 16.16,18.83 C16.23,18.72 16.23,18.57 16.16,18.43 L12.5,11.74 L12.5,11.72 L18.25,1.56 C18.32,1.42 18.32,1.27 18.25,1.16 C18.21,1.06 18.08,1 17.93,1 L15.3,1 L15.3,1 Z\"/></svg>",
"yelp": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.175,14.971c-0.112,0.77-1.686,2.767-2.406,3.054c-0.246,0.1-0.487,0.076-0.675-0.069\tc-0.122-0.096-2.446-3.859-2.446-3.859c-0.194-0.293-0.157-0.682,0.083-0.978c0.234-0.284,0.581-0.393,0.881-0.276\tc0.016,0.01,4.21,1.394,4.332,1.482c0.178,0.148,0.263,0.379,0.225,0.646L17.175,14.971L17.175,14.971z M11.464,10.789\tc-0.203-0.307-0.199-0.666,0.009-0.916c0,0,2.625-3.574,2.745-3.657c0.203-0.135,0.452-0.141,0.69-0.025\tc0.691,0.335,2.085,2.405,2.167,3.199v0.027c0.024,0.271-0.082,0.491-0.273,0.623c-0.132,0.083-4.43,1.155-4.43,1.155\tc-0.322,0.096-0.68-0.06-0.882-0.381L11.464,10.789z M9.475,9.563C9.32,9.609,8.848,9.757,8.269,8.817c0,0-3.916-6.16-4.007-6.351\tc-0.057-0.212,0.011-0.455,0.202-0.65C5.047,1.211,8.21,0.327,9.037,0.529c0.27,0.069,0.457,0.238,0.522,0.479\tc0.047,0.266,0.433,5.982,0.488,7.264C10.098,9.368,9.629,9.517,9.475,9.563z M9.927,19.066c-0.083,0.225-0.273,0.373-0.54,0.421\tc-0.762,0.13-3.15-0.751-3.647-1.342c-0.096-0.131-0.155-0.262-0.167-0.394c-0.011-0.095,0-0.189,0.036-0.272\tc0.061-0.155,2.917-3.538,2.917-3.538c0.214-0.272,0.595-0.355,0.952-0.213c0.345,0.13,0.56,0.428,0.536,0.749\tC10.014,14.479,9.977,18.923,9.927,19.066z M3.495,13.912c-0.235-0.009-0.444-0.148-0.568-0.382c-0.089-0.17-0.151-0.453-0.19-0.794\tC2.63,11.701,2.761,10.144,3.07,9.648c0.145-0.226,0.357-0.345,0.592-0.336c0.154,0,4.255,1.667,4.255,1.667\tc0.321,0.118,0.521,0.453,0.5,0.833c-0.023,0.37-0.236,0.655-0.551,0.738L3.495,13.912z\"/></svg>",
"youtube": "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15,4.1c1,0.1,2.3,0,3,0.8c0.8,0.8,0.9,2.1,0.9,3.1C19,9.2,19,10.9,19,12c-0.1,1.1,0,2.4-0.5,3.4c-0.5,1.1-1.4,1.5-2.5,1.6 c-1.2,0.1-8.6,0.1-11,0c-1.1-0.1-2.4-0.1-3.2-1c-0.7-0.8-0.7-2-0.8-3C1,11.8,1,10.1,1,8.9c0-1.1,0-2.4,0.5-3.4C2,4.5,3,4.3,4.1,4.2 C5.3,4.1,12.6,4,15,4.1z M8,7.5v6l5.5-3L8,7.5z\"/></svg>"
});
}
if (typeof window !== 'undefined' && window.UIkit) {
window.UIkit.use(plugin);
}
return plugin;
})));
-3
View File
File diff suppressed because one or more lines are too long
-12130
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
-3
View File
File diff suppressed because one or more lines are too long
-19
View File
@@ -1,19 +0,0 @@
{
"version": "1.0.0-alpha.4.app.116",
"notes": "VTracer 1.0.0-alpha.4 - Build 116 (543204e5)",
"pub_date": "2026-08-29T21:18:11.665Z",
"platforms": {
"macos-universal": {
"url": "https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_universal.app.tar.gz",
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVSUENOK1VhM1NxTVlmbXNvOGVkb2l0cVRxeFArUE1saFUwRmRIZFFsRXJtN0IyZGs3M29EejV1M2t6SHcyTXo5c050aStaWlVFbkVwMGtVK0JPb1gvRE1nSHdmaTJqSFFvPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzg4MDM4MjAxCWZpbGU6VlRyYWNlci5hcHAudGFyLmd6ClBrSGF1RE5ITFdxUnNTcGFUeC9kKzBIR3U4TzBmRklWMWdibU5uL25oRmhzd2RkaTJrV1VxcEo5dXA1SnBIRnFReUFtK2RJZVY3NzZPekF5MXRqSUN3PT0K"
},
"windows-x86_64": {
"url": "https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_x64-setup.exe",
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVSUENOK1VhM1NxTVZTUEhKaHMxU1h2d09lS2xERUJTbmRWVittaHRveGlRUWtsdnY2NkV2YnA4YWFxZWpZbWNsWkRndWttcnJGVDN4dXMyWk1MandjV25JYWxVS1FuelEwPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzg4MDM2NTY2CWZpbGU6VlRyYWNlcl8xLjAuMC1hbHBoYS40LmFwcC4xMTZfeDY0LXNldHVwLmV4ZQp3YS9Xdk5vdUFVbWg2SUw3U3dFdFBSeVU3ZUNVMmd3SFpoejlyZWZHYjdvQjNRVFVoWkRmNjZZM0lQeEYzV2s4d2s4NHQ3Q1c3eTVpOFVYaWgrQjFBZz09Cg=="
},
"linux-x86_64": {
"url": "https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_x64.AppImage",
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVSUENOK1VhM1NxTVVhRjErZk5oVWQvdWRmMndzalNVYWNBQzN0emRVM1kvMWw5KzZjcUFCS0s2TFI4Ymc1Ynl2cWtNcmJDMFBvbU9IT0VYekQzc3VsQUlLdWdHMWFzK2dNPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzg4MDIyMjUzCWZpbGU6VlRyYWNlcl8xLjAuMC1hbHBoYS40LmFwcC4xMTFfYW1kNjQuQXBwSW1hZ2UKT0RzUkx4azJqTmJvN3AvVFlIQUZZakVHTVFUalVWU2prajhvakp6eHRzTHVNZU5OVUV3WEZCWDd3QkY4YStqSDFqb0Qyam5XU1ZrdWVzK2JjUTI1RGc9PQo="
}
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
[package]
name = "vtracer-wasm"
description = "WebAssembly core for the vtracer Node.js package."
version = "1.0.0-alpha.3"
version = "1.0.0-alpha.4"
authors = ["Chris Tsang <tyt2y7@gmail.com>"]
edition = "2024"
license = "MIT OR Apache-2.0"
@@ -15,7 +15,7 @@ repository = "https://github.com/visioncortex/vtracer/"
crate-type = ["cdylib"]
[dependencies]
vtracer = { version = "1.0.0-alpha.3", path = "../crates/vtracer" }
vtracer = { version = "1.0.0-alpha.4", path = "../crates/vtracer" }
wasm-bindgen = "0.2"
serde = { version = "1", features = ["derive"] }
serde-wasm-bindgen = "0.6"
+37 -5
View File
@@ -1,9 +1,40 @@
<div align="center">
<img src="https://raw.githubusercontent.com/visioncortex/vtracer/master/docs/images/visioncortex-banner.png">
<h1>VTracer</h1>
<p>
<strong>Raster to Vector Graphics Converter</strong>
</p>
<h3>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_x64-setup.exe">Windows App</a>
<span> | </span>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_universal.dmg">macOS App</a>
<span> | </span>
<a href="https://github.com/visioncortex/vtracer/releases/download/1.0.0-alpha.4/VTracer_1.0.0-alpha.4_x64.AppImage">Linux App</a>
</h3>
</div>
# vtracer (Node.js)
Raster → vector (SVG) for Node, a WebAssembly build of the
[`vtracer`](https://github.com/visioncortex/vtracer) framework. Image decoding
and vectorization both happen in wasm, so there is **no native dependency**
just `npm install`.
Raster → vector (SVG) for Node, a WebAssembly build of
[`vtracer`](https://github.com/visioncortex/vtracer). Image decoding and
vectorization both happen in wasm, so there is **no native dependency** just
`npm install`.
## 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, VTracer has an image processing pipeline which can handle colored images. VTracer skips Potrace's expensive optimal-polygon search in favor of a fast, linear pipeline that stays faithful to high-resolution images.
Comparing to Adobe Illustrator's Image Trace, VTracer's output is much more compact 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.
Technical descriptions of the [tracing algorithm](https://www.visioncortex.org/vtracer-docs) and [clustering algorithm](https://www.visioncortex.org/impression-docs).
## Install
@@ -14,6 +45,7 @@ npm install @visioncortex/vtracer
## Usage
```js
const fs = require('fs');
const vtracer = require('@visioncortex/vtracer');
// file in, file out
@@ -44,7 +76,7 @@ for the seam-free mosaic), `mode` (`"pixel" | "polygon" | "spline"`),
simplification tolerance in px, try 12.5), `pathPrecision`, `palette` (list of
`#rrggbb`), `maxColors`, `optimize` (`0 | 1 | 2`), `binaryThreshold` /
`adaptive` / `adaptiveWindow` / `adaptiveT` (binary mode), `watershedDetail`
(0..=255).
(default 128; higher = more regions, uncapped).
## Build from source
+1 -1
View File
@@ -30,7 +30,7 @@ export interface Options {
adaptiveWindow?: number;
/** Adaptive sensitivity: percent below the local mean (default 15). */
adaptiveT?: number;
/** Watershed clustering: hierarchy cut level 0..=255 (higher = more regions, default 128). */
/** Watershed clustering: hierarchy cut level (default 128; higher = more regions, uncapped). */
watershedDetail?: number;
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@visioncortex/vtracer",
"version": "1.0.0-alpha.3",
"version": "1.0.0-alpha.4",
"description": "Raster to vector graphics converter (SVG). WebAssembly build of the vtracer framework — no native dependencies.",
"main": "index.js",
"types": "index.d.ts",
+3 -2
View File
@@ -40,8 +40,9 @@ struct Options {
adaptive_window: Option<u32>,
/// Adaptive sensitivity: percent below the local mean (default 15).
adaptive_t: Option<f64>,
/// Watershed clustering: hierarchy cut level (0..=255).
watershed_detail: Option<u8>,
/// Watershed clustering: hierarchy cut level (default 128; higher = more
/// regions, uncapped).
watershed_detail: Option<u32>,
/// One of "bw" | "poster" | "photo"; applied before the other fields.
preset: Option<String>,
}