diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | capi/include/ResvgQt.h | 17 | ||||
-rw-r--r-- | capi/include/resvg.h | 14 | ||||
-rw-r--r-- | capi/qtests/tst_resvgqt.cpp | 24 | ||||
-rw-r--r-- | capi/qtests/vb.svg | 3 | ||||
-rw-r--r-- | capi/src/lib.rs | 33 | ||||
-rw-r--r-- | usvg/src/tree/mod.rs | 2 |
7 files changed, 90 insertions, 5 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index adddcf5..1eba0ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ This changelog also contains important changes in dependencies. - `shape-rendering`, `text-rendering` and `image-rendering` support. - The `arithmetic` operator for `feComposite`. - (usvg) `--quiet` argument. +- (c-api) `resvg_get_image_bbox`. +- (qt-api) `ResvgRenderer::boundingBox`. ### Changed - (resvg) Do not rescale images before rendering. This is faster and better. diff --git a/capi/include/ResvgQt.h b/capi/include/ResvgQt.h index d4516fc..53b44d7 100644 --- a/capi/include/ResvgQt.h +++ b/capi/include/ResvgQt.h @@ -216,6 +216,11 @@ public: QRectF boundsOnElement(const QString &id) const; /** + * @brief Returns bounding rectangle of a whole image. + */ + QRectF boundingBox() const; + + /** * @brief Returns \b true if element with such an ID exists. */ bool elementExists(const QString &id) const; @@ -380,6 +385,18 @@ inline QRectF ResvgRenderer::boundsOnElement(const QString &id) const return QRectF(); } +inline QRectF ResvgRenderer::boundingBox() const +{ + if (!d->tree) + return QRectF(); + + resvg_rect bbox; + if (resvg_get_image_bbox(d->tree, &bbox)) + return QRectF(bbox.x, bbox.y, bbox.height, bbox.width); + + return QRectF(); +} + inline bool ResvgRenderer::elementExists(const QString &id) const { if (!d->tree) diff --git a/capi/include/resvg.h b/capi/include/resvg.h index 1a5bf4d..8702978 100644 --- a/capi/include/resvg.h +++ b/capi/include/resvg.h @@ -301,6 +301,8 @@ bool resvg_is_image_empty(const resvg_render_tree *tree); /** * @brief Returns an image size. * + * The size of a canvas that required to render this SVG. + * * @param tree Render tree. * @return Image size. */ @@ -315,6 +317,18 @@ resvg_size resvg_get_image_size(const resvg_render_tree *tree); resvg_rect resvg_get_image_viewbox(const resvg_render_tree *tree); /** + * @brief Returns an image bounding box. + * + * Can be smaller or bigger than a \b viewbox. + * + * @param tree Render tree. + * @param bbox Image's bounding box. + * @return \b false if an image has no elements. + */ +bool resvg_get_image_bbox(const resvg_render_tree *tree, + resvg_rect *bbox); + +/** * @brief Returns \b true if a renderable node with such an ID exists. * * @param tree Render tree. diff --git a/capi/qtests/tst_resvgqt.cpp b/capi/qtests/tst_resvgqt.cpp index 72e8dec..c5bec64 100644 --- a/capi/qtests/tst_resvgqt.cpp +++ b/capi/qtests/tst_resvgqt.cpp @@ -15,6 +15,9 @@ private Q_SLOTS: void test_renderFile(); + void test_imageSize(); + void test_imageViewBox(); + void test_imageBoundingBox(); void test_elementExists(); void test_transformForElement(); }; @@ -66,6 +69,27 @@ void ResvgQtTests::test_renderFile() #endif } +void ResvgQtTests::test_imageSize() +{ + ResvgRenderer render(localPath("vb.svg")); + QVERIFY(!render.isEmpty()); + QCOMPARE(render.defaultSize(), QSize(200, 400)); +} + +void ResvgQtTests::test_imageViewBox() +{ + ResvgRenderer render(localPath("vb.svg")); + QVERIFY(!render.isEmpty()); + QCOMPARE(render.viewBox(), QRect(50, 100, 200, 400)); +} + +void ResvgQtTests::test_imageBoundingBox() +{ + ResvgRenderer render(localPath("test.svg")); + QVERIFY(!render.isEmpty()); + QCOMPARE(render.boundingBox(), QRect(20, 20, 160, 160)); +} + void ResvgQtTests::test_elementExists() { ResvgRenderer render(localPath("test.svg")); diff --git a/capi/qtests/vb.svg b/capi/qtests/vb.svg new file mode 100644 index 0000000..7049b09 --- /dev/null +++ b/capi/qtests/vb.svg @@ -0,0 +1,3 @@ +<svg id="svg1" viewBox="50 100 200 400" xmlns="http://www.w3.org/2000/svg"> + <circle id="circle1" cx="80" cy="100" r="40" fill="green" transform="scale(2)"/> +</svg> diff --git a/capi/src/lib.rs b/capi/src/lib.rs index 3d31a7f..08d5dac 100644 --- a/capi/src/lib.rs +++ b/capi/src/lib.rs @@ -438,6 +438,20 @@ pub extern "C" fn resvg_cairo_render_to_canvas_by_id( } #[no_mangle] +pub extern "C" fn resvg_is_image_empty( + tree: *const resvg_render_tree, +) -> bool { + let tree = unsafe { + assert!(!tree.is_null()); + &*tree + }; + + // The root/svg node should have at least two children. + // The first child is `defs` and it always present. + tree.0.root().children().count() > 1 +} + +#[no_mangle] pub extern "C" fn resvg_get_image_size( tree: *const resvg_render_tree, ) -> resvg_size { @@ -473,18 +487,29 @@ pub extern "C" fn resvg_get_image_viewbox( } } + #[no_mangle] -pub extern "C" fn resvg_is_image_empty( +pub extern "C" fn resvg_get_image_bbox( tree: *const resvg_render_tree, + bbox: *mut resvg_rect, ) -> bool { let tree = unsafe { assert!(!tree.is_null()); &*tree }; - // The root/svg node should have at least two children. - // The first child is `defs` and it always present. - tree.0.root().children().count() > 1 + if let Some(r) = tree.0.root().calculate_bbox() { + unsafe { + (*bbox).x = r.x(); + (*bbox).y = r.y(); + (*bbox).width = r.width(); + (*bbox).height = r.height(); + } + + true + } else { + false + } } #[no_mangle] diff --git a/usvg/src/tree/mod.rs b/usvg/src/tree/mod.rs index b0ce808..d6898d9 100644 --- a/usvg/src/tree/mod.rs +++ b/usvg/src/tree/mod.rs @@ -294,7 +294,7 @@ fn calc_node_bbox( let segments = utils::rect_to_path(img.view_box.rect); utils::path_bbox(&segments, None, Some(ts2)) } - NodeKind::Group(_) => { + NodeKind::Svg(_) | NodeKind::Group(_) => { let mut bbox = Rect::new_bbox(); for child in node.children() { |