summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorReizner Evgeniy <razrfalcon@gmail.com>2018-03-16 15:10:56 +0200
committerReizner Evgeniy <razrfalcon@gmail.com>2018-03-16 15:10:56 +0200
commitd3b63c807705503130d76c39f62a19cf2c410fef (patch)
treecc03cc5dd11d45f37bfb9b98db50296692e6d3f0
parentcbcb49dc6be03728e279e2cadbc7ce5b2aa44e31 (diff)
Require image size instead of image rect.
-rw-r--r--capi/include/resvg.h13
-rw-r--r--capi/src/lib.rs215
-rw-r--r--demo/svgview.cpp9
-rw-r--r--examples/cairo-capi/example.c4
-rw-r--r--examples/cairo-rs/src/main.rs10
-rw-r--r--src/convert/fill.rs2
-rw-r--r--src/convert/mod.rs2
-rw-r--r--src/convert/stroke.rs2
-rw-r--r--src/lib.rs1
-rw-r--r--src/render_cairo/mod.rs24
-rw-r--r--src/render_cairo/pattern.rs3
-rw-r--r--src/render_qt/mod.rs29
-rw-r--r--src/render_qt/pattern.rs3
-rw-r--r--src/tree/mod.rs26
-rw-r--r--src/utils.rs10
-rw-r--r--tools/rendersvg/src/main.rs3
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: &gtk::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));
}
}
diff --git a/src/lib.rs b/src/lib.rs
index a498055..eecf6f8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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()));
}