diff --git a/crates/resvg/src/image.rs b/crates/resvg/src/image.rs index 3f4f34958..bcb315841 100644 --- a/crates/resvg/src/image.rs +++ b/crates/resvg/src/image.rs @@ -57,6 +57,7 @@ fn render_vector( #[cfg(feature = "raster-images")] mod raster_images { use crate::OptionLog; + use usvg::ImageRendering; fn decode_raster(image: &usvg::ImageKind) -> Option { match image { @@ -169,10 +170,14 @@ mod raster_images { let rect = tiny_skia::Size::from_wh(raster.width() as f32, raster.height() as f32)? .to_rect(0.0, 0.0)?; - let mut quality = tiny_skia::FilterQuality::Bicubic; - if rendering_mode == usvg::ImageRendering::OptimizeSpeed { - quality = tiny_skia::FilterQuality::Nearest; - } + let quality = match rendering_mode { + ImageRendering::OptimizeQuality => tiny_skia::FilterQuality::Bicubic, + ImageRendering::OptimizeSpeed => tiny_skia::FilterQuality::Nearest, + ImageRendering::Smooth => tiny_skia::FilterQuality::Bilinear, + ImageRendering::HighQuality => tiny_skia::FilterQuality::Bicubic, + ImageRendering::CrispEdges => tiny_skia::FilterQuality::Nearest, + ImageRendering::Pixelated => tiny_skia::FilterQuality::Nearest, + }; let pattern = tiny_skia::Pattern::new( raster.as_ref(), diff --git a/crates/resvg/src/main.rs b/crates/resvg/src/main.rs index 45ced6017..b30252354 100644 --- a/crates/resvg/src/main.rs +++ b/crates/resvg/src/main.rs @@ -162,7 +162,7 @@ OPTIONS: geometricPrecision] --image-rendering HINT Selects the default image rendering method [default: optimizeQuality] - [possible values: optimizeQuality, optimizeSpeed] + [possible values: optimizeQuality, optimizeSpeed, smooth, high-quality, crisp-edges, pixelated] --resources-dir DIR Sets a directory that will be used during relative paths resolving. Expected to be the same as the directory that diff --git a/crates/resvg/tests/integration/render.rs b/crates/resvg/tests/integration/render.rs index 43fb0be5d..eb829fe9d 100644 --- a/crates/resvg/tests/integration/render.rs +++ b/crates/resvg/tests/integration/render.rs @@ -740,6 +740,7 @@ use crate::render; #[test] fn painting_fill_opacity_with_pattern() { assert_eq!(render("tests/painting/fill-opacity/with-pattern"), 0); } #[test] fn painting_fill_rule_evenodd() { assert_eq!(render("tests/painting/fill-rule/evenodd"), 0); } #[test] fn painting_fill_rule_nonzero() { assert_eq!(render("tests/painting/fill-rule/nonzero"), 0); } +#[test] fn painting_image_rendering_high_quality() { assert_eq!(render("tests/painting/image-rendering/high-quality"), 0); } #[test] fn painting_image_rendering_on_feImage() { assert_eq!(render("tests/painting/image-rendering/on-feImage"), 0); } #[test] fn painting_image_rendering_optimizeSpeed_on_SVG() { assert_eq!(render("tests/painting/image-rendering/optimizeSpeed-on-SVG"), 0); } #[test] fn painting_image_rendering_optimizeSpeed() { assert_eq!(render("tests/painting/image-rendering/optimizeSpeed"), 0); } diff --git a/crates/resvg/tests/tests/painting/image-rendering/high-quality.png b/crates/resvg/tests/tests/painting/image-rendering/high-quality.png new file mode 100644 index 000000000..c1874e84c Binary files /dev/null and b/crates/resvg/tests/tests/painting/image-rendering/high-quality.png differ diff --git a/crates/resvg/tests/tests/painting/image-rendering/high-quality.svg b/crates/resvg/tests/tests/painting/image-rendering/high-quality.svg new file mode 100644 index 000000000..392667f06 --- /dev/null +++ b/crates/resvg/tests/tests/painting/image-rendering/high-quality.svg @@ -0,0 +1,62 @@ + + `optimizeSpeed` + + + + + diff --git a/crates/usvg/src/main.rs b/crates/usvg/src/main.rs index 56a53b146..1ecc02c62 100644 --- a/crates/usvg/src/main.rs +++ b/crates/usvg/src/main.rs @@ -43,7 +43,7 @@ OPTIONS: geometricPrecision] --image-rendering HINT Selects the default image rendering method [default: optimizeQuality] - [possible values: optimizeQuality, optimizeSpeed] + [possible values: optimizeQuality, optimizeSpeed, smooth, high-quality, crisp-edges, pixelated] --resources-dir DIR Sets a directory that will be used during relative paths resolving. Expected to be the same as the directory that diff --git a/crates/usvg/src/parser/svgtree/mod.rs b/crates/usvg/src/parser/svgtree/mod.rs index 540a8b45e..edb36f191 100644 --- a/crates/usvg/src/parser/svgtree/mod.rs +++ b/crates/usvg/src/parser/svgtree/mod.rs @@ -1020,6 +1020,10 @@ impl<'a, 'input: 'a> FromValue<'a, 'input> for ImageRendering { match value { "auto" | "optimizeQuality" => Some(ImageRendering::OptimizeQuality), "optimizeSpeed" => Some(ImageRendering::OptimizeSpeed), + "smooth" => Some(ImageRendering::Smooth), + "high-quality" => Some(ImageRendering::HighQuality), + "crisp-edges" => Some(ImageRendering::CrispEdges), + "pixelated" => Some(ImageRendering::Pixelated), _ => None, } } diff --git a/crates/usvg/src/parser/svgtree/parse.rs b/crates/usvg/src/parser/svgtree/parse.rs index dfb04fb7b..0c2328ba2 100644 --- a/crates/usvg/src/parser/svgtree/parse.rs +++ b/crates/usvg/src/parser/svgtree/parse.rs @@ -242,6 +242,13 @@ pub(crate) fn parse_svg_element<'input>( // For some reason those properties are allowed only inside a `style` attribute and CSS. if matches!(aid, AId::MixBlendMode | AId::Isolation | AId::FontKerning) { continue; + } else if aid == AId::ImageRendering + && matches!( + attr.value(), + "smooth" | "high-quality" | "crisp-edges" | "pixelated" + ) + { + continue; } append_attribute(parent_id, tag_name, aid, attr.value_storage().clone(), doc); diff --git a/crates/usvg/src/tree/mod.rs b/crates/usvg/src/tree/mod.rs index a964c11cd..481cda9ce 100644 --- a/crates/usvg/src/tree/mod.rs +++ b/crates/usvg/src/tree/mod.rs @@ -170,6 +170,11 @@ impl std::str::FromStr for TextRendering { pub enum ImageRendering { OptimizeQuality, OptimizeSpeed, + // The following can only appear as presentation attributes. + Smooth, + HighQuality, + CrispEdges, + Pixelated, } impl Default for ImageRendering { @@ -185,6 +190,10 @@ impl std::str::FromStr for ImageRendering { match s { "optimizeQuality" => Ok(ImageRendering::OptimizeQuality), "optimizeSpeed" => Ok(ImageRendering::OptimizeSpeed), + "smooth" => Ok(ImageRendering::Smooth), + "high-quality" => Ok(ImageRendering::HighQuality), + "crisp-edges" => Ok(ImageRendering::CrispEdges), + "pixelated" => Ok(ImageRendering::Pixelated), _ => Err("invalid"), } } diff --git a/crates/usvg/src/writer.rs b/crates/usvg/src/writer.rs index c36045fd8..9b0e74467 100644 --- a/crates/usvg/src/writer.rs +++ b/crates/usvg/src/writer.rs @@ -647,6 +647,18 @@ fn write_element(node: &Node, is_clip_path: bool, opt: &WriteOptions, xml: &mut ImageRendering::OptimizeSpeed => { xml.write_svg_attribute(AId::ImageRendering, "optimizeSpeed"); } + ImageRendering::Smooth => { + xml.write_attribute(AId::Style.to_str(), "image-rendering:smooth"); + } + ImageRendering::HighQuality => { + xml.write_attribute(AId::Style.to_str(), "image-rendering:high-quality"); + } + ImageRendering::CrispEdges => { + xml.write_attribute(AId::Style.to_str(), "image-rendering:crisp-edges"); + } + ImageRendering::Pixelated => { + xml.write_attribute(AId::Style.to_str(), "image-rendering:pixelated"); + } } xml.write_image_data(&img.kind); diff --git a/docs/svg2-changelog.md b/docs/svg2-changelog.md index c6c2638c1..0ed6ba4e3 100644 --- a/docs/svg2-changelog.md +++ b/docs/svg2-changelog.md @@ -196,7 +196,7 @@ Basically everything from [CSS Text Module Level 3](https://www.w3.org/TR/css-te - [x] An [`isolation`](https://www.w3.org/TR/compositing-1/#isolation) property. - [ ] `left`, `center` and `right` variants to `refX` and `refY` properties of the [`marker`](https://www.w3.org/TR/SVG2/painting.html#MarkerElement) element. - [x] An `auto-start-reverse` variant to [`orient`](https://www.w3.org/TR/SVG2/painting.html#OrientAttribute) property of the [`marker`](https://www.w3.org/TR/SVG2/painting.html#MarkerElement) element - +- [x] The `image-rendering` can appear as a presentation attribute with additional possible values. Currently, there is only best-effort support for "pixelated". ### Changed - [x] Markers can be set on all shapes and not only on `path`.