question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SVG Image in iOS-TabbedPage blurry

See original GitHub issue

I’m trying to add a SVG image to a TabbedPage. It comes up very blurry though. If I try to compensate the size for the screen scale, it comes out way too big and get’s larger then the TabBar itself. I tried rendering it in a higher resolution and then downscale it using UIImage.Scale but it get’s even worse with that.

Here is my minified TabbedRenderer code:

protected override async Task<Tuple<UIImage, UIImage>> GetIcon(Page page)
{
    int height = TabBar.Frame.Height - TabBar.SafeAreaInsets.Bottom;    
    int size = (int)(height / 2d);
    
    var params = ImageService.Instance.LoadEmbeddedResource(((UriImageSource)page.IconImageSource).File)
        .WithCustomDataResolver(new SvgDataResolver(0, size, false));
    var image = await params.AsUIImageAsync();

    return Tuple.Create(image, (UIImage)null);
}

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:8

github_iconTop GitHub Comments

2reactions
Dreselcommented, Oct 24, 2019

Possible related to #1305.

I had a similar problem when using SvgImageSource (might also be valid for other sources):

The problem is that scale is ignored in the IImageSourceHandler for iOS. This property should be passed when instantiating the UIImage. I did a quick test and registered my own IImageSourceHandler and everything worked:

public class ScaleAwareImageSourceHandler : IImageSourceHandler
{
	public ScaleAwareImageSourceHandler()
	{
		WrappedImageSourceHandler = new FFImageLoadingImageSourceHandler();
	}

	public IImageSourceHandler WrappedImageSourceHandler { get; }

	public Task<UIImage> LoadImageAsync(ImageSource imageSource, CancellationToken cancellationToken = default, float scale = 1)
	{
		return WrappedImageSourceHandler.LoadImageAsync(imageSource, cancellationToken, scale)
			.ContinueWith(async (task) =>
			{
				UIImage uiImage = await task;

				if (uiImage != null && scale != 1.0)
				{
					return new UIImage(uiImage.CGImage, scale, uiImage.Orientation);
				}

				return uiImage;
			}, cancellationToken)
			.Unwrap();
	}
}

@daniel-luberda I would go for a PR, but I’m not sure where this parameter should be added and passed down to the SvgDataResolver.

1reaction
BaltoAFcommented, Oct 13, 2022

@Dresel thak you for your help. I finally succeeded in implementing this. This is what I’ve done :

1- Add this class based in iOS project, based on Dresel post :

public class ScaleAwareImageSourceHandler : IImageSourceHandler { public ScaleAwareImageSourceHandler() { WrappedImageSourceHandler = new FFImageLoadingImageSourceHandler(); }

    public IImageSourceHandler WrappedImageSourceHandler { get; }

    public Task<UIImage> LoadImageAsync(ImageSource imageSource, CancellationToken cancellationToken = default, float scale = 1)
    {
        return WrappedImageSourceHandler.LoadImageAsync(imageSource, cancellationToken, scale)
            .ContinueWith(async (task) =>
            {
                UIImage uiImage = await task;

                if (uiImage != null && scale != 1.0)
                {
                    return new UIImage(uiImage.CGImage, scale, uiImage.Orientation);
                }

                return uiImage;
            }, cancellationToken)
            .Unwrap();
    }

    public static void Register(Type type, Type renderer)
    {
        var assembly = typeof(Image).GetTypeInfo().Assembly;
        var registrarType = assembly.GetType("Xamarin.Forms.Internals.Registrar") ?? assembly.GetType("Xamarin.Forms.Registrar");
        var registrarProperty = registrarType.GetRuntimeProperty("Registered");

        var registrar = registrarProperty.GetValue(registrarType, null);
        var registerMethod = registrar.GetType().GetRuntimeMethod("Register", new[] { typeof(Type), typeof(Type) });
        registerMethod.Invoke(registrar, new[] { type, renderer });
    }

    /// <summary>
    /// This is a copy of CachedImageRenderer.InitImageSourceHandler(); Replacing the renderer of the SvgImageSource.
    /// </summary>
    public static void InitImageSourceHandler()
    {
        Register(typeof(FileImageSource), typeof(FFImageLoadingImageSourceHandler));
        Register(typeof(StreamImageSource), typeof(FFImageLoadingImageSourceHandler));
        Register(typeof(UriImageSource), typeof(FFImageLoadingImageSourceHandler));
        Register(typeof(EmbeddedResourceImageSource), typeof(FFImageLoadingImageSourceHandler));
        Register(typeof(DataUrlImageSource), typeof(FFImageLoadingImageSourceHandler));
        try
        {
            Assembly assembly = Assembly.Load("FFImageLoading.Svg.Forms");
            if (assembly != null)
            {
                Type type = assembly.GetType("FFImageLoading.Svg.Forms.SvgImageSource");
                if (type != null)
                {
                    Register(type, typeof(ScaleAwareImageSourceHandler));
                }
            }
        }
        catch
        {
        }
    }
}

2- In AppDelegate.cs, use custom implementation of InitImageSourceHandler() :

//CachedImageRenderer.InitImageSourceHandler(); //Use a custom ImageSourceHandler for Svgs. ScaleAwareImageSourceHandler.InitImageSourceHandler();

3- Keep scale to use it later. On Android, scale is always 1. But on iOS it can be found in ScaleHelper.

ScaleAwareImageSourceHandler.InitImageSourceHandler(); … //ResourceHelper is my helper class. You can use your own. ResourceHelper.Scale = (float)ScaleHelper.Scale;

4 - Use the scale when building the image :

SvgImageSource.FromResource(resourceName, vectorWidth: (int)(width * ResourceHelper.Scale), vectorHeight: (int)(height * ResourceHelper.Scale)

That’s all !

Read more comments on GitHub >

github_iconTop Results From Across the Web

In Safari svg mask looks blurry like if it's raster
Safari has some problems with resizing SVG images, in the case the viewBox attribute is missing. I can't tell if this is an...
Read more >
Issue with blurry SVG images on mobile - General
It is an iOS issue that occurs when an SVG file is smaller than 20px. Even though it's vectors these browsers have issues...
Read more >
[Resolve]-SVG icons in safari are blurred - appsloveworld.com
I have noticed that svg icons that placed via 'img' tag aren't rendered correctly in safari. They end up being all blurry. I...
Read more >
Developers - SVG Image in iOS-TabbedPage blurry -
I'm trying to add a SVG image to a TabbedPage. It comes up very blurry though. If I try to compensate the size...
Read more >
6 Common SVG Fails (and How to Fix Them)
I'm editing these to reframe the image. The last two are the width and height of the coordinate system inside the viewport —...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found