diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f6548c1f..0935e30d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). This changelog also contains important changes in dependencies. ## [Unreleased] +### Added +- `usvg::ImageHrefResolver` that allows a custom `xlink:href` handling. + Thanks to [antmelnyk](https://github.com/antmelnyk). ## [0.20.0] - 2021-12-29 ### Changed diff --git a/examples/custom_href_resolver.rs b/examples/custom_href_resolver.rs index 0207913bb..7627991d9 100644 --- a/examples/custom_href_resolver.rs +++ b/examples/custom_href_resolver.rs @@ -25,13 +25,7 @@ fn main() { let pixmap_size = rtree.svg_node().size.to_screen_size(); let mut pixmap = tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap(); - resvg::render( - &rtree, - usvg::FitTo::Original, - tiny_skia::Transform::default(), - pixmap.as_mut(), - ) - .unwrap(); + resvg::render(&rtree, usvg::FitTo::Original, tiny_skia::Transform::default(), pixmap.as_mut()).unwrap(); pixmap.save_png("custom_href_resolver.png").unwrap(); } diff --git a/examples/ferris.png b/examples/ferris.png index d553e7481..e1c909286 100644 Binary files a/examples/ferris.png and b/examples/ferris.png differ diff --git a/usvg/src/filter/image.rs b/usvg/src/filter/image.rs index fe6c89208..36b1d489a 100644 --- a/usvg/src/filter/image.rs +++ b/usvg/src/filter/image.rs @@ -64,7 +64,6 @@ pub(crate) fn convert(fe: svgtree::Node, state: &converter::State) -> Kind { }; let href = crate::image::get_href_data(href, state.opt); - let img_data = match href { Some(data) => data, None => return super::create_dummy_primitive(), diff --git a/usvg/src/image.rs b/usvg/src/image.rs index cb61ce413..7f4eb088e 100644 --- a/usvg/src/image.rs +++ b/usvg/src/image.rs @@ -37,22 +37,47 @@ impl std::fmt::Debug for ImageKind { } } -/// Functions that accept various representations of `xlink:href` value of the `` -/// element and return ImageKind that holds reference to the image buffer determined by these functions. -#[allow(clippy::type_complexity)] +/// A shorthand for [ImageHrefResolver]'s data function. +pub type ImageHrefDataResolverFn = Box>, &OptionsRef) -> Option + Send + Sync>; +/// A shorthand for [ImageHrefResolver]'s string function. +pub type ImageHrefStringResolverFn = Box Option + Send + Sync>; + +/// An `xlink:href` resolver for `` elements. +/// +/// This type can be useful if you want to have an alternative `xlink:href` handling +/// to the default one. For example, you can forbid access to local files (which is allowed by default) +/// or add support for resolving actual URLs (usvg doesn't do any network requests). pub struct ImageHrefResolver { - /// Resolver function that will be used if `xlink:href` is a DataUrl with encoded base64 string. - pub resolve_data: Box>, &OptionsRef) -> Option + Send + Sync>, + /// Resolver function that will be used when `xlink:href` contains a + /// [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs). + /// + /// A function would be called with mime, decoded base64 data and parsing options. + pub resolve_data: ImageHrefDataResolverFn, - /// Resolver function that will be used to handle arbitrary string in `xlink:href`. - pub resolve_string: Box Option + Send + Sync>, + /// Resolver function that will be used to handle an arbitrary string in `xlink:href`. + pub resolve_string: ImageHrefStringResolverFn, +} + +impl Default for ImageHrefResolver { + fn default() -> Self { + ImageHrefResolver { + resolve_data: ImageHrefResolver::default_data_resolver(), + resolve_string: ImageHrefResolver::default_string_resolver() + } + } } impl ImageHrefResolver { - /// Create DataUrl resolver function that handles standard mime types for JPEG, PNG and SVG. - #[allow(clippy::type_complexity)] - pub fn default_data_resolver<'a>( - ) -> Box>, &OptionsRef) -> Option + Send + Sync + 'a> { + /// Creates a default + /// [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) + /// resolver closure. + /// + /// base64 encoded data is already decoded. + /// + /// The default implementation would try to load JPEG, PNG, SVG and SVGZ types. + /// Note that it will simply match the `mime` or data's magic. + /// The actual images would not be decoded. It's up to the renderer. + pub fn default_data_resolver() -> ImageHrefDataResolverFn { Box::new( move |mime: &str, data: Arc>, opts: &OptionsRef| match mime { "image/jpg" | "image/jpeg" => Some(ImageKind::JPEG(data)), @@ -64,13 +89,18 @@ impl ImageHrefResolver { _ => load_sub_svg(&data, opts), }, _ => None, - }, + } ) } - /// Create resolver function that handles `href` string as path to local JPEG, PNG or SVG file. - pub fn default_string_resolver<'a>( - ) -> Box Option + Send + Sync + 'a> { + /// Creates a default string resolver. + /// + /// The default implementation treats an input string as a file path and tries to open. + /// If a string is an URL or something else it would be ignored. + /// + /// Paths have to be absolute or relative to the input SVG file or relative to + /// [Options::resources_dir](crate::Options::resources_dir). + pub fn default_string_resolver() -> ImageHrefStringResolverFn { Box::new(move |href: &str, opts: &OptionsRef| { let path = opts.get_abs_path(std::path::Path::new(href)); @@ -106,15 +136,6 @@ impl std::fmt::Debug for ImageHrefResolver { } } -impl Default for ImageHrefResolver { - fn default() -> Self { - ImageHrefResolver { - resolve_data: ImageHrefResolver::default_data_resolver(), - resolve_string: ImageHrefResolver::default_string_resolver() - } - } -} - /// A raster image element. /// /// `image` element in SVG. diff --git a/usvg/src/options.rs b/usvg/src/options.rs index d5764257a..1f3737aa9 100644 --- a/usvg/src/options.rs +++ b/usvg/src/options.rs @@ -2,10 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -use crate::{ - image::ImageHrefResolver, - ImageRendering, ShapeRendering, TextRendering, Size, ScreenSize, -}; +use crate::{ImageHrefResolver, ImageRendering, ShapeRendering, TextRendering, Size, ScreenSize}; /// Image fit options. /// @@ -135,9 +132,9 @@ pub struct Options { #[cfg(feature = "text")] pub fontdb: fontdb::Database, - /// Specifies the way to parse `` elements `xlink:href` value. + /// Specifies the way `xlink:href` in `` elements should be handled. /// - /// Default: either parse `href` as DataUrl, or parse it as a path to the local image file. + /// Default: see type's documentation for details pub image_href_resolver: ImageHrefResolver, }