Skip to content

Commit

Permalink
(c-api) Change resvg_get_image_bbox behavior.
Browse files Browse the repository at this point in the history
Closes #822 Closes #823
  • Loading branch information
RazrFalcon committed Sep 25, 2024
1 parent 5141a83 commit 39ca0a8
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 8 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
This changelog also contains important changes in dependencies.

## [Unreleased]
### Added
- (c-api) `resvg_get_object_bbox`

### Changed
- (c-api) `resvg_get_image_bbox` returns a _layer_ and not _object_ bounding box now.
Use `resvg_get_object_bbox` to preserve the old behavior.

### Fixed
- (svgtypes) Path parsing with `S` or `T` segments after `A`.

Expand Down
2 changes: 1 addition & 1 deletion crates/c-api/ResvgQt.h
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ class ResvgRenderer {
return QRectF();

resvg_rect bbox;
if (resvg_get_image_bbox(d->tree, &bbox))
if (resvg_get_object_bbox(d->tree, &bbox))
return QRectF(bbox.x, bbox.y, bbox.width, bbox.height);

return QRectF();
Expand Down
49 changes: 45 additions & 4 deletions crates/c-api/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,9 +574,10 @@ pub extern "C" fn resvg_is_image_empty(tree: *const resvg_render_tree) -> bool {

/// @brief Returns an image size.
///
/// The size of a canvas that required to render this SVG.
/// The size of an image that is required to render this SVG.
///
/// The `width` and `height` attributes in SVG.
/// Note that elements outside the viewbox will be clipped. This is by design.
/// If you want to render the whole SVG content, use #resvg_get_image_bbox instead.
///
/// @param tree Render tree.
/// @return Image size.
Expand All @@ -595,9 +596,47 @@ pub extern "C" fn resvg_get_image_size(tree: *const resvg_render_tree) -> resvg_
}
}

/// @brief Returns an object bounding box.
///
/// This bounding box does not include objects stroke and filter regions.
/// This is what SVG calls "absolute object bonding box".
///
/// If you're looking for a "complete" bounding box see #resvg_get_image_bbox
///
/// @param tree Render tree.
/// @param bbox Image's object bounding box.
/// @return `false` if an image has no elements.
#[no_mangle]
pub extern "C" fn resvg_get_object_bbox(
tree: *const resvg_render_tree,
bbox: *mut resvg_rect,
) -> bool {
let tree = unsafe {
assert!(!tree.is_null());
&*tree
};

if let Some(r) = tree.0.root().abs_bounding_box().to_non_zero_rect() {
unsafe {
*bbox = resvg_rect {
x: r.x(),
y: r.y(),
width: r.width(),
height: r.height(),
}
}

true
} else {
false
}
}

/// @brief Returns an image bounding box.
///
/// Can be smaller or bigger than a `viewbox`.
/// This bounding box contains the maximum SVG dimensions.
/// It's size can be bigger or smaller than #resvg_get_image_size
/// Use it when you want to avoid clipping of elements that are outside the SVG viewbox.
///
/// @param tree Render tree.
/// @param bbox Image's bounding box.
Expand All @@ -612,7 +651,9 @@ pub extern "C" fn resvg_get_image_bbox(
&*tree
};

if let Some(r) = tree.0.root().abs_bounding_box().to_non_zero_rect() {
// `abs_layer_bounding_box` returns 0x0x1x1 for empty groups, so we need additional checks.
if tree.0.root().has_children() || !tree.0.root().filters().is_empty() {
let r = tree.0.root().abs_layer_bounding_box();
unsafe {
*bbox = resvg_rect {
x: r.x(),
Expand Down
23 changes: 20 additions & 3 deletions crates/c-api/resvg.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,19 +375,36 @@ 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.
* The size of an image that is required to render this SVG.
*
* The `width` and `height` attributes in SVG.
* Note that elements outside the viewbox will be clipped. This is by design.
* If you want to render the whole SVG content, use #resvg_get_image_bbox instead.
*
* @param tree Render tree.
* @return Image size.
*/
resvg_size resvg_get_image_size(const resvg_render_tree *tree);

/**
* @brief Returns an object bounding box.
*
* This bounding box does not include objects stroke and filter regions.
* This is what SVG calls "absolute object bonding box".
*
* If you're looking for a "complete" bounding box see #resvg_get_image_bbox
*
* @param tree Render tree.
* @param bbox Image's object bounding box.
* @return `false` if an image has no elements.
*/
bool resvg_get_object_bbox(const resvg_render_tree *tree, resvg_rect *bbox);

/**
* @brief Returns an image bounding box.
*
* Can be smaller or bigger than a `viewbox`.
* This bounding box contains the maximum SVG dimensions.
* It's size can be bigger or smaller than #resvg_get_image_size
* Use it when you want to avoid clipping of elements that are outside the SVG viewbox.
*
* @param tree Render tree.
* @param bbox Image's bounding box.
Expand Down
2 changes: 2 additions & 0 deletions crates/usvg/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,8 @@ impl Group {
/// For other nodes layer bounding box is the same as stroke bounding box.
///
/// Unlike other bounding boxes, cannot have zero size.
///
/// Returns 0x0x1x1 for empty groups.
pub fn layer_bounding_box(&self) -> NonZeroRect {
self.layer_bounding_box
}
Expand Down

0 comments on commit 39ca0a8

Please sign in to comment.