[librsvg/rustify-rsvg-convert: 24/41] rsvg-convert: simplify output handling and use Gio




commit 4a8eecae48d0bc52ea8ed66ec1fed3c4ce90b964
Author: Paolo Borelli <pborelli gnome org>
Date:   Sat Jan 9 15:02:20 2021 +0100

    rsvg-convert: simplify output handling and use Gio
    
    Simplify output handling in a way similar to what was done for
    info and use GOutpuStream for simmetry and because it has a
    into_write() method that we can feed to cairo.

 src/bin/rsvg-convert/cli.rs     | 15 +++++++-------
 src/bin/rsvg-convert/main.rs    | 30 ++++++++++++++++++++-------
 src/bin/rsvg-convert/output.rs  | 45 +++++++++--------------------------------
 src/bin/rsvg-convert/surface.rs | 37 ++++++++++++++++-----------------
 4 files changed, 57 insertions(+), 70 deletions(-)
---
diff --git a/src/bin/rsvg-convert/cli.rs b/src/bin/rsvg-convert/cli.rs
index 69d5aac3..784e99c3 100644
--- a/src/bin/rsvg-convert/cli.rs
+++ b/src/bin/rsvg-convert/cli.rs
@@ -1,10 +1,11 @@
 // command-line interface for rsvg-convert
 
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 
 use librsvg::{Color, Parse};
 
 use crate::input::Input;
