Skip to content

Commit ad721f7

Browse files
committed
Support floating point viewbox in resvg binary
Avoid rounding sizes for images until creating the pixmap, and always use the ceil for that to avoid truncating images. This requires a corresponding change to tiny-skia to add scale_by/scale_to_width/scale_to_height functions to tiny_skia_path::Size to match the implementations in IntSize.
1 parent cf024df commit ad721f7

File tree

1 file changed

+25
-20
lines changed

1 file changed

+25
-20
lines changed

crates/resvg/src/main.rs

+25-20
Original file line numberDiff line numberDiff line change
@@ -389,30 +389,29 @@ enum FitTo {
389389
/// Keep original size.
390390
Original,
391391
/// Scale to width.
392-
Width(u32),
392+
Width(f32),
393393
/// Scale to height.
394-
Height(u32),
394+
Height(f32),
395395
/// Scale to size.
396-
Size(u32, u32),
396+
Size(f32, f32),
397397
/// Zoom by factor.
398398
Zoom(f32),
399399
}
400400

401401
impl FitTo {
402-
fn fit_to_size(&self, size: tiny_skia::IntSize) -> Option<tiny_skia::IntSize> {
402+
fn fit_to_size(&self, size: tiny_skia::Size) -> Option<tiny_skia::Size> {
403403
match *self {
404404
FitTo::Original => Some(size),
405405
FitTo::Width(w) => size.scale_to_width(w),
406406
FitTo::Height(h) => size.scale_to_height(h),
407-
FitTo::Size(w, h) => tiny_skia::IntSize::from_wh(w, h).map(|s| size.scale_to(s)),
407+
FitTo::Size(w, h) => tiny_skia::Size::from_wh(w, h).map(|s| size.scale_to(s)),
408408
FitTo::Zoom(z) => size.scale_by(z),
409409
}
410410
}
411411

412-
fn fit_to_transform(&self, size: tiny_skia::IntSize) -> tiny_skia::Transform {
413-
let size1 = size.to_size();
414-
let size2 = match self.fit_to_size(size) {
415-
Some(v) => v.to_size(),
412+
fn fit_to_transform(&self, size1: tiny_skia::Size) -> tiny_skia::Transform {
413+
let size2 = match self.fit_to_size(size1) {
414+
Some(v) => v,
416415
None => return tiny_skia::Transform::default(),
417416
};
418417
tiny_skia::Transform::from_scale(
@@ -526,13 +525,13 @@ fn parse_args() -> Result<Args, String> {
526525
let mut default_size = usvg::Size::from_wh(100.0, 100.0).unwrap();
527526
if let (Some(w), Some(h)) = (args.width, args.height) {
528527
default_size = usvg::Size::from_wh(w as f32, h as f32).unwrap();
529-
fit_to = FitTo::Size(w, h);
528+
fit_to = FitTo::Size(w as f32, h as f32);
530529
} else if let Some(w) = args.width {
531530
default_size = usvg::Size::from_wh(w as f32, 100.0).unwrap();
532-
fit_to = FitTo::Width(w);
531+
fit_to = FitTo::Width(w as f32);
533532
} else if let Some(h) = args.height {
534533
default_size = usvg::Size::from_wh(100.0, h as f32).unwrap();
535-
fit_to = FitTo::Height(h);
534+
fit_to = FitTo::Height(h as f32);
536535
} else if let Some(z) = args.zoom {
537536
fit_to = FitTo::Zoom(z);
538537
}
@@ -681,19 +680,21 @@ fn render_svg(args: &Args, tree: &usvg::Tree) -> Result<tiny_skia::Pixmap, Strin
681680

682681
let size = args
683682
.fit_to
684-
.fit_to_size(bbox.size().to_int_size())
683+
.fit_to_size(bbox.size())
685684
.ok_or_else(|| "target size is zero".to_string())?;
686685

687686
// Unwrap is safe, because `size` is already valid.
688-
let mut pixmap = tiny_skia::Pixmap::new(size.width(), size.height()).unwrap();
687+
let mut pixmap =
688+
tiny_skia::Pixmap::new(size.width().ceil() as u32, size.height().ceil() as u32)
689+
.unwrap();
689690

690691
if !args.export_area_page {
691692
if let Some(background) = args.background {
692693
pixmap.fill(svg_to_skia_color(background));
693694
}
694695
}
695696

696-
let ts = args.fit_to.fit_to_transform(tree.size().to_int_size());
697+
let ts = args.fit_to.fit_to_transform(tree.size());
697698

698699
resvg::render_node(node, ts, &mut pixmap.as_mut());
699700

@@ -702,11 +703,13 @@ fn render_svg(args: &Args, tree: &usvg::Tree) -> Result<tiny_skia::Pixmap, Strin
702703

703704
let size = args
704705
.fit_to
705-
.fit_to_size(tree.size().to_int_size())
706+
.fit_to_size(tree.size())
706707
.ok_or_else(|| "target size is zero".to_string())?;
707708

708709
// Unwrap is safe, because `size` is already valid.
709-
let mut page_pixmap = tiny_skia::Pixmap::new(size.width(), size.height()).unwrap();
710+
let mut page_pixmap =
711+
tiny_skia::Pixmap::new(size.width().ceil() as u32, size.height().ceil() as u32)
712+
.unwrap();
710713

711714
if let Some(background) = args.background {
712715
page_pixmap.fill(svg_to_skia_color(background));
@@ -727,17 +730,19 @@ fn render_svg(args: &Args, tree: &usvg::Tree) -> Result<tiny_skia::Pixmap, Strin
727730
} else {
728731
let size = args
729732
.fit_to
730-
.fit_to_size(tree.size().to_int_size())
733+
.fit_to_size(tree.size())
731734
.ok_or_else(|| "target size is zero".to_string())?;
732735

733736
// Unwrap is safe, because `size` is already valid.
734-
let mut pixmap = tiny_skia::Pixmap::new(size.width(), size.height()).unwrap();
737+
let mut pixmap =
738+
tiny_skia::Pixmap::new(size.width().ceil() as u32, size.height().ceil() as u32)
739+
.unwrap();
735740

736741
if let Some(background) = args.background {
737742
pixmap.fill(svg_to_skia_color(background));
738743
}
739744

740-
let ts = args.fit_to.fit_to_transform(tree.size().to_int_size());
745+
let ts = args.fit_to.fit_to_transform(tree.size());
741746

742747
resvg::render(tree, ts, &mut pixmap.as_mut());
743748

0 commit comments

Comments
 (0)