Skip to content

Commit

Permalink
SVG path string numeric precision
Browse files Browse the repository at this point in the history
  • Loading branch information
bobbyng626 authored and tyt2y3 committed Jul 23, 2021
1 parent 9ce7df1 commit d0593e7
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 17 deletions.
2 changes: 1 addition & 1 deletion cmdapp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ keywords = ["svg", "computer-graphics"]
[dependencies]
clap = "2.33.3"
image = "0.23.10"
visioncortex = "0.4.0"
visioncortex = "0.6.0"
35 changes: 28 additions & 7 deletions cmdapp/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct Config {
pub length_threshold: f64,
pub max_iterations: usize,
pub splice_threshold: i32,
pub path_precision: Option<u32>,
}

pub(crate) struct ConverterConfig {
Expand All @@ -48,6 +49,7 @@ pub(crate) struct ConverterConfig {
pub length_threshold: f64,
pub max_iterations: usize,
pub splice_threshold: f64,
pub path_precision: Option<u32>,
}

impl Default for Config {
Expand All @@ -65,6 +67,7 @@ impl Default for Config {
length_threshold: 4.0,
splice_threshold: 45,
max_iterations: 10,
path_precision: Some(8),
}
}
}
Expand Down Expand Up @@ -194,6 +197,11 @@ impl Config {
.takes_value(true)
.help("Curver fitting mode `pixel`, `polygon`, `spline`"));

let app = app.arg(Arg::with_name("path_precision")
.long("path_precision")
.takes_value(true)
.help("Number of deciaml places to use in path string"));

// Extract matches
let matches = app.get_matches();

Expand Down Expand Up @@ -225,7 +233,7 @@ impl Config {
} else if value == "spline" {
"spline"
} else {
panic!("Parser Error: Curve fitting mode is invalid with value {}", value);
panic!("Parser Error: Curve fitting mode is invalid: {}", value);
});
}

Expand All @@ -237,7 +245,7 @@ impl Config {
}
config.filter_speckle = value;
} else {
panic!("Parser Error: Filter speckle is not a positive integer with value {}.", value);
panic!("Parser Error: Filter speckle is not a positive integer: {}.", value);
}
}

Expand All @@ -249,7 +257,7 @@ impl Config {
}
config.color_precision = value;
} else {
panic!("Parser Error: Color precision is not an integer with value {}.", value);
panic!("Parser Error: Color precision is not an integer: {}.", value);
}
}

Expand All @@ -261,7 +269,7 @@ impl Config {
}
config.layer_difference = value;
} else {
panic!("Parser Error: Gradient step is not an integer with value {}.", value);
panic!("Parser Error: Gradient step is not an integer: {}.", value);
}
}

Expand All @@ -273,7 +281,7 @@ impl Config {
}
config.corner_threshold = value
} else {
panic!("Parser Error: Corner threshold is not numeric with value {}.", value);
panic!("Parser Error: Corner threshold is not numeric: {}.", value);
}
}

Expand All @@ -285,7 +293,7 @@ impl Config {
}
config.length_threshold = value;
} else {
panic!("Parser Error: Segment length is not numeric with value {}.", value);
panic!("Parser Error: Segment length is not numeric: {}.", value);
}
}

Expand All @@ -297,7 +305,16 @@ impl Config {
}
config.splice_threshold = value;
} else {
panic!("Parser Error: Segment length is not numeric with value {}.", value);
panic!("Parser Error: Segment length is not numeric: {}.", value);
}
}

if let Some(value) = matches.value_of("path_precision") {
if value.trim().parse::<u32>().is_ok() { // is numeric
let value = value.trim().parse::<u32>().ok();
config.path_precision = value;
} else {
panic!("Parser Error: Path precision is not an unsigned integer: {}.", value);
}
}

