【问题标题】:How to get better image scaling in Xamarin Forms UWP?如何在 Xamarin Forms UWP 中获得更好的图像缩放?
【发布时间】:2021-07-13 04:44:05
【问题描述】:

当我的应用程序中的图像元素被 UI 缩小到 UWP 中的小尺寸时,缩放看起来质量很差,就像它是通过旧的“最近邻”样式缩放的,这使它非常像素化:

当我在 Android 上运行同一个应用时,它看起来不错:

这些图像使用 TMDB API 从 URL 显示。有什么方法可以控制它使用的图像缩放算法吗?

【问题讨论】:

  • 分辨率取决于硬件上每英寸的像素数。您没有说第一个应用程序使用的是什么机器。只有第二个应用是 Android,所以我必须假设第一个不是 Android。而且我必须假设第一个和第二个每英寸的像素数不同。
  • 我说的是UWP,UWP是windows 10。分辨率一样的情况下,安卓版看起来更流畅。它似乎使用了比 UWP 版本更好的缩放插值。

标签: c# xamarin.forms uwp


【解决方案1】:

如何在 Xamarin Forms UWP 中获得更好的图像缩放?

请参考 UWP 图像文件和性能document,如果您在引用图像文件时知道源文件是大的高分辨率图像,但您的应用在小于图片的自然尺寸,你应该设置DecodePixelWidth属性,或者DecodePixelHeight。对于 xamarin 表单项目,我们建议您使用effect 重新渲染图像。

[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()
    {

    }
}

表单代码部分

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)}")
    {
    }
}

用法

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

更新

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()
    {

    }
}

【讨论】:

  • 问题是,UWP版本是在windows中运行的,这意味着人们可以动态地使窗口变大或变小,我不想每次都重新渲染或重新解码图像他们这样做。有了良好的过滤,就像在最低限度的双线性插值,这不应该是必要的。 WPF 在其图像控件中有 RenderOptions.BitmapScalingMode="HighQuality",但我很难在 Xamarin 甚至独立 UWP 中找到类似的东西。
  • 是的,目前还没有像wpf BitmapScalingMode这样的选项,所以我们建议您根据图像控件大小设置DecodePixelHeight DecodePixelWidth,如案例更新部分
  • @morphinapg 我已根据更改的图像大小使用动态 DecodePixelSize 更新案例回复,它有效吗?
  • 我正试图让它工作,但我需要在代码中设置图像的 Uri,而不是 XAML,因为它从 API 或我的数据库加载,而且我只需要在 UWP 上使用它因为Android工作正常。现在我正在做 ShowImage.SetBinding(ImageEffect.TextProperty, uri.AbsoluteUri);但这似乎没有做任何事情。我已将 ImageEffect 复制到主项目中,并将 ImageSourceEffect 复制到 UWP 项目中。我假设这是对的?还有什么我需要做的吗?
  • 如果在代码隐藏中设置uri,更好的解决方案是自定义渲染图像控制并在原生渲染中处理位图,您可以参考tutorial
猜你喜欢
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
  • 2017-10-03
  • 2011-09-04
  • 2023-03-13
  • 2014-08-12
  • 1970-01-01
  • 2020-03-08
相关资源
最近更新 更多