From 1ca35d842619322a88af9deb797ef5fc7eec9059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20K=C3=B6ln?= Date: Mon, 24 Jun 2019 22:41:34 +0300 Subject: [PATCH] add PS export as well. also rename svg2pdf into convert and add PS export to it --- Cargo.toml | 2 +- examples/{svg2pdf => convert}/Cargo.toml | 2 +- examples/convert/src/main.rs | 26 +++++++++ examples/svg2pdf/src/main.rs | 20 ------- renderer/src/scene.rs | 70 ++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 22 deletions(-) rename examples/{svg2pdf => convert}/Cargo.toml (94%) create mode 100644 examples/convert/src/main.rs delete mode 100644 examples/svg2pdf/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 174b1bcf..e22af15d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ members = [ "examples/canvas_moire", "examples/canvas_text", "examples/lottie_basic", - "examples/svg2pdf", + "examples/convert", "examples/swf_basic", "geometry", "gl", diff --git a/examples/svg2pdf/Cargo.toml b/examples/convert/Cargo.toml similarity index 94% rename from examples/svg2pdf/Cargo.toml rename to examples/convert/Cargo.toml index e656de8b..c36e9dfa 100644 --- a/examples/svg2pdf/Cargo.toml +++ b/examples/convert/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "svg2pdf" +name = "convert" version = "0.1.0" authors = ["Sebastian Köln "] edition = "2018" diff --git a/examples/convert/src/main.rs b/examples/convert/src/main.rs new file mode 100644 index 00000000..29720cf9 --- /dev/null +++ b/examples/convert/src/main.rs @@ -0,0 +1,26 @@ +use std::fs::File; +use std::io::{Read, BufWriter}; +use std::error::Error; +use std::path::PathBuf; +use pathfinder_svg::BuiltSVG; +use pathfinder_pdf::make_pdf; +use usvg::{Tree, Options}; + +fn main() -> Result<(), Box> { + let mut args = std::env::args_os().skip(1); + let input = PathBuf::from(args.next().expect("no input given")); + let output = PathBuf::from(args.next().expect("no output given")); + + let mut data = Vec::new(); + File::open(input)?.read_to_end(&mut data)?; + let svg = BuiltSVG::from_tree(Tree::from_data(&data, &Options::default()).unwrap()); + + let scene = &svg.scene; + let mut writer = BufWriter::new(File::create(&output)?); + match output.extension().and_then(|s| s.to_str()) { + Some("pdf") => make_pdf(&mut writer, scene), + Some("ps") => scene.write_ps(&mut writer)?, + _ => return Err("output filename must have .ps or .pdf extension".into()) + } + Ok(()) +} diff --git a/examples/svg2pdf/src/main.rs b/examples/svg2pdf/src/main.rs deleted file mode 100644 index 9dd7b88e..00000000 --- a/examples/svg2pdf/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::fs::File; -use std::io::{Read, BufWriter}; -use std::error::Error; -use pathfinder_svg::BuiltSVG; -use pathfinder_pdf::make_pdf; -use usvg::{Tree, Options}; - -fn main() -> Result<(), Box> { - let mut args = std::env::args().skip(1); - let input = args.next().expect("no input given"); - let output = args.next().expect("no output given"); - - let mut data = Vec::new(); - File::open(input)?.read_to_end(&mut data)?; - let svg = BuiltSVG::from_tree(Tree::from_data(&data, &Options::default()).unwrap()); - - make_pdf(BufWriter::new(File::create(output)?), &svg.scene); - - Ok(()) -} diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index f441d02f..13c2c299 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -199,6 +199,76 @@ impl Scene { Ok(()) } + pub fn write_ps(&self, writer: &mut W) -> io::Result<()> + where + W: Write, + { + use std::fmt; + use pathfinder_content::segment::SegmentKind; + + struct P(Vector2F); + impl fmt::Display for P { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {}", self.0.x(), self.0.y()) + } + } + + writeln!(writer, "%!PS-Adobe-3.0 EPSF-3.0")?; + writeln!(writer, "%%BoundingBox: {:.0} {:.0}", + P(self.view_box.origin()), + P(self.view_box.size()), + )?; + writeln!(writer, "%%HiResBoundingBox: {} {}", + P(self.view_box.origin()), + P(self.view_box.size()), + )?; + writeln!(writer, "0 {} translate", self.view_box.size().y())?; + writeln!(writer, "1 -1 scale")?; + + for path_object in &self.paths { + writeln!(writer, "newpath")?; + let color = self.paints[path_object.paint.0 as usize].color.to_f32(); + for contour in path_object.outline.contours() { + for (segment_index, segment) in contour.iter().enumerate() { + if segment_index == 0 { + writeln!(writer, "{} moveto", P(segment.baseline.from()))?; + } + + match segment.kind { + SegmentKind::None => {} + SegmentKind::Line => { + writeln!(writer, "{} lineto", P(segment.baseline.to()))?; + } + SegmentKind::Quadratic => { + let current = segment.baseline.from(); + let c = segment.ctrl.from(); + let p = segment.baseline.to(); + let c1 = Vector2F::splat(2. / 3.) * c + Vector2F::splat(1. / 3.) * current; + let c2 = Vector2F::splat(2. / 3.) * c + Vector2F::splat(1. / 3.) * p; + writeln!(writer, "{} {} {} curveto", P(c1), P(c2), P(p))?; + } + SegmentKind::Cubic => { + writeln!(writer, "{} {} {} curveto", + P(segment.ctrl.from()), + P(segment.ctrl.to()), + P(segment.baseline.to()) + )?; + } + } + } + + if contour.is_closed() { + writeln!(writer, "closepath")?; + } + } + writeln!(writer, "{} {} {} setrgbcolor", color.r(), color.g(), color.b())?; + writeln!(writer, "fill")?; + } + writeln!(writer, "showpage")?; + Ok(()) + } + + pub fn paths<'a>(&'a self) -> PathIter { PathIter { scene: self,