diff options
author | Reizner Evgeniy <razrfalcon@gmail.com> | 2018-03-16 15:10:56 +0200 |
---|---|---|
committer | Reizner Evgeniy <razrfalcon@gmail.com> | 2018-03-16 15:10:56 +0200 |
commit | d3b63c807705503130d76c39f62a19cf2c410fef (patch) | |
tree | cc03cc5dd11d45f37bfb9b98db50296692e6d3f0 | |
parent | cbcb49dc6be03728e279e2cadbc7ce5b2aa44e31 (diff) |
Require image size instead of image rect.
-rw-r--r-- | capi/include/resvg.h | 13 | ||||
-rw-r--r-- | capi/src/lib.rs | 215 | ||||
-rw-r--r-- | demo/svgview.cpp | 9 | ||||
-rw-r--r-- | examples/cairo-capi/example.c | 4 | ||||
-rw-r--r-- | examples/cairo-rs/src/main.rs | 10 | ||||
-rw-r--r-- | src/convert/fill.rs | 2 | ||||
-rw-r--r-- | src/convert/mod.rs | 2 | ||||
-rw-r--r-- | src/convert/stroke.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/render_cairo/mod.rs | 24 | ||||
-rw-r--r-- | src/render_cairo/pattern.rs | 3 | ||||
-rw-r--r-- | src/render_qt/mod.rs | 29 | ||||
-rw-r--r-- | src/render_qt/pattern.rs | 3 | ||||
-rw-r--r-- | src/tree/mod.rs | 26 | ||||
-rw-r--r-- | src/utils.rs | 10 | ||||
-rw-r--r-- | tools/rendersvg/src/main.rs | 3 |
16 files changed, 189 insertions, 167 deletions
diff --git a/capi/include/resvg.h b/capi/include/resvg.h index e01c30b..b301db9 100644 --- a/capi/include/resvg.h +++ b/capi/include/resvg.h @@ -49,6 +49,11 @@ typedef struct resvg_rect { double height; } resvg_rect; +typedef struct resvg_size { + unsigned int width; + unsigned int height; +} resvg_size; + typedef struct resvg_transform { double a; double b; @@ -128,12 +133,12 @@ bool resvg_cairo_render_to_image(const resvg_render_tree *rtree, void resvg_cairo_render_to_canvas(const resvg_render_tree *rtree, const resvg_options *opt, - resvg_rect view, + resvg_size size, cairo_t *cr); void resvg_cairo_render_to_canvas_by_id(const resvg_render_tree *rtree, const resvg_options *opt, - resvg_rect view, + resvg_size size, const char *id, void *painter); #endif @@ -150,12 +155,12 @@ bool resvg_qt_render_to_image(const resvg_render_tree *rtree, void resvg_qt_render_to_canvas(const resvg_render_tree *rtree, const resvg_options *opt, - resvg_rect view, + resvg_size size, void *painter); void resvg_qt_render_to_canvas_by_id(const resvg_render_tree *rtree, const resvg_options *opt, - resvg_rect view, + resvg_size size, const char *id, void *painter); #endif diff --git a/capi/src/lib.rs b/capi/src/lib.rs index ec50e6c..d4c154b 100644 --- a/capi/src/lib.rs +++ b/capi/src/lib.rs @@ -74,6 +74,12 @@ pub struct resvg_rect { } #[repr(C)] +pub struct resvg_size { + pub width: u32, + pub height: u32, +} + +#[repr(C)] pub struct resvg_transform { pub a: f64, pub b: f64, @@ -138,54 +144,6 @@ fn log_format(out: fern::FormatCallback, message: &fmt::Arguments, record: &log: )) } -fn to_native_opt(opt: &resvg_options) -> resvg::Options { - let mut path: Option<path::PathBuf> = None; - - if !opt.path.is_null() { - if let Some(p) = cstr_to_str(opt.path) { - if !p.is_empty() { - path = Some(p.into()); - } - } - }; - - let fit_to = match opt.fit_to.kind { - resvg_fit_to_type::RESVG_FIT_TO_ORIGINAL => { - resvg::FitTo::Original - } - resvg_fit_to_type::RESVG_FIT_TO_WIDTH => { - assert!(opt.fit_to.value > 0.0); - resvg::FitTo::Width(opt.fit_to.value as u32) - } - resvg_fit_to_type::RESVG_FIT_TO_HEIGHT => { - assert!(opt.fit_to.value > 0.0); - resvg::FitTo::Height(opt.fit_to.value as u32) - } - resvg_fit_to_type::RESVG_FIT_TO_ZOOM => { - assert!(opt.fit_to.value > 0.0); - resvg::FitTo::Zoom(opt.fit_to.value) - } - }; - - let background = if opt.draw_background { - Some(resvg::tree::Color::new( - opt.background.r, - opt.background.g, - opt.background.b, - )) - } else { - None - }; - - resvg::Options { - path, - dpi: opt.dpi, - fit_to, - background, - keep_named_groups: opt.keep_named_groups, - } -} - #[no_mangle] pub extern fn resvg_parse_rtree_from_file( file_path: *const c_char, @@ -246,15 +204,6 @@ pub extern fn resvg_rtree_destroy(rtree: *mut resvg_render_tree) { }; } -fn cstr_to_str(text: *const c_char) -> Option<&'static str> { - let text = unsafe { - assert!(!text.is_null()); - CStr::from_ptr(text) - }; - - text.to_str().ok() -} - #[cfg(feature = "qt-backend")] #[no_mangle] pub extern fn resvg_qt_render_to_image( @@ -312,7 +261,7 @@ fn render_to_image( pub extern fn resvg_qt_render_to_canvas( rtree: *const resvg_render_tree, opt: *const resvg_options, - view: resvg_rect, + size: resvg_size, painter: *mut qt::qtc_qpainter, ) { let rtree = unsafe { @@ -321,63 +270,68 @@ pub extern fn resvg_qt_render_to_canvas( }; let painter = unsafe { qt::Painter::from_raw(painter) }; - let rect = resvg::Rect::from_xywh(view.x, view.y, view.width, view.height); - + let size = resvg::ScreenSize::new(size.width, size.height); let opt = to_native_opt(unsafe { &*opt }); - resvg::render_qt::render_to_canvas(&rtree.0, &opt, rect, &painter); + resvg::render_qt::render_to_canvas(&rtree.0, &opt, size, &painter); } -#[cfg(feature = "qt-backend")] +#[cfg(feature = "cairo-backend")] #[no_mangle] -pub extern fn resvg_qt_render_to_canvas_by_id( +pub extern fn resvg_cairo_render_to_canvas( rtree: *const resvg_render_tree, opt: *const resvg_options, - view: resvg_rect, - id: *const c_char, - painter: *mut qt::qtc_qpainter, + size: resvg_size, + cr: *mut cairo_sys::cairo_t, ) { let rtree = unsafe { assert!(!rtree.is_null()); &*rtree }; - let painter = unsafe { qt::Painter::from_raw(painter) }; - let rect = resvg::Rect::from_xywh(view.x, view.y, view.width, view.height); + use glib::translate::FromGlibPtrNone; - let opt = to_native_opt(unsafe { &*opt }); + let cr = unsafe { cairo::Context::from_glib_none(cr) }; + let size = resvg::ScreenSize::new(size.width, size.height); - let id = match cstr_to_str(id) { - Some(v) => v, - None => return, - }; + let opt = to_native_opt(unsafe { &*opt }); - if let Some(node) = node_by_id(&rtree.0, id) { - resvg::render_qt::render_node_to_canvas(node, &opt, rect.to_screen_size(), &painter); - } + resvg::render_cairo::render_to_canvas(&rtree.0, &opt, size, &cr); } -#[cfg(feature = "cairo-backend")] +#[cfg(feature = "qt-backend")] #[no_mangle] -pub extern fn resvg_cairo_render_to_canvas( +pub extern fn resvg_qt_render_to_canvas_by_id( rtree: *const resvg_render_tree, opt: *const resvg_options, - view: resvg_rect, - cr: *mut cairo_sys::cairo_t, + size: resvg_size, + id: *const c_char, + painter: *mut qt::qtc_qpainter, ) { let rtree = unsafe { assert!(!rtree.is_null()); &*rtree }; - use glib::translate::FromGlibPtrNone; + let painter = unsafe { qt::Painter::from_raw(painter) }; + let size = resvg::ScreenSize::new(size.width, size.height); + let opt = to_native_opt(unsafe { &*opt }); - let cr = unsafe { cairo::Context::from_glib_none(cr) }; - let rect = resvg::Rect::from_xywh(view.x, view.y, view.width, view.height); + let id = match cstr_to_str(id) { + Some(v) => v, + None => return, + }; - let opt = to_native_opt(unsafe { &*opt }); + if let Some(node) = rtree.0.node_by_svg_id(id) { + if let Some(bbox) = resvg::render_qt::calc_node_bbox(node, &opt) { + let vbox = tree::ViewBox { + rect: bbox, + .. tree::ViewBox::default() + }; - resvg::render_cairo::render_to_canvas(&rtree.0, &opt, rect, &cr); + resvg::render_qt::render_node_to_canvas(node, &opt, vbox, size, &painter); + } + } } #[cfg(feature = "cairo-backend")] @@ -385,7 +339,7 @@ pub extern fn resvg_cairo_render_to_canvas( pub extern fn resvg_cairo_render_to_canvas_by_id( rtree: *const resvg_render_tree, opt: *const resvg_options, - view: resvg_rect, + size: resvg_size, id: *const c_char, cr: *mut cairo_sys::cairo_t, ) { @@ -402,12 +356,19 @@ pub extern fn resvg_cairo_render_to_canvas_by_id( use glib::translate::FromGlibPtrNone; let cr = unsafe { cairo::Context::from_glib_none(cr) }; - let rect = resvg::Rect::from_xywh(view.x, view.y, view.width, view.height); + let size = resvg::ScreenSize::new(size.width, size.height); let opt = to_native_opt(unsafe { &*opt }); - if let Some(node) = node_by_id(&rtree.0, id) { - resvg::render_cairo::render_node_to_canvas(node, &opt, rect.to_screen_size(), &cr); + if let Some(node) = rtree.0.node_by_svg_id(id) { + if let Some(bbox) = resvg::render_cairo::calc_node_bbox(node, &opt) { + let vbox = tree::ViewBox { + rect: bbox, + .. tree::ViewBox::default() + }; + + resvg::render_cairo::render_node_to_canvas(node, &opt, vbox, size, &cr); + } } } @@ -482,7 +443,7 @@ fn get_node_bbox( let opt = to_native_opt(unsafe { &*opt }); - match node_by_id(&rtree.0, id) { + match rtree.0.node_by_svg_id(id) { Some(node) => { if let Some(r) = backend.calc_node_bbox(node, &opt) { unsafe { @@ -517,16 +478,12 @@ pub extern fn resvg_node_exists( } }; - if id.is_empty() { - return false; - } - let rtree = unsafe { assert!(!rtree.is_null()); &*rtree }; - node_by_id(&rtree.0, id).is_some() + rtree.0.node_by_svg_id(id).is_some() } #[no_mangle] @@ -543,16 +500,12 @@ pub extern fn resvg_get_node_transform( } }; - if id.is_empty() { - return false; - } - let rtree = unsafe { assert!(!rtree.is_null()); &*rtree }; - if let Some(node) = node_by_id(&rtree.0, id) { + if let Some(node) = rtree.0.node_by_svg_id(id) { let abs_ts = resvg::utils::abs_transform(node); unsafe { @@ -570,17 +523,59 @@ pub extern fn resvg_get_node_transform( false } -fn node_by_id<'a>( - rtree: &'a resvg::tree::RenderTree, - id: &str -) -> Option<resvg::tree::NodeRef<'a>> { - for node in rtree.root().descendants() { - if !rtree.is_in_defs(node) { - if node.svg_id() == id { - return Some(node); +fn cstr_to_str(text: *const c_char) -> Option<&'static str> { + let text = unsafe { + assert!(!text.is_null()); + CStr::from_ptr(text) + }; + + text.to_str().ok() +} + +fn to_native_opt(opt: &resvg_options) -> resvg::Options { + let mut path: Option<path::PathBuf> = None; + + if !opt.path.is_null() { + if let Some(p) = cstr_to_str(opt.path) { + if !p.is_empty() { + path = Some(p.into()); } } - } + }; - None + let fit_to = match opt.fit_to.kind { + resvg_fit_to_type::RESVG_FIT_TO_ORIGINAL => { + resvg::FitTo::Original + } + resvg_fit_to_type::RESVG_FIT_TO_WIDTH => { + assert!(opt.fit_to.value > 0.0); + resvg::FitTo::Width(opt.fit_to.value as u32) + } + resvg_fit_to_type::RESVG_FIT_TO_HEIGHT => { + assert!(opt.fit_to.value > 0.0); + resvg::FitTo::Height(opt.fit_to.value as u32) + } + resvg_fit_to_type::RESVG_FIT_TO_ZOOM => { + assert!(opt.fit_to.value > 0.0); + resvg::FitTo::Zoom(opt.fit_to.value) + } + }; + + let background = if opt.draw_background { + Some(resvg::tree::Color::new( + opt.background.r, + opt.background.g, + opt.background.b, + )) + } else { + None + }; + + resvg::Options { + path, + dpi: opt.dpi, + fit_to, + background, + keep_named_groups: opt.keep_named_groups, + } } diff --git a/demo/svgview.cpp b/demo/svgview.cpp index 0476d8c..5d7da22 100644 --- a/demo/svgview.cpp +++ b/demo/svgview.cpp @@ -86,8 +86,8 @@ void SvgView::setRenderToImage(bool flag) QPainter p; p.begin(&img); p.setRenderHint(QPainter::Antialiasing); - resvg_rect r { 0, 0, width, height }; - resvg_qt_render_to_canvas(m_rtree, m_opt, r, &p); + resvg_size s { (uint)width, (uint)height }; + resvg_qt_render_to_canvas(m_rtree, m_opt, s, &p); p.end(); img.setDevicePixelRatio(ratio); @@ -216,8 +216,9 @@ void SvgView::paintEvent(QPaintEvent *e) y = (r.height() - img_height)/2; } - resvg_rect rr { x, y, img_width, img_height }; - resvg_qt_render_to_canvas(m_rtree, m_opt, rr, &p); + p.translate(x, y); + resvg_size s { (uint)img_width, (uint)img_height }; + resvg_qt_render_to_canvas(m_rtree, m_opt, s, &p); p.setTransform(QTransform()); imgRect = QRect(x, y, img_width, img_height); diff --git a/examples/cairo-capi/example.c b/examples/cairo-capi/example.c index 5d0aeb6..2bf36b7 100644 --- a/examples/cairo-capi/example.c +++ b/examples/cairo-capi/example.c @@ -14,8 +14,8 @@ draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data) gtk_widget_get_allocation(widget, &alloc); if (rtree) { - resvg_rect r = { 0, 0, alloc.width, alloc.height }; - resvg_cairo_render_to_canvas(rtree, &opt, r, cr); + resvg_size s = { alloc.width, alloc.height }; + resvg_cairo_render_to_canvas(rtree, &opt, s, cr); } return FALSE; diff --git a/examples/cairo-rs/src/main.rs b/examples/cairo-rs/src/main.rs index 1519c7d..fdbeb1b 100644 --- a/examples/cairo-rs/src/main.rs +++ b/examples/cairo-rs/src/main.rs @@ -12,8 +12,6 @@ use gio::prelude::*; use gtk::prelude::*; use gtk::DrawingArea; -use resvg::RectExt; - // make moving clones into closures more convenient macro_rules! clone { (@param _) => ( _ ); @@ -64,11 +62,11 @@ fn build_ui(application: >k::Application, file_path: &Path) { let rtree = resvg::parse_rtree_from_file(file_path, &opt).unwrap(); drawing_area.connect_draw(move |w, cr| { - let r = resvg::Rect::from_xywh( - 0.0, 0.0, - w.get_allocated_width() as f64, w.get_allocated_height() as f64 + let s = resvg::ScreenSize::new( + w.get_allocated_width() as u32, + w.get_allocated_height() as u32, ); - resvg::render_cairo::render_to_canvas(&rtree, &opt, r, cr); + resvg::render_cairo::render_to_canvas(&rtree, &opt, s, cr); Inhibit(false) }); diff --git a/src/convert/fill.rs b/src/convert/fill.rs index 68f19b6..59332bc 100644 --- a/src/convert/fill.rs +++ b/src/convert/fill.rs @@ -36,7 +36,7 @@ pub fn convert( let mut p = None; if link.is_gradient() || link.is_tag_name(EId::Pattern) { - if let Some(id) = rtree.defs_id(&link.id()) { + if let Some(id) = rtree.defs_by_svg_id(&link.id()) { p = Some(tree::Paint::Link(id)); } } diff --git a/src/convert/mod.rs b/src/convert/mod.rs index 4412340..3f06889 100644 --- a/src/convert/mod.rs +++ b/src/convert/mod.rs @@ -153,7 +153,7 @@ pub(super) fn convert_nodes( let mut v = None; if let &AValue::FuncLink(ref link) = av { if link.is_tag_name(EId::ClipPath) { - if let Some(idx) = rtree.defs_id(&link.id()) { + if let Some(idx) = rtree.defs_by_svg_id(&link.id()) { v = Some(idx); } } diff --git a/src/convert/stroke.rs b/src/convert/stroke.rs index 9494e35..c864b54 100644 --- a/src/convert/stroke.rs +++ b/src/convert/stroke.rs @@ -48,7 +48,7 @@ pub fn convert( AValue::FuncLink(ref link) => { let mut p = None; if link.is_gradient() || link.is_tag_name(EId::Pattern) { - if let Some(id) = rtree.defs_id(&link.id()) { + if let Some(id) = rtree.defs_by_svg_id(&link.id()) { p = Some(tree::Paint::Link(id)); } } @@ -31,6 +31,7 @@ extern crate ego_tree; #[macro_use] extern crate log; #[macro_use] extern crate error_chain; +// TODO: move to modules #[cfg(feature = "cairo-backend")] pub extern crate cairo; #[cfg(feature = "cairo-backend")] extern crate pango; #[cfg(feature = "cairo-backend")] extern crate pangocairo; diff --git a/src/render_cairo/mod.rs b/src/render_cairo/mod.rs index 9df7d6a..858f3ec 100644 --- a/src/render_cairo/mod.rs +++ b/src/render_cairo/mod.rs @@ -153,7 +153,7 @@ pub fn render_node_to_image( return Err(ErrorKind::NoCanvas.into()); }; - let (surface, img_view) = create_surface(node_bbox.to_screen_size(), opt)?; + let (surface, img_size) = create_surface(node_bbox.to_screen_size(), opt)?; let vbox = tree::ViewBox { rect: node_bbox, @@ -168,8 +168,7 @@ pub fn render_node_to_image( cr.paint(); } - apply_viewbox_transform(vbox, img_view, &cr); - render_node_to_canvas(node, opt, img_view.to_screen_size(), &cr); + render_node_to_canvas(node, opt, vbox, img_size, &cr); Ok(surface) } @@ -178,20 +177,23 @@ pub fn render_node_to_image( pub fn render_to_canvas( rtree: &tree::RenderTree, opt: &Options, - img_view: Rect, + img_size: ScreenSize, cr: &cairo::Context, ) { - apply_viewbox_transform(rtree.svg_node().view_box, img_view, cr); - render_group(rtree.root(), opt, img_view.to_screen_size(), &cr); + apply_viewbox_transform(rtree.svg_node().view_box, img_size, cr); + render_group(rtree.root(), opt, img_size, &cr); } /// Renders SVG node to canvas. pub fn render_node_to_canvas( node: tree::NodeRef, opt: &Options, + view_box: tree::ViewBox, img_size: ScreenSize, cr: &cairo::Context, ) { + apply_viewbox_transform(view_box, img_size, &cr); + let curr_ts = cr.get_matrix(); let mut ts = utils::abs_transform(node); ts.append(&node.transform()); @@ -204,25 +206,23 @@ pub fn render_node_to_canvas( fn create_surface( size: ScreenSize, opt: &Options, -) -> Result<(cairo::ImageSurface, Rect)> { +) -> Result<(cairo::ImageSurface, ScreenSize)> { let img_size = utils::fit_to(size, opt.fit_to); debug_assert!(!img_size.is_empty_or_negative()); let surface = try_create_surface!(img_size, Err(ErrorKind::NoCanvas.into())); - let img_view = Rect::new(Point::new(0.0, 0.0), img_size.to_f64()); - - Ok((surface, img_view)) + Ok((surface, img_size)) } /// Applies viewbox transformation to the painter. fn apply_viewbox_transform( view_box: tree::ViewBox, - img_view: Rect, + img_size: ScreenSize, cr: &cairo::Context, ) { let ts = { - let (dx, dy, sx, sy) = utils::view_box_transform(view_box, img_view); + let (dx, dy, sx, sy) = utils::view_box_transform(view_box, img_size); cairo::Matrix::new(sx, 0.0, 0.0, sy, dx, dy) }; cr.transform(ts); diff --git a/src/render_cairo/pattern.rs b/src/render_cairo/pattern.rs index 8c75659..d25c398 100644 --- a/src/render_cairo/pattern.rs +++ b/src/render_cairo/pattern.rs @@ -46,8 +46,7 @@ pub fn apply( sub_cr.transform(cairo::Matrix::new(sx, 0.0, 0.0, sy, 0.0, 0.0)); if let Some(vbox) = pattern.view_box { - let img_view = Rect::from_xywh(0.0, 0.0, r.width(), r.height()); - let (dx, dy, sx2, sy2) = utils::view_box_transform(vbox, img_view); + let (dx, dy, sx2, sy2) = utils::view_box_transform(vbox, r.to_screen_size()); sub_cr.transform(cairo::Matrix::new(sx2, 0.0, 0.0, sy2, dx, dy)); } else if pattern.content_units == tree::Units::ObjectBoundingBox { // 'Note that this attribute has no effect if attribute `viewBox` is specified.' diff --git a/src/render_qt/mod.rs b/src/render_qt/mod.rs index 1bd9ae9..0423a63 100644 --- a/src/render_qt/mod.rs +++ b/src/render_qt/mod.rs @@ -109,10 +109,10 @@ pub fn render_to_image( rtree: &tree::RenderTree, opt: &Options, ) -> Result<qt::Image> { - let (img, img_view) = create_image(rtree.svg_node().size.to_screen_size(), opt)?; + let (img, img_size) = create_image(rtree.svg_node().size.to_screen_size(), opt)?; let painter = qt::Painter::new(&img); - render_to_canvas(rtree, opt, img_view, &painter); + render_to_canvas(rtree, opt, img_size, &painter); painter.end(); Ok(img) @@ -126,6 +126,7 @@ pub fn render_node_to_image( let node_bbox = if let Some(bbox) = calc_node_bbox(node, opt) { bbox } else { + // TODO: custom error warn!("Node {:?} has zero size.", node.svg_id()); return Err(ErrorKind::NoCanvas.into()); }; @@ -135,11 +136,10 @@ pub fn render_node_to_image( .. tree::ViewBox::default() }; - let (img, img_view) = create_image(node_bbox.size.to_screen_size(), opt)?; + let (img, img_size) = create_image(node_bbox.size.to_screen_size(), opt)?; let painter = qt::Painter::new(&img); - apply_viewbox_transform(vbox, img_view, &painter); - render_node_to_canvas(node, opt, img_view.to_screen_size(), &painter); + render_node_to_canvas(node, opt, vbox, img_size, &painter); painter.end(); Ok(img) @@ -148,7 +148,7 @@ pub fn render_node_to_image( fn create_image( size: ScreenSize, opt: &Options, -) -> Result<(qt::Image, Rect)> { +) -> Result<(qt::Image, ScreenSize)> { let img_size = utils::fit_to(size, opt.fit_to); debug_assert!(!img_size.is_empty_or_negative()); @@ -163,29 +163,30 @@ fn create_image( } img.set_dpi(opt.dpi); - let img_view = Rect::new(Point::new(0.0, 0.0), img_size.to_f64()); - - Ok((img, img_view)) + Ok((img, img_size)) } /// Renders SVG to canvas. pub fn render_to_canvas( rtree: &tree::RenderTree, opt: &Options, - img_view: Rect, + img_size: ScreenSize, painter: &qt::Painter, ) { - apply_viewbox_transform(rtree.svg_node().view_box, img_view, painter); - render_group(rtree.root(), opt, img_view.to_screen_size(), &painter); + apply_viewbox_transform(rtree.svg_node().view_box, img_size, painter); + render_group(rtree.root(), opt, img_size, &painter); } /// Renders SVG node to canvas. pub fn render_node_to_canvas( node: tree::NodeRef, opt: &Options, + view_box: tree::ViewBox, img_size: ScreenSize, painter: &qt::Painter, ) { + apply_viewbox_transform(view_box, img_size, &painter); + let curr_ts = painter.get_transform(); let mut ts = utils::abs_transform(node); ts.append(&node.transform()); @@ -198,11 +199,11 @@ pub fn render_node_to_canvas( /// Applies viewbox transformation to the painter. pub fn apply_viewbox_transform( view_box: tree::ViewBox, - img_view: Rect, + img_size: ScreenSize, painter: &qt::Painter, ) { let ts = { - let (dx, dy, sx, sy) = utils::view_box_transform(view_box, img_view); + let (dx, dy, sx, sy) = utils::view_box_transform(view_box, img_size); qt::Transform::new(sx, 0.0, 0.0, sy, dx, dy) }; painter.apply_transform(&ts); diff --git a/src/render_qt/pattern.rs b/src/render_qt/pattern.rs index 7e37bd8..160e36d 100644 --- a/src/render_qt/pattern.rs +++ b/src/render_qt/pattern.rs @@ -45,8 +45,7 @@ pub fn apply( p.apply_transform(&qt::Transform::new(sx, 0.0, 0.0, sy, 0.0, 0.0)); if let Some(vbox) = pattern.view_box { - let img_view = Rect::from_xywh(0.0, 0.0, r.width(), r.height()); - let (dx, dy, sx2, sy2) = utils::view_box_transform(vbox, img_view); + let (dx, dy, sx2, sy2) = utils::view_box_transform(vbox, r.to_screen_size()); p.apply_transform(&qt::Transform::new(sx2, 0.0, 0.0, sy2, dx, dy)); } else if pattern.content_units == tree::Units::ObjectBoundingBox { // 'Note that this attribute has no effect if attribute `viewBox` is specified.' diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 589a2d2..8a69be7 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -64,7 +64,13 @@ pub trait TreeExt { fn defs_at(&self, id: NodeId) -> Option<NodeRef>; /// Searches for `NodeId` in `Defs` children by ID. - fn defs_id(&self, id: &str) -> Option<NodeId>; + fn defs_by_svg_id(&self, id: &str) -> Option<NodeId>; + + /// Returns renderable node by ID. + /// + /// If an empty ID is provided, than this method will always return `None`. + /// Even if tree has nodes with empty ID. + fn node_by_svg_id(&self, id: &str) -> Option<NodeRef>; /// Converts the document to `svgdom::Document`. /// @@ -117,7 +123,7 @@ impl TreeExt for RenderTree { None } - fn defs_id(&self, id: &str) -> Option<NodeId> { + fn defs_by_svg_id(&self, id: &str) -> Option<NodeId> { for n in self.defs().children() { if n.svg_id() == id { return Some(n.id()); @@ -128,6 +134,22 @@ impl TreeExt for RenderTree { None } + fn node_by_svg_id(&self, id: &str) -> Option<NodeRef> { + if id.is_empty() { + return None; + } + + for node in self.root().descendants() { + if !self.is_in_defs(node) { + if node.svg_id() == id { + return Some(node); + } + } + } + + None + } + fn to_svgdom(&self) -> svgdom::Document { dump::conv_doc(self) } diff --git a/src/utils.rs b/src/utils.rs index 02f3d44..ce49f89 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -43,11 +43,11 @@ pub fn fit_to(size: ScreenSize, fit: FitTo) -> ScreenSize { /// - offset by Y axis /// - scale by X axis /// - scale by Y axis -pub fn view_box_transform(view_box: tree::ViewBox, img_view: Rect) -> (f64, f64, f64, f64) { +pub fn view_box_transform(view_box: tree::ViewBox, img_size: ScreenSize) -> (f64, f64, f64, f64) { let vr = view_box.rect; - let sx = img_view.width() / vr.width(); - let sy = img_view.height() / vr.height(); + let sx = img_size.width as f64 / vr.width(); + let sy = img_size.height as f64 / vr.height(); let (sx, sy) = if view_box.aspect.align == tree::Align::None { (sx, sy) @@ -63,8 +63,8 @@ pub fn view_box_transform(view_box: tree::ViewBox, img_view: Rect) -> (f64, f64, let x = -vr.x() * sx; let y = -vr.y() * sy; - let w = img_view.width() - vr.width() * sx; - let h = img_view.height() - vr.height() * sy; + let w = img_size.width as f64 - vr.width() * sx; + let h = img_size.height as f64 - vr.height() * sy; let pos = aligned_pos(view_box.aspect.align, x, y, w, h); diff --git a/tools/rendersvg/src/main.rs b/tools/rendersvg/src/main.rs index 4fe16fb..21e7197 100644 --- a/tools/rendersvg/src/main.rs +++ b/tools/rendersvg/src/main.rs @@ -125,7 +125,8 @@ fn process() -> Result<(), Error> { if let Some(ref out_png) = args.out_png { let img = if let Some(ref id) = args.export_id { if let Some(node) = rtree.root().descendants().find(|n| n.svg_id() == id) { - args.backend.render_node_to_image(node, &opt) + run_task(args.perf, "Rendering", + || args.backend.render_node_to_image(node, &opt)) } else { return Err(Error::InvalidId(id.clone())); } |