font-explorer/src/writer/svg.rs

106 lines
2.4 KiB
Rust

use std::{fs::File, io::{BufWriter, Write}};
use crate::font::{GlyphHeader, GlyphPoint, SplineElement};
use super::Visitor;
pub struct SvgWriter<'a, W: Sized + Write> {
first_point: bool,
writer: &'a mut W,
points: Vec<(i32, i32)>,
control_points: Vec<(i32, i32)>,
virtual_points: Vec<(i32, i32)>
}
impl<'a, W: Sized + Write> SvgWriter<'a, W> {
pub fn new(out: &'a mut W) -> Self {
SvgWriter {
first_point: true,
writer: out,
points: vec![],
control_points: vec![],
virtual_points: vec![]
}
}
}
impl<'a, W: Sized + Write> SvgWriter<'a, W> {
fn handle_start_point(&mut self, point: &GlyphPoint) {
if self.first_point {
write!(self.writer, "M{} {} ", point.x, -point.y);
self.first_point = false;
}
}
fn handle_end_point(&mut self, point: &GlyphPoint) {
if point.is_endpoint {
self.first_point = true;
}
}
fn write_points(&mut self) {
for (x, y) in &self.points {
write!(self.writer, "<circle cx=\"{x}\" cy=\"{y}\" r=\"10\" fill=\"red\" />");
}
for (x, y) in &self.control_points {
write!(self.writer, "<circle cx=\"{x}\" cy=\"{y}\" r=\"10\" fill=\"blue\" />");
}
for (x, y) in &self.virtual_points {
write!(self.writer, "<circle cx=\"{x}\" cy=\"{y}\" r=\"10\" fill=\"green\" />");
}
}
}
impl<'a, W: Sized + Write> Visitor for SvgWriter<'a, W> {
fn write_prefix(&mut self, header: &GlyphHeader) {
write!(
self.writer,
"<svg width=\"1000\" height=\"1000\" viewBox=\"{} {} {} {}\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"",
header.xmin, -header.ymax,
header.xmax - header.xmin,
header.ymax - header.ymin
);
}
fn write_point(&mut self, point: &SplineElement) {
match point {
SplineElement::Line(start, end) => {
self.handle_start_point(start);
write!(self.writer, "L{} {} ", end.x, -end.y);
self.points.push((start.x, -start.y));
self.handle_end_point(start);
},
SplineElement::Bezier(start, control, end) => {
self.handle_start_point(start);
write!(self.writer, "Q{} {} {} {} ", control.x, -control.y, end.x, -end.y);
if start.is_virtual {
self.virtual_points.push((start.x, -start.y));
} else {
self.points.push((start.x, -start.y));
}
self.control_points.push((control.x, -control.y));
self.handle_end_point(start);
}
}
}
fn write_suffix(&mut self) {
write!(
self.writer,
"\" style=\"fill:none; stroke:black; stroke-width:3;\" />"
);
self.write_points();
write!(self.writer, "</svg>");
}
}