From febcc289200ad20f6862149e9925cb0ca233c746 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sun, 2 Aug 2026 02:41:45 +0100 Subject: [PATCH] Improve core lib docs for docs.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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. --- crates/vtracer/src/config.rs | 25 ++++++++- crates/vtracer/src/error.rs | 2 + crates/vtracer/src/frontend.rs | 4 +- crates/vtracer/src/frontend/binary.rs | 7 ++- crates/vtracer/src/lib.rs | 81 +++++++++++++++++++++------ crates/vtracer/src/session.rs | 2 +- 6 files changed, 100 insertions(+), 21 deletions(-) diff --git a/crates/vtracer/src/config.rs b/crates/vtracer/src/config.rs index e4f624e..d576952 100644 --- a/crates/vtracer/src/config.rs +++ b/crates/vtracer/src/config.rs @@ -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, + /// Douglas–Peucker 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, @@ -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, @@ -145,6 +164,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 { diff --git a/crates/vtracer/src/error.rs b/crates/vtracer/src/error.rs index a4f9fa3..061046a 100644 --- a/crates/vtracer/src/error.rs +++ b/crates/vtracer/src/error.rs @@ -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. diff --git a/crates/vtracer/src/frontend.rs b/crates/vtracer/src/frontend.rs index 47a5f35..ef1ad2e 100644 --- a/crates/vtracer/src/frontend.rs +++ b/crates/vtracer/src/frontend.rs @@ -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 Bradley–Roth 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 diff --git a/crates/vtracer/src/frontend/binary.rs b/crates/vtracer/src/frontend/binary.rs index 28e148a..7e5f0ca 100644 --- a/crates/vtracer/src/frontend/binary.rs +++ b/crates/vtracer/src/frontend/binary.rs @@ -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 Bradley–Roth 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, diff --git a/crates/vtracer/src/lib.rs b/crates/vtracer/src/lib.rs index b3980d6..08b7217 100644 --- a/crates/vtracer/src/lib.rs +++ b/crates/vtracer/src/lib.rs @@ -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; diff --git a/crates/vtracer/src/session.rs b/crates/vtracer/src/session.rs index b074973..11c721d 100644 --- a/crates/vtracer/src/session.rs +++ b/crates/vtracer/src/session.rs @@ -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. //!