0
votes

When an Image element in my app is scaled down by the UI to a small size in UWP, the scaling looks quite bad quality, like it's being scaled via the old "Nearest Neighbor" style which leaves it very pixelated:

UWP Scaling

When I run the same app on Android, it looks fine:

Android Scaling

These images are displayed from an URL using the TMDB API. Is there any way to control the image scaling algorithm it's using?

1
The resolution depends on the number of pixels per inch on the hardware. You did not say what machine you are using for the first app. Only the second app is an Android so I have to assume the first is not Android. And I have to assume the number of pixels per inch is different on first than the second.jdweng
I said it's UWP, UWP is windows 10. When the resolution is the same, the Android version looks smoother. It appears to be using a better scaling interpolation than the UWP version.morphinapg

1 Answers

0
votes

How to get better image scaling in Xamarin Forms UWP?

Please refer UWP image files and performance document, If you are referencing an image file where you know that the source file is a large, high resolution image, but your app is displaying it in a UI region that's smaller than the image's natural size, you should set the DecodePixelWidth property, or DecodePixelHeight. For xamarin form project, we suggest you use effect to re-render image.

[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(ImageFormsTest.UWP.ImageSourceEffect), nameof(ImageEffect))]

public class ImageSourceEffect : PlatformEffect
{
    protected override void OnAttached()
    {
        try
        {
            var control = Control ?? Container;

            if (control is DependencyObject)
            {
                var image = control as Windows.UI.Xaml.Controls.Image;
                var uri = ImageEffect.GetText(Element);
                var bitmap = new BitmapImage(new Uri(uri)) { DecodePixelHeight = 300, DecodePixelWidth = 600 };

                image.Source = bitmap;

            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
        }
    }
 
    protected override void OnDetached()
    {

    }
}

Forms code part

public static class ImageEffect
{

    public static readonly BindableProperty TextProperty =
      BindableProperty.CreateAttached("Text", typeof(string), typeof(ImageEffect), string.Empty, propertyChanged: OnTextChanged);

    public static string GetText(BindableObject view)
    {
        return (string)view.GetValue(TextProperty);
    }

    public static void SetText(BindableObject view, string value)
    {
        view.SetValue(TextProperty, value);
    }

    static void OnTextChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var view = bindable as View;
        if (view == null)
        {
            return;
        }

        string text = (string)newValue;
        if (!string.IsNullOrEmpty(text))
        {
            view.Effects.Add(new SourceEffect());
        }
        else
        {
            var toRemove = view.Effects.FirstOrDefault(e => e is SourceEffect);
            if (toRemove != null)
            {
                view.Effects.Remove(toRemove);
            }
        }
    }

}

public class SourceEffect : RoutingEffect
{
    public SourceEffect() : base($"MyCompany.{nameof(ImageEffect)}")
    {
    }
}

Usage

<Image
    x:Name="TitleImage" effect:ImageEffect.Text="https://xxxx.jpg"
   />

Update

public class ImageSourceEffect : PlatformEffect
{
    protected override void OnAttached()
    {
        try
        {
            var control = Control ?? Container;

            if (control is DependencyObject)
            {
                var image = control as Windows.UI.Xaml.Controls.Image;
                var uri = ImageEffect.GetText(Element);
                var bitmap = new BitmapImage(new Uri(uri));
                bitmap.ImageOpened += Bitmap_ImageOpened;
                image.Source = bitmap;
                image.SizeChanged += Image_SizeChanged;
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Cannot set property on attached control. Error: ", ex.Message);
        }
    }

    private void Image_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (bitmapImage != null)
        {
            bitmapImage.DecodePixelType = DecodePixelType.Logical;
            bitmapImage.DecodePixelHeight = (int)e.NewSize.Height;
            bitmapImage.DecodePixelWidth = (int)e.NewSize.Width;
        }

    }

    private BitmapImage bitmapImage;
    private void Bitmap_ImageOpened(object sender, RoutedEventArgs e)
    {
        bitmapImage = sender as BitmapImage;
     
    }

    protected override void OnDetached()
    {

    }
}