[librsvg/rustify-rsvg-convert: 8/14] rsvg-convert: Start to work on sizing the output properly




commit 5b1b69499a682caf4c92a902b424304ca083e26c
Author: Sven Neumann <sven svenfoo org>
Date:   Thu Nov 5 00:28:29 2020 +0100

    rsvg-convert: Start to work on sizing the output properly

 src/bin/rsvg-convert/cli.rs     | 37 ++++++++++++---------
 src/bin/rsvg-convert/main.rs    | 38 +++++++++++++--------
 src/bin/rsvg-convert/size.rs    | 29 ++++++++++++++++
 src/bin/rsvg-convert/surface.rs | 74 +++++++++++++++++++----------------------
 4 files changed, 110 insertions(+), 68 deletions(-)
---
diff --git a/src/bin/rsvg-convert/cli.rs b/src/bin/rsvg-convert/cli.rs
index 5567dd43..a5f21b94 100644
--- a/src/bin/rsvg-convert/cli.rs
+++ b/src/bin/rsvg-convert/cli.rs
@@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};
 use librsvg::{Color, Parse};
 
 use crate::input::Input;
+use crate::size::{Dpi, Zoom};
 
 arg_enum! {
     #[derive(Clone, Copy, Debug)]
@@ -19,9 +20,9 @@ arg_enum! {
 
 #[derive(Debug)]
 pub struct Args {
-    pub dpi_x: f64,
-    pub dpi_y: f64,
-    pub zoom: (f32, f32),
+    pub dpi: Dpi,
+    zoom_x: Option<f64>,
+    zoom_y: Option<f64>,
     pub width: Option<u32>,
     pub height: Option<u32>,
     pub format: Format,
@@ -66,7 +67,6 @@ impl Args {
                     .long("x-zoom")
                     .takes_value(true)
                     .value_name("float")
-                    .default_value("1.0")
                     .conflicts_with("zoom")
                     .help("Horizontal zoom factor"),
             )
@@ -76,7 +76,6 @@ impl Args {
                     .long("y-zoom")
                     .takes_value(true)
                     .value_name("float")
-                    .default_value("1.0")
                     .conflicts_with("zoom")
                     .help("Vertical zoom factor"),
             )
@@ -86,7 +85,6 @@ impl Args {
                     .long("zoom")
                     .takes_value(true)
                     .value_name("float")
-                    .default_value("1.0")
                     .help("Zoom factor"),
             )
             .arg(
@@ -197,17 +195,17 @@ impl Args {
             }
         };
 
+        let zoom = value_t!(matches, "zoom", f64).or_none()?;
+        let zoom_x = value_t!(matches, "zoom_x", f64).or_none()?;
+        let zoom_y = value_t!(matches, "zoom_y", f64).or_none()?;
+
         let args = Args {
-            dpi_x: value_t!(matches, "res_x", f64)?,
-            dpi_y: value_t!(matches, "res_y", f64)?,
-            zoom: if matches.is_present("zoom") {
-                let zoom = value_t!(matches, "zoom", f32)?;
-                (zoom, zoom)
-            } else {
-                let zoom_x = value_t!(matches, "zoom_x", f32)?;
-                let zoom_y = value_t!(matches, "zoom_y", f32)?;
-                (zoom_x, zoom_y)
+            dpi: Dpi {
+                x: value_t!(matches, "res_x", f64)?,
+                y: value_t!(matches, "res_y", f64)?,
             },
+            zoom_x: zoom.or(zoom_x),
+            zoom_y: zoom.or(zoom_y),
             width: value_t!(matches, "size_x", u32).or_none()?,
             height: value_t!(matches, "size_y", u32).or_none()?,
             format,
@@ -252,6 +250,15 @@ impl Args {
     pub fn input(&self) -> Input<'_> {
         Input::new(&self.input)
     }
+
+    pub fn zoom(&self) -> Zoom {
+        match (self.zoom_x, self.zoom_y) {
+            (None, None) => Zoom { x: 1.0, y: 1.0 },
+            (Some(x), None) => Zoom { x, y: x },
+            (None, Some(y)) => Zoom { x: y, y },
+            (Some(x), Some(y)) => Zoom { x, y },
+        }
+    }
 }
 
 trait NotFound {
diff --git a/src/bin/rsvg-convert/main.rs b/src/bin/rsvg-convert/main.rs
index 4ac0c439..c250287d 100644
--- a/src/bin/rsvg-convert/main.rs
+++ b/src/bin/rsvg-convert/main.rs
@@ -4,13 +4,15 @@ extern crate clap;
 mod cli;
 mod input;
 mod output;
+mod size;
 mod surface;
 
 use cssparser::Color;
-use librsvg::{CairoRenderer, Loader, RenderingError};
+use librsvg::{CairoRenderer, Loader, RenderingError, SvgHandle};
 
 use crate::cli::Args;
 use crate::output::Stream;
+use crate::size::Size;
 use crate::surface::Surface;
 
 #[macro_export]
@@ -37,6 +39,13 @@ fn load_stylesheet(args: &Args) -> std::io::Result<Option<String>> {
     }
 }
 
+fn get_size(_handle: &SvgHandle, renderer: &CairoRenderer, args: &Args) -> Option<Size> {
+    // TODO
+    renderer
+        .intrinsic_size_in_pixels()
+        .map(|(w, h)| Size::new(w, h).scale(args.zoom()))
+}
+
 fn main() {
     let args = Args::new().unwrap_or_else(|e| e.exit());
 
@@ -58,21 +67,21 @@ fn main() {
                 .unwrap_or_else(|e| exit!("Error applying stylesheet: {}", e));
         }
 
-        let renderer = CairoRenderer::new(&handle).with_dpi(args.dpi_x, args.dpi_y);
+        let renderer = CairoRenderer::new(&handle).with_dpi(args.dpi.x, args.dpi.y);
 
         if target.is_none() {
-            target = match renderer.intrinsic_size_in_pixels() {
-                Some((width, height)) => {
-                    let output = Stream::new(args.output())
-                        .unwrap_or_else(|e| exit!("Error opening output: {}", e));
-
-                    match Surface::new(args.format, width, height, output) {
-                        Ok(surface) => Some(surface),
-                        Err(cairo::Status::InvalidSize) => size_limit_exceeded(),
-                        Err(e) => exit!("Error creating output surface: {}", e),
-                    }
+            let size = get_size(&handle, &renderer, &args)
+                .unwrap_or_else(|| exit!("Could not get dimensions for file {}", input));
+
+            target = {
+                let output = Stream::new(args.output())
+                    .unwrap_or_else(|e| exit!("Error opening output: {}", e));
+
+                match Surface::new(args.format, size, output) {
+                    Ok(surface) => Some(surface),
+                    Err(cairo::Status::InvalidSize) => size_limit_exceeded(),
+                    Err(e) => exit!("Error creating output surface: {}", e),
                 }
-                None => None,
             };
         }
 
@@ -88,6 +97,9 @@ fn main() {
                 );
             }
 
+            let zoom = args.zoom();
+            cr.scale(zoom.x, zoom.y);
+
             surface
                 .render(&renderer, &cr, args.export_id())
                 .unwrap_or_else(|e| match e {
diff --git a/src/bin/rsvg-convert/size.rs b/src/bin/rsvg-convert/size.rs
new file mode 100644
index 00000000..5b86481d
--- /dev/null
+++ b/src/bin/rsvg-convert/size.rs
@@ -0,0 +1,29 @@
+#[derive(Debug)]
+pub struct Dpi {
+    pub x: f64,
+    pub y: f64,
+}
+
+pub struct Zoom {
+    pub x: f64,
+    pub y: f64,
+}
+
+#[derive(Clone, Debug)]
+pub struct Size {
+    pub w: f64,
+    pub h: f64,
+}
+
+impl Size {
+    pub fn new(w: f64, h: f64) -> Self {
+        Self { w, h }
+    }
+
+    pub fn scale(&self, zoom: Zoom) -> Self {
+        Self {
+            w: self.w * zoom.x,
+            h: self.h * zoom.y,
+        }
+    }
+}
diff --git a/src/bin/rsvg-convert/surface.rs b/src/bin/rsvg-convert/surface.rs
index b94c203a..b577bd75 100644
--- a/src/bin/rsvg-convert/surface.rs
+++ b/src/bin/rsvg-convert/surface.rs
@@ -5,17 +5,18 @@ use librsvg::{CairoRenderer, RenderingError};
 
 use crate::cli::Format;
 use crate::output::Stream;
+use crate::size::Size;
 
-// TODO
+// TODO: use from src/lib/handle.rs
 fn checked_i32(x: f64) -> Result<i32, cairo::Status> {
     cast::i32(x).map_err(|_| cairo::Status::InvalidSize)
 }
 
 pub enum Surface {
     Png(cairo::ImageSurface, Stream),
-    Pdf(cairo::PdfSurface, (f64, f64)),
-    Ps(cairo::PsSurface, (f64, f64)),
-    Svg(cairo::SvgSurface, (f64, f64)),
+    Pdf(cairo::PdfSurface, Size),
+    Ps(cairo::PsSurface, Size),
+    Svg(cairo::SvgSurface, Size),
 }
 
 impl Deref for Surface {
@@ -32,68 +33,61 @@ impl Deref for Surface {
 }
 
 impl Surface {
-    pub fn new(
-        format: Format,
-        width: f64,
-        height: f64,
-        stream: Stream,
-    ) -> Result<Self, cairo::Status> {
+    pub fn new(format: Format, size: Size, stream: Stream) -> Result<Self, cairo::Status> {
         match format {
-            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),
+            Format::Png => Self::new_for_png(size, stream),
+            Format::Pdf => Self::new_for_pdf(size, stream),
+            Format::Ps => Self::new_for_ps(size, stream, false),
+            Format::Eps => Self::new_for_ps(size, stream, true),
+            Format::Svg => Self::new_for_svg(size, stream),
         }
     }
 
-    fn new_for_png(width: f64, height: f64, stream: Stream) -> Result<Self, cairo::Status> {
-        let w = checked_i32(width.round())?;
-        let h = checked_i32(height.round())?;
+    fn new_for_png(size: Size, stream: Stream) -> Result<Self, cairo::Status> {
+        let w = checked_i32(size.w.round())?;
+        let h = checked_i32(size.h.round())?;
         let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, w, h)?;
         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)?;
+    fn new_for_pdf(size: Size, stream: Stream) -> Result<Self, cairo::Status> {
+        let surface = cairo::PdfSurface::for_stream(size.w, size.h, stream)?;
         if let Some(date) = metadata::creation_date() {
             surface.set_metadata(cairo::PdfMetadata::CreateDate, &date)?;
         }
-        Ok(Self::Pdf(surface, (width, height)))
+        Ok(Self::Pdf(surface, size))
     }
 
-    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)?;
+    fn new_for_ps(size: Size, stream: Stream, eps: bool) -> Result<Self, cairo::Status> {
+        let surface = cairo::PsSurface::for_stream(size.w, size.h, stream)?;
         surface.set_eps(eps);
-        Ok(Self::Ps(surface, (width, height)))
+        Ok(Self::Ps(surface, size))
     }
 
-    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 new_for_svg(size: Size, stream: Stream) -> Result<Self, cairo::Status> {
+        let surface = cairo::SvgSurface::for_stream(size.w, size.h, stream)?;
+        Ok(Self::Svg(surface, size))
     }
 
-    fn size(&self) -> (f64, f64) {
+    fn size(&self) -> Size {
         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,
+            Self::Png(surface, _) => Size {
+                w: surface.get_width() as f64,
+                h: surface.get_height() as f64,
+            },
+            Self::Pdf(_, size) => size.clone(),
+            Self::Ps(_, size) => size.clone(),
+            Self::Svg(_, size) => size.clone(),
         }
     }
 
     fn bounds(&self) -> cairo::Rectangle {
-        let (width, height) = self.size();
+        let size = self.size();
         cairo::Rectangle {
             x: 0.0,
             y: 0.0,
-            width,
-            height,
+            width: size.w,
+            height: size.h,
         }
     }
 


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