+use crate::output::Output;
 use crate::size::{Dpi, Scale};
 
 arg_enum! {
@@ -31,7 +32,7 @@ pub struct Args {
     pub stylesheet: Option<PathBuf>,
     pub unlimited: bool,
     pub keep_image_data: bool,
-    output: Option<PathBuf>,
+    pub output: Output,
     pub input: Vec<Input>,
 }
 
@@ -223,7 +224,11 @@ impl Args {
             stylesheet: matches.value_of_os("stylesheet").map(PathBuf::from),
             unlimited: matches.is_present("unlimited"),
             keep_image_data,
-            output: matches.value_of_os("output").map(PathBuf::from),
+            output: matches
+                .value_of_os("output")
+                .map(PathBuf::from)
+                .map(Output::Path)
+                .unwrap_or(Output::Stdout),
             input: match matches.values_of_os("FILE") {
                 Some(values) => values.map(PathBuf::from).map(Input::Path).collect(),
                 None => vec![Input::Stdin],
@@ -248,10 +253,6 @@ impl Args {
     pub fn export_id(&self) -> Option<&str> {
         self.export_id.as_deref()
     }
-
-    pub fn output(&self) -> Option<&Path> {
-        self.output.as_deref()
-    }
 }
 
 fn is_valid_resolution(v: String) -> Result<(), String> {
diff --git a/src/bin/rsvg-convert/main.rs b/src/bin/rsvg-convert/main.rs
index 91ad18c0..d611dbca 100644
--- a/src/bin/rsvg-convert/main.rs
+++ b/src/bin/rsvg-convert/main.rs
@@ -9,13 +9,16 @@ mod surface;
 
 use cssparser::Color;
 use gio::prelude::*;
-use gio::{Cancellable, FileExt, InputStream, UnixInputStream};
+use gio::{
+    Cancellable, FileCreateFlags, FileExt, InputStream, OutputStream, UnixInputStream,
+    UnixOutputStream,
+};
 use librsvg::rsvg_convert_only::LegacySize;
 use librsvg::{CairoRenderer, Loader, RenderingError};
 
 use crate::cli::Args;
 use crate::input::Input;
-use crate::output::Stream;
+use crate::output::Output;
 use crate::size::{ResizeStrategy, Size};
 use crate::surface::Surface;
 
@@ -109,14 +112,27 @@ fn main() {
             };
 
             target = {
-                let output = Stream::new(args.output())
-                    .unwrap_or_else(|e| exit!("Error opening output: {}", e));
-
                 let size = strategy
                     .apply(Size::new(width, height), args.keep_aspect_ratio)
                     .unwrap_or_else(|_| exit!("The SVG {} has no dimensions", input));
 
-                match Surface::new(args.format, size, output) {
+                let output_stream = match args.output {
+                    Output::Stdout => {
+                        let stream = unsafe { UnixOutputStream::new(1) };
+                        stream.upcast::<OutputStream>()
+                    }
+                    Output::Path(ref p) => {
+                        let file = gio::File::new_for_path(p);
+                        let stream = file
+                            .create(FileCreateFlags::NONE, None::<&Cancellable>)
+                            .unwrap_or_else(|e| {
+                                exit!("Error opening output \"{}\": {}", args.output, e)
+                            });
+                        stream.upcast::<OutputStream>()
+                    }
+                };
+
+                match Surface::new(args.format, size, output_stream) {
                     Ok(surface) => Some(surface),
                     Err(cairo::Status::InvalidSize) => size_limit_exceeded(),
                     Err(e) => exit!("Error creating output surface: {}", e),
@@ -144,7 +160,7 @@ fn main() {
         }
     }
 
-    if let Some(ref mut surface) = target {
+    if let Some(surface) = target {
         surface
             .finish()
             .unwrap_or_else(|e| exit!("Error saving output: {}", e));
diff --git a/src/bin/rsvg-convert/output.rs b/src/bin/rsvg-convert/output.rs
index e6862ec4..6ed2829d 100644
--- a/src/bin/rsvg-convert/output.rs
+++ b/src/bin/rsvg-convert/output.rs
@@ -1,44 +1,17 @@
 // output stream for rsvg-convert
+use std::path::PathBuf;
 
-use std::fs;
-use std::io;
-
-pub enum Stream {
-    File(fs::File),
-    Stdout(io::Stdout),
+#[derive(Clone, Debug)]
+pub enum Output {
+    Stdout,
+    Path(PathBuf),
 }
 
-impl Stream {
-    pub fn new(path: Option<&std::path::Path>) -> io::Result<Self> {
-        match path {
-            Some(path) => {
-                let file = fs::File::create(path)?;
-                Ok(Self::File(file))
-            }
-            None => Ok(Self::Stdout(io::stdout())),
-        }
-    }
-}
-
-impl io::Write for Stream {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        match self {
-            Self::File(file) => file.write(buf),
-            Self::Stdout(stream) => stream.write(buf),
-        }
-    }
-
-    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        match self {
-            Self::File(file) => file.write_all(buf),
-            Self::Stdout(stream) => stream.write_all(buf),
-        }
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
+impl std::fmt::Display for Output {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
-            Self::File(file) => file.flush(),
-            Self::Stdout(stream) => stream.flush(),
+            Output::Stdout => "stdout".fmt(f),
+            Output::Path(p) => p.display().fmt(f),
         }
     }
 }
diff --git a/src/bin/rsvg-convert/surface.rs b/src/bin/rsvg-convert/surface.rs
index 361165ee..3c6f7578 100644
--- a/src/bin/rsvg-convert/surface.rs
+++ b/src/bin/rsvg-convert/surface.rs
@@ -1,10 +1,11 @@
 use core::ops::Deref;
 use std::io;
 
+use gio::prelude::*;
+use gio::OutputStream;
 use librsvg::{CairoRenderer, RenderingError};
 
 use crate::cli::Format;
-use crate::output::Stream;
 use crate::size::Size;
 
 // TODO: use from src/lib/handle.rs
@@ -13,7 +14,7 @@ fn checked_i32(x: f64) -> Result<i32, cairo::Status> {
 }
 
 pub enum Surface {
-    Png(cairo::ImageSurface, Stream),
+    Png(cairo::ImageSurface, OutputStream),
     Pdf(cairo::PdfSurface, Size),
     Ps(cairo::PsSurface, Size),
     Svg(cairo::SvgSurface, Size),
@@ -33,7 +34,7 @@ impl Deref for Surface {
 }
 
 impl Surface {
-    pub fn new(format: Format, size: Size, stream: Stream) -> Result<Self, cairo::Status> {
+    pub fn new(format: Format, size: Size, stream: OutputStream) -> Result<Self, cairo::Status> {
         match format {
             Format::Png => Self::new_for_png(size, stream),
             Format::Pdf => Self::new_for_pdf(size, stream),
@@ -43,29 +44,29 @@ impl Surface {
         }
     }
 
-    fn new_for_png(size: Size, stream: Stream) -> Result<Self, cairo::Status> {
+    fn new_for_png(size: Size, stream: OutputStream) -> 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(size: Size, stream: Stream) -> Result<Self, cairo::Status> {
-        let surface = cairo::PdfSurface::for_stream(size.w, size.h, stream)?;
+    fn new_for_pdf(size: Size, stream: OutputStream) -> Result<Self, cairo::Status> {
+        let surface = cairo::PdfSurface::for_stream(size.w, size.h, stream.into_write())?;
         if let Some(date) = metadata::creation_date() {
             surface.set_metadata(cairo::PdfMetadata::CreateDate, &date)?;
         }
         Ok(Self::Pdf(surface, size))
     }
 
-    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)?;
+    fn new_for_ps(size: Size, stream: OutputStream, eps: bool) -> Result<Self, cairo::Status> {
+        let surface = cairo::PsSurface::for_stream(size.w, size.h, stream.into_write())?;
         surface.set_eps(eps);
         Ok(Self::Ps(surface, size))
     }
 
-    fn new_for_svg(size: Size, stream: Stream) -> Result<Self, cairo::Status> {
-        let surface = cairo::SvgSurface::for_stream(size.w, size.h, stream)?;
+    fn new_for_svg(size: Size, stream: OutputStream) -> Result<Self, cairo::Status> {
+        let surface = cairo::SvgSurface::for_stream(size.w, size.h, stream.into_write())?;
         Ok(Self::Svg(surface, size))
     }
 
@@ -111,17 +112,13 @@ impl Surface {
         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> {
+    pub fn finish(self) -> Result<(), cairo::IoError> {
         match self {
-            Self::Png(surface, stream) => surface.write_to_png(stream),
-            _ => Self::finish_output_stream(self),
+            Self::Png(surface, stream) => surface.write_to_png(&mut stream.into_write()),
+            _ => match self.finish_output_stream() {
+                Ok(_) => Ok(()),
+                Err(e) => Err(cairo::IoError::Io(io::Error::from(e))),
+            },
         }
     }
 }


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