[librsvg/rustify-rsvg-convert: 23/78] rsvg-convert: Add support for (E)PS and SVG output formats




commit da172eef5ec40939e50e74714c1e44f0d39d3722
Author: Sven Neumann <sven svenfoo org>
Date:   Mon Nov 2 15:26:54 2020 +0100

    rsvg-convert: Add support for (E)PS and SVG output formats
    
    We will want to revisit the package dependencies, only the rsvg-convert
    binary needs the PS feature from cairo-rs.

 Cargo.toml                      |  2 +-
 src/bin/rsvg-convert/surface.rs | 90 +++++++++++++++++++++++++++++++----------
 2 files changed, 69 insertions(+), 23 deletions(-)
---
diff --git a/Cargo.toml b/Cargo.toml
index 9f511b0d..45c965aa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@ crate-type = [ "staticlib", "rlib" ]
 bitflags = "1.0"
 # Keep these in sync with respect to the cairo-rs version:
 #   src/lib.rs - toplevel example in the docs
-cairo-rs = { version="0.8.0", features=["v1_16", "png", "pdf", "svg"] }
+cairo-rs = { version="0.8.0", features=["v1_16", "png", "pdf", "ps", "svg"] }
 cairo-sys-rs = "0.9.0"
 cast = "0.2.3"
 clap = "~2.33.0"
diff --git a/src/bin/rsvg-convert/surface.rs b/src/bin/rsvg-convert/surface.rs
index 262bb15c..e834c349 100644
--- a/src/bin/rsvg-convert/surface.rs
+++ b/src/bin/rsvg-convert/surface.rs
@@ -3,12 +3,14 @@ use std::io;
 
 use librsvg::{CairoRenderer, RenderingError};
 
-use crate::cli;
+use crate::cli::Format;
 use crate::output::Stream;
 
 pub enum Surface {
     Png(cairo::ImageSurface, Stream),
     Pdf(cairo::PdfSurface, (f64, f64)),
+    Ps(cairo::PsSurface, (f64, f64)),
+    Svg(cairo::SvgSurface, (f64, f64)),
 }
 
 impl Deref for Surface {
@@ -16,61 +18,105 @@ impl Deref for Surface {
 
     fn deref(&self) -> &cairo::Surface {
         match self {
-            Self::Png(surface, _) => surface.deref(),
-            Self::Pdf(surface, _) => surface.deref(),
+            Self::Png(surface, _) => &surface,
+            Self::Pdf(surface, _) => &surface,
+            Self::Ps(surface, _) => &surface,
+            Self::Svg(surface, _) => &surface,
         }
     }
 }
 
 impl Surface {
     pub fn new(
-        format: cli::Format,
+        format: Format,
         width: f64,
         height: f64,
         stream: Stream,
     ) -> Result<Self, cairo::Status> {
         match format {
-            cli::Format::Png => {
-                cairo::ImageSurface::create(cairo::Format::ARgb32, width as i32, height as i32)
-                    .map(|s| Self::Png(s, stream))
-            }
-            cli::Format::Pdf => cairo::PdfSurface::for_stream(width, height, stream)
-                .map(|s| Self::Pdf(s, (width, height))),
-            _ => Err(cairo::Status::InvalidFormat),
+            Format::Png => Self::new_for_png(width, height, stream),
+            Format::Pdf => Self::new_for_pdf(width, height, stream),
+            Format::Ps => Self::new_for_ps(width, height, stream, false),
+            Format::Eps => Self::new_for_ps(width, height, stream, true),
+            Format::Svg => Self::new_for_svg(width, height, stream),
         }
     }
 
+    fn new_for_png(width: f64, height: f64, stream: Stream) -> Result<Self, cairo::Status> {
+        let surface =
+            cairo::ImageSurface::create(cairo::Format::ARgb32, width as i32, height as i32)?;
+        Ok(Self::Png(surface, stream))
+    }
+
+    fn new_for_pdf(width: f64, height: f64, stream: Stream) -> Result<Self, cairo::Status> {
+        let surface = cairo::PdfSurface::for_stream(width, height, stream)?;
+        Ok(Self::Pdf(surface, (width, height)))
+    }
+
+    fn new_for_ps(
+        width: f64,
+        height: f64,
+        stream: Stream,
+        eps: bool,
+    ) -> Result<Self, cairo::Status> {
+        let surface = cairo::PsSurface::for_stream(width, height, stream)?;
+        surface.set_eps(eps);
+        Ok(Self::Ps(surface, (width, height)))
+    }
+
+    fn new_for_svg(width: f64, height: f64, stream: Stream) -> Result<Self, cairo::Status> {
+        let surface = cairo::SvgSurface::for_stream(width, height, stream)?;
+        Ok(Self::Svg(surface, (width, height)))
+    }
+
     fn size(&self) -> (f64, f64) {
         match self {
             Self::Png(s, _) => (s.get_width() as f64, s.get_height() as f64),
             Self::Pdf(_, size) => *size,
+            Self::Ps(_, size) => *size,
+            Self::Svg(_, size) => *size,
         }
     }
 
-    pub fn render(&self, renderer: &CairoRenderer, id: Option<&str>) -> Result<(), RenderingError> {
-        let cr = cairo::Context::new(self);
-
+    fn bounds(&self) -> cairo::Rectangle {
         let (width, height) = self.size();
-        let viewport = cairo::Rectangle {
+        cairo::Rectangle {
             x: 0.0,
             y: 0.0,
             width,
             height,
-        };
+        }
+    }
 
-        renderer.render_layer(&cr, id, &viewport)?;
-        cr.show_page();
+    pub fn render(&self, renderer: &CairoRenderer, id: Option<&str>) -> Result<(), RenderingError> {
+        let cr = cairo::Context::new(self);
+        let viewport = self.bounds();
+        let show_page = |_| self.show_page(&cr);
 
+        renderer
+            .render_layer(&cr, id, &viewport)
+            .and_then(show_page)
+    }
+
+    pub fn show_page(&self, cr: &cairo::Context) -> Result<(), RenderingError> {
+        match self {
+            Self::Png(_, _) => (),
+            _ => cr.show_page(),
+        }
         Ok(())
     }
 
+    fn finish_output_stream(surface: &cairo::Surface) -> Result<(), cairo::IoError> {
+        match surface.finish_output_stream() {
+            Ok(_) => Ok(()),
+            Err(e) => Err(cairo::IoError::Io(io::Error::from(e))),
+        }
+    }
+
     pub fn finish(&mut self) -> Result<(), cairo::IoError> {
         match self {
             Self::Png(surface, stream) => surface.write_to_png(stream),
-            Self::Pdf(surface, _) => surface
-                .finish_output_stream()
-                .map(|_| ())
-                .map_err(|e| cairo::IoError::Io(io::Error::from(e))),
+            _ => Self::finish_output_stream(self),
         }
     }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]