Expand All @@ -321,6 +338,7 @@ impl Config {
length_threshold: 4.0,
max_iterations: 10,
splice_threshold: 45,
path_precision: Some(8),
},
Preset::Poster => Self {
input_path,
Expand All @@ -335,6 +353,7 @@ impl Config {
length_threshold: 4.0,
max_iterations: 10,
splice_threshold: 45,
path_precision: Some(8),
},
Preset::Photo => Self {
input_path,
Expand All @@ -349,6 +368,7 @@ impl Config {
length_threshold: 4.0,
max_iterations: 10,
splice_threshold: 45,
path_precision: Some(8),
}
}
}
Expand All @@ -367,6 +387,7 @@ impl Config {
length_threshold: self.length_threshold,
max_iterations: self.max_iterations,
splice_threshold: deg2rad(self.splice_threshold),
path_precision: self.path_precision,
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions cmdapp/src/converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ fn color_image_to_svg(config: ConverterConfig) -> Result<(), String> {
config.max_iterations,
config.splice_threshold
);
svg.add_path(paths, cluster.residue_color());
svg.add_path(paths, cluster.residue_color(), config.path_precision);
}

write_svg(svg, config.output_path)
Expand Down Expand Up @@ -106,7 +106,7 @@ fn binary_image_to_svg(config: ConverterConfig) -> Result<(), String> {
config.max_iterations,
config.splice_threshold,
);
svg.add_path(paths, Color::color(&ColorName::Black));
svg.add_path(paths, Color::color(&ColorName::Black), config.path_precision);
}
}

