resvg
resvg copied to clipboard
Low image quality when downscaling
The use case is a PNG image which is base64-encoded and embedded in the SVG in an <image>
tag. In the attached example, the original image is 160x160, and scaled down to 49x49 in the SVG markup.
The rendered image (resvg-rendered-49px.png) quality is degraded, especially on the curves.
When defining the dimensions as 160x160 in the SVG markup, the rendered image (resvg-rendered-160px.png) quality is great. And when including that image on an HTML page and re-scaling in the HTML markup, <img src="resvg-rendered-160px.png" width="49" height="49">
, the image quality remains crisp.
We also tried setting the image-rendering
attribute for OptimizeQuality
, but the improvement was negligible.
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/image-rendering
Is is correct that Bicubic interpolation is being used? Do you have any guidance for improving image quality, and/or are there plans for other interpolation options?
Processing this same image with various interpolation filters in ImageSharp
(e.g. Lanczos, MitchellNetravali, etc.) does produce a high quality result.
resvg does use bicubic scaling, but I guess something goes wrong. Will see.
Also ran into this issue. The SVG below has an embedded PNG in 1024 * 1024 size, which looks really aliased when rendered at 100 * 100 size.
SVG
resvg output
Chromium output
I also tried explicitly passing FilterQuality::Bicubic
here, but the result was the same. Could it be a problem with tiny-skia then?
@romanzes It most definitely is.
Any updates on this issue?
It will be done when it will be done.
modify the pipeline
in tiny-skia
to slightly expand the sparsity of the neighboring 4x4 for bicubic
, then average them. This might yield some improvement.
I don't think this is the case. It works fine in Skia, meaning the bug is somewhere else.
I don't think this is the case. It works fine in Skia, meaning the bug is somewhere else.
Actually, Skia has the same problem, embedded rasters look aliased when downscaled. I was able to fix it in my fork of Skia by changing this line to:
ctx.canvas()->drawImageRect(
imgInfo.fImage, imgInfo.fDst, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear));
However, as far as I understand, tiny-skia
doesn't support mipmapping, so this workaround wouldn't help here.
@romanzes That's surprising. I will double check later. If Skia fails in the same way as tiny-skia then there is nothing we can do, sort of. We would have to find a workaround.
And no, tiny-skia doesn't support mipmapping. Afaik it was a lot of work to implement and Skia uses some sort of shared cashing for them. Too much complexity for now.