font-explorer/src/writer/svg.rs

100 lines
2.3 KiB
Rust
Raw Normal View History

2025-03-03 12:18:52 +00:00
use std::{fs::File, io::{BufWriter, Write}};
2025-03-03 22:48:25 +00:00
use crate::font::{GlyphHeader, GlyphPoint, SplineElement};
2025-03-03 12:18:52 +00:00
use super::Visitor;
pub struct SvgWriter {
first_point: bool,
2025-03-03 22:48:25 +00:00
writer: BufWriter<File>,
points: Vec<(i32, i32)>,
control_points: Vec<(i32, i32)>,
virtual_points: Vec<(i32, i32)>
2025-03-03 12:18:52 +00:00
}
impl SvgWriter {
pub fn new(file: File) -> Self {
SvgWriter {
first_point: true,
2025-03-03 22:48:25 +00:00
writer: BufWriter::new(file),
points: vec![],
control_points: vec![],
virtual_points: vec![]
}
}
}
impl SvgWriter {
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(writer: &mut BufWriter<File>, points: &Vec<(i32, i32)>, color: &'static str) {
for (x, y) in points {
write!(writer, "<circle cx=\"{x}\" cy=\"{y}\" r=\"10\" fill=\"{color}\" />");
2025-03-03 12:18:52 +00:00
}
}
}
impl Visitor for SvgWriter {
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=\"",
2025-03-03 16:21:55 +00:00
header.xmin, -header.ymax,
2025-03-03 12:18:52 +00:00
header.xmax - header.xmin,
header.ymax - header.ymin
);
}
2025-03-03 22:48:25 +00:00
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);
2025-03-03 12:18:52 +00:00
2025-03-03 22:48:25 +00:00
self.points.push((start.x, -start.y));
self.handle_end_point(start);
},
2025-03-03 16:21:55 +00:00
2025-03-03 22:48:25 +00:00
SplineElement::Bezier(start, control, end) => {
self.handle_start_point(start);
write!(self.writer, "Q{} {} {} {} ", control.x, -control.y, end.x, -end.y);
2025-03-03 16:21:55 +00:00
2025-03-03 22:48:25 +00:00
if start.is_virtual {
self.virtual_points.push((start.x, -start.y));
2025-03-03 16:21:55 +00:00
} else {
2025-03-03 22:48:25 +00:00
self.points.push((start.x, -start.y));
2025-03-03 16:21:55 +00:00
}
2025-03-03 22:48:25 +00:00
self.control_points.push((control.x, -control.y));
self.handle_end_point(start);
}
2025-03-03 16:21:55 +00:00
}
2025-03-03 12:18:52 +00:00
}
fn write_suffix(&mut self) {
write!(
self.writer,
2025-03-03 22:48:25 +00:00
"\" style=\"fill:none; stroke:black; stroke-width:3;\" />"
2025-03-03 12:18:52 +00:00
);
2025-03-03 22:48:25 +00:00
SvgWriter::write_points(&mut self.writer, &self.points, "red");
SvgWriter::write_points(&mut self.writer, &self.control_points, "blue");
SvgWriter::write_points(&mut self.writer, &self.virtual_points, "green");
write!(self.writer, "</svg>");
2025-03-03 12:18:52 +00:00
}
}