Expand Down
6 changes: 4 additions & 2 deletions cmdapp/src/svg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct SvgFile {
pub struct SvgPath {
pub path: CompoundPath,
pub color: Color,
pub path_precision: Option<u32>,
}

impl SvgFile {
Expand All @@ -21,10 +22,11 @@ impl SvgFile {
}
}

pub fn add_path(&mut self, path: CompoundPath, color: Color) {
pub fn add_path(&mut self, path: CompoundPath, color: Color, path_precision: Option<u32>) {
self.paths.push(SvgPath {
path,
color,
path_precision,
})
}
}
Expand All @@ -47,7 +49,7 @@ impl fmt::Display for SvgFile {

impl fmt::Display for SvgPath {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (string, offset) = self.path.to_svg_string(true, PointF64::default());
let (string, offset) = self.path.to_svg_string(true, PointF64::default(), self.path_precision);
writeln!(
f, "<path d=\"{}\" fill=\"{}\" transform=\"translate({},{})\"/>",
string, self.color.to_hex_string(),
Expand Down
2 changes: 1 addition & 1 deletion webapp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ console_log = { version = "0.2", features = ["color"] }
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
visioncortex = "0.4.0"
visioncortex = "0.6.0"

# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
Expand Down
13 changes: 13 additions & 0 deletions webapp/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,19 @@
<input id="splice" type="range" min="0" max="180" step="1" value="45">
</div>

<div style="display: none">
<div class="spline-options">
<div title="Number of decimal places used in svg path string">
Path Precision <span>(More digits)</span>
</div>
</div>
<div id="pathprecisionvalue" class="spline-options">
8
</div>
<div class="spline-options">
<input id="pathprecision" class="uk-range" type="range" min="0" max="16" step="1" value="8">
</div>
</div>
</div>
</div>
<script src="./bootstrap.js"></script>
Expand Down
21 changes: 19 additions & 2 deletions webapp/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ var presetConfigs = [
clustering_hierarchical: 'stacked',
filter_speckle: 4,
color_precision: 6,
path_precision: 8,
layer_difference: 16,
mode: 'spline',
corner_threshold: 60,
Expand All @@ -66,6 +67,7 @@ var presetConfigs = [
clustering_hierarchical: 'stacked',
filter_speckle: 4,
color_precision: 8,
path_precision: 8,
layer_difference: 25,
mode: 'spline',
corner_threshold: 60,
Expand All @@ -77,9 +79,10 @@ var presetConfigs = [
{
src: 'assets/samples/Gum Tree Vector.jpg',
clustering_mode: 'color',
clustering_hierarchical: 'cutout',
clustering_hierarchical: 'stacked',
filter_speckle: 4,
color_precision: 8,
path_precision: 8,
layer_difference: 28,
mode: 'spline',
corner_threshold: 60,
Expand All @@ -94,6 +97,7 @@ var presetConfigs = [
clustering_hierarchical: 'stacked',
filter_speckle: 8,
color_precision: 7,
path_precision: 8,
layer_difference: 64,
mode: 'spline',
corner_threshold: 60,
Expand All @@ -108,6 +112,7 @@ var presetConfigs = [
clustering_hierarchical: 'stacked',
filter_speckle: 10,
color_precision: 8,
path_precision: 8,
layer_difference: 48,
mode: 'spline',
corner_threshold: 180,
Expand All @@ -122,6 +127,7 @@ var presetConfigs = [
clustering_hierarchical: 'stacked',
filter_speckle: 0,
color_precision: 8,
path_precision: 8,
layer_difference: 0,
mode: 'none',
corner_threshold: 180,
Expand Down Expand Up @@ -178,6 +184,9 @@ function loadConfig(config) {
document.getElementById('layerdifferencevalue').innerHTML = globallayerdifference;
document.getElementById('layerdifference').value = globallayerdifference;

globalpathprecision = config.path_precision;
document.getElementById('pathprecisionvalue').innerHTML = globalpathprecision;
document.getElementById('pathprecision').value = globalpathprecision;
}

// Choose template from gallery
Expand Down Expand Up @@ -244,7 +253,8 @@ var globalcorner = parseInt(document.getElementById('corner').value),
globalsplice = parseInt(document.getElementById('splice').value),
globalfilterspeckle = parseInt(document.getElementById('filterspeckle').value),
globalcolorprecision = parseInt(document.getElementById('colorprecision').value),
globallayerdifference = parseInt(document.getElementById('layerdifference').value);
globallayerdifference = parseInt(document.getElementById('layerdifference').value),
globalpathprecision = parseInt(document.getElementById('pathprecision').value);

// Load past inputs from localStorage
/*
Expand Down Expand Up @@ -327,6 +337,12 @@ document.getElementById('splice').addEventListener('change', function (e) {
restart();
});

document.getElementById('pathprecision').addEventListener('change', function (e) {
globalpathprecision = parseInt(this.value);
document.getElementById('pathprecisionvalue').innerHTML = this.value;
restart();
});

// Save inputs before unloading
/*
window.addEventListener('beforeunload', function () {
Expand Down Expand Up @@ -404,6 +420,7 @@ function restart() {
'filter_speckle': globalfilterspeckle*globalfilterspeckle,
'color_precision': 8-globalcolorprecision,
'layer_difference': globallayerdifference,
'path_precision': globalpathprecision,
});
if (runner) {
runner.stop();
Expand Down
2 changes: 2 additions & 0 deletions webapp/src/conversion/binary_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct BinaryImageConverterParams {
pub max_iterations: usize,
pub splice_threshold: f64,
pub filter_speckle: usize,
pub path_precision: u32,
}

#[wasm_bindgen]
Expand Down Expand Up @@ -80,6 +81,7 @@ impl BinaryImageConverter {
self.svg.prepend_path(
&paths,
&color,
Some(self.params.path_precision),
);
}
self.counter += 1;
Expand Down
2 changes: 2 additions & 0 deletions webapp/src/conversion/color_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct ColorImageConverterParams {
pub filter_speckle: usize,
pub color_precision: i32,
pub layer_difference: i32,
pub path_precision: u32,
}

#[wasm_bindgen]
Expand Down Expand Up @@ -137,6 +138,7 @@ impl ColorImageConverter {
self.svg.prepend_path(
&paths,
&cluster.residue_color(),
Some(self.params.path_precision),
);
self.counter += 1;
false
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/svg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ impl Svg {
Self { element }
}

pub fn prepend_path(&mut self, paths: &CompoundPath, color: &Color) {
pub fn prepend_path(&mut self, paths: &CompoundPath, color: &Color, precision: Option<u32>) {
let path = document()
.create_element_ns(Some("http://www.w3.org/2000/svg"), "path")
.unwrap();
let (string, offset) = paths.to_svg_string(true, PointF64::default());
let (string, offset) = paths.to_svg_string(true, PointF64::default(), precision);
path.set_attribute("d", &string).unwrap();
path.set_attribute(
"transform",
Expand Down

0 comments on commit d0593e7

Please sign in to comment.