[librsvg: 13/35] rsvg-convert: parse the --width and --height arguments as a CSS length
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 13/35] rsvg-convert: parse the --width and --height arguments as a CSS length
- Date: Thu, 17 Jun 2021 19:31:38 +0000 (UTC)
commit 222ae0a40621a2028fb8456e65bf50d25fcc149f
Author: Federico Mena Quintero <federico gnome org>
Date: Mon Jun 14 16:36:58 2021 -0500
rsvg-convert: parse the --width and --height arguments as a CSS length
For now we simply convert to pixels based on the DPI values. The
interesting stuff comes next.
Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/547>
src/bin/rsvg-convert.rs | 95 +++++++++++++++++++++++++++++++++++++++----------
src/lib.rs | 2 ++
2 files changed, 79 insertions(+), 18 deletions(-)
---
diff --git a/src/bin/rsvg-convert.rs b/src/bin/rsvg-convert.rs
index 152b7873..624ae9ce 100644
--- a/src/bin/rsvg-convert.rs
+++ b/src/bin/rsvg-convert.rs
@@ -20,8 +20,12 @@ mod windows_imports {
#[cfg(windows)]
use self::windows_imports::*;
-use librsvg::rsvg_convert_only::{LegacySize, PathOrUrl};
-use librsvg::{AcceptLanguage, CairoRenderer, Color, Language, Loader, Parse, RenderingError};
+use librsvg::rsvg_convert_only::{
+ Dpi, Horizontal, LegacySize, Normalize, NormalizeParams, PathOrUrl, ULength, Vertical,
+};
+use librsvg::{
+ AcceptLanguage, CairoRenderer, Color, Language, LengthUnit, Loader, Parse, RenderingError,
+};
use once_cell::unsync::OnceCell;
use std::ops::Deref;
use std::path::PathBuf;
@@ -95,14 +99,23 @@ impl Size {
#[derive(Clone, Copy, Debug)]
enum ResizeStrategy {
Scale(Scale),
- Fit(u32, u32),
- FitWidth(u32),
- FitHeight(u32),
- FitLargestScale(Scale, Option<u32>, Option<u32>),
+ Fit(ULength<Horizontal>, ULength<Vertical>),
+ FitWidth(ULength<Horizontal>),
+ FitHeight(ULength<Vertical>),
+ FitLargestScale(
+ Scale,
+ Option<ULength<Horizontal>>,
+ Option<ULength<Vertical>>,
+ ),
}
impl ResizeStrategy {
- pub fn apply(self, input: Size, keep_aspect_ratio: bool) -> Option<Size> {
+ pub fn apply(
+ self,
+ input: Size,
+ keep_aspect_ratio: bool,
+ params: &NormalizeParams,
+ ) -> Option<Size> {
if input.w == 0.0 || input.h == 0.0 {
return None;
}
@@ -113,22 +126,22 @@ impl ResizeStrategy {
h: input.h * s.y,
},
ResizeStrategy::Fit(w, h) => Size {
- w: f64::from(w),
- h: f64::from(h),
+ w: w.to_user(params),
+ h: h.to_user(params),
},
ResizeStrategy::FitWidth(w) => Size {
- w: f64::from(w),
- h: input.h * f64::from(w) / input.w,
+ w: w.to_user(params),
+ h: input.h * w.to_user(params) / input.w,
},
ResizeStrategy::FitHeight(h) => Size {
- w: input.w * f64::from(h) / input.h,
- h: f64::from(h),
+ w: input.w * h.to_user(params) / input.h,
+ h: h.to_user(params),
},
ResizeStrategy::FitLargestScale(s, w, h) => {
let scaled_input_w = input.w * s.x;
let scaled_input_h = input.h * s.y;
- let f = match (w.map(f64::from), h.map(f64::from)) {
+ let f = match (w.map(|l| l.to_user(params)), h.map(|l| l.to_user(params))) {
(Some(w), Some(h)) if w < scaled_input_w || h < scaled_input_h => {
let sx = w / scaled_input_w;
let sy = h / scaled_input_h;
@@ -439,8 +452,8 @@ arg_enum! {
struct Converter {
pub dpi: (f64, f64),
pub zoom: Scale,
- pub width: Option<u32>,
- pub height: Option<u32>,
+ pub width: Option<ULength<Horizontal>>,
+ pub height: Option<ULength<Vertical>>,
pub format: Format,
pub export_id: Option<String>,
pub keep_aspect_ratio: bool,
@@ -560,10 +573,13 @@ impl Converter {
natural_size: &Size,
input: &Input,
) -> Result<Size, Error> {
+ let params = NormalizeParams::from_dpi(Dpi::new(self.dpi.0, self.dpi.1));
+
strategy
.apply(
Size::new(natural_size.w, natural_size.h),
self.keep_aspect_ratio,
+ ¶ms,
)
.ok_or_else(|| error!("The SVG {} has no dimensions", input))
}
@@ -777,6 +793,15 @@ fn parse_args() -> Result<Converter, Error> {
}
};
+ let width = value_t!(matches, "size_x", String)
+ .or_none()?
+ .map(parse_length)
+ .transpose()?;
+ let height = value_t!(matches, "size_y", String)
+ .or_none()?
+ .map(parse_length)
+ .transpose()?;
+
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()?;
@@ -805,8 +830,8 @@ fn parse_args() -> Result<Converter, Error> {
x: zoom.or(zoom_x).unwrap_or(1.0),
y: zoom.or(zoom_y).unwrap_or(1.0),
},
- width: value_t!(matches, "size_x", u32).or_none()?,
- height: value_t!(matches, "size_y", u32).or_none()?,
+ width,
+ height,
format,
export_id: value_t!(matches, "export_id", String)
.or_none()?
@@ -885,6 +910,40 @@ fn parse_color_string<T: AsRef<str> + std::fmt::Display>(s: T) -> Result<Color,
}
}
+fn is_absolute_unit(u: LengthUnit) -> bool {
+ use LengthUnit::*;
+
+ match u {
+ Percent | Em | Ex => false,
+ Px | In | Cm | Mm | Pt | Pc => true,
+ }
+}
+
+fn parse_length<N: Normalize>(s: String) -> Result<ULength<N>, clap::Error> {
+ <ULength<N> as Parse>::parse_str(&s)
+ .map_err(|_| {
+ let desc = format!(
+ "Invalid value: The argument '{}' can not be parsed as a length",
+ s
+ );
+ clap::Error::with_description(&desc, clap::ErrorKind::InvalidValue)
+ })
+ .and_then(|l| {
+ if is_absolute_unit(l.unit) {
+ Ok(l)
+ } else {
+ let desc = format!(
+ "Invalid value '{}': supported units are px, in, cm, mm, pt, pc",
+ s
+ );
+ Err(clap::Error::with_description(
+ &desc,
+ clap::ErrorKind::InvalidValue,
+ ))
+ }
+ })
+}
+
fn main() {
if let Err(e) = parse_args().and_then(|converter| converter.convert()) {
std::eprintln!("{}", e);
diff --git a/src/lib.rs b/src/lib.rs
index 825ac3ea..3e80ae82 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -250,4 +250,6 @@ pub mod doctest_only {
pub mod rsvg_convert_only {
pub use crate::c_api::handle::PathOrUrl;
pub use crate::c_api::sizing::LegacySize;
+ pub use crate::dpi::Dpi;
+ pub use crate::length::{Horizontal, Normalize, NormalizeParams, ULength, Validate, Vertical};
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]