在 Xamarin.Forms 中序列化 ImageSource

Posted

技术标签:

【中文标题】在 Xamarin.Forms 中序列化 ImageSource【英文标题】:Serialize ImageSource in Xamarin.Forms 【发布时间】:2021-03-31 06:19:39 【问题描述】:

我正在尝试序列化一个成员为ImageSource 类型的类。 班级是:

    public class AppInfo
    
        public string Name  get; set; 
        public ImageSource Icon  get; set; 
        public bool Is90Hz  get; set; 
    

我得到这样的类的数据:

        private static IList<AppInfo> GetAppInfos()
        
            var localAppInfo = new List<AppInfo>();
            var allAppsRaw = DependencyService.Get<IGetAllApps>().GetApps();

            var pm = android.App.Application.Context.PackageManager;
            if (pm == null)
                return null;

            foreach (var info in allAppsRaw)
            
                var bitmap = DependencyService.Get<IGetAllApps>().DrawableToBitmap(info.LoadIcon(pm));
                byte[] bitmapData;

                using (var stream = new MemoryStream())
                
                    bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
                    bitmapData = stream.ToArray();
                

                var imageSource = ImageSource.FromStream(() => new MemoryStream(bitmapData, 0, bitmapData.Length));

                localAppInfo.Add(new AppInfo  Name = info.LoadLabel(pm), Icon = imageSource, Is90Hz = true );
            

            return localAppInfo;
        

问题在于 System.Text.Json 无法序列化该类型。我来回搜索如何将其转换为字节数组或 Base64 字符串,但我有点迷路了。

我将[JsonConverter(typeof(ImageSourceConverter))] 添加到成员并声明我的转换器类如下:

    public class ImageSourceConverter : JsonConverter<ImageSource>
    
        public override ImageSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        
        

        public override void Write(Utf8JsonWriter writer, ImageSource value, JsonSerializerOptions options)
        
        
    

但我现在有点迷失了......只是无法弄清楚读写方法的逻辑。

*编辑: 最终目标是展示它,目前的做法:

        <ListView Grid.Column="3" x:Name="AppsView" CachingStrategy="RecycleElement" Margin="10,10,10,10">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal" CompressedLayout.IsHeadless="true">
                            <Image Source="Binding Icon, Mode=TwoWay" WidthRequest="40" HeightRequest="40" HorizontalOptions="StartAndExpand"/>
                            <Label Text="Binding Name, Mode=TwoWay" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
                            <Switch IsToggled="Binding Is90Hz, Mode=TwoWay" HorizontalOptions="EndAndExpand"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ContentPage.Content>

【问题讨论】:

我认为没有任何简单的方法可以做到这一点。 ImageSource 并非旨在公开其基础数据。您最好在 AppInfo 类中存储文件路径、url 或 byte[]。 【参考方案1】:

Xamarin.Forms 使用 Image 视图在页面上显示图像。它有几个重要的属性:

Source - 一个 ImageSource 实例,可以是 File、Uri 或 Resource,用于设置要显示的图像。

ImageSource可以使用静态方法为每种类型的图像源获取实例:

FromFile - 需要一个可以在每个平台上解析的文件名或文件路径。

FromUri - 需要一个 Uri 对象,例如。新的 Uri("http://....") .

FromResource - 需要资源标识符来嵌入应用程序或 .NET Standard 库项目中的图像文件,并带有 构建操作:EmbeddedResource。

FromStream - 需要一个提供图像数据的流。

所以你可以尝试绑定流:

改变

public ImageSource Icon  get; set; 

public Stream Icon  get; set; 

然后添加流:

var imageSource = new MemoryStream(bitmapData, 0, bitmapData.Length);

localAppInfo.Add(new AppInfo  Name = info.LoadLabel(pm), Icon = imageSource, Is90Hz = true );

在您的 xaml 中:

<Image>
    <Image.Source>
       <StreamImageSource Stream="Binding Icon"
    </Image.Source>
</Image>

【讨论】:

【参考方案2】:

谢谢,我最终用转换器做了类似的事情。 在我的 xaml 中:

    <ContentPage.Resources>
         <ResourceDictionary>
              <api:ByteArrayToImageConverter x:Key="Bti"/>
         </ResourceDictionary>
    </ContentPage.Resources>
<Image Source="Binding Icon, Converter=StaticResource Bti, Mode=Default" WidthRequest="37" HeightRequest="37" HorizontalOptions="StartAndExpand"/>

转换器类:

    public class ByteArrayToImageConverter : IValueConverter
    
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        
            if (value == null)
                return null;

            var imageAsBytes = (byte[])value;
            return ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
        

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) =>
                throw new NotImplementedException();
    

我只是将照片保存为byte[]

                var bitmap = DependencyService.Get<IGetAllApps>().DrawableToBitmap(info.LoadIcon(pm));
                byte[] bitmapData;

                using (var stream = new MemoryStream())
                
                    bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
                    bitmapData = stream.ToArray();
                

                localAppInfo.Add(new AppInfo
                    Name = info.LoadLabel(pm), PackageName = info.PackageName, Icon = bitmapData, Is90Hz = true);

【讨论】:

以上是关于在 Xamarin.Forms 中序列化 ImageSource的主要内容,如果未能解决你的问题,请参考以下文章

无法反序列化当前 JSON 对象 xamarin.forms

Xamarin.Forms DependencyService 始终返回 null

Xamarin.Forms 导航页

如何在我的 Xamarin Forms 应用程序上本地保存一些用户数据?

Xamarin.Forms:如何在 Xamarin.Forms 跨平台项目中开发具有蓝牙连接的应用程序?

如何使用 Xamarin.Forms.Maps(无 Xamarin.Forms.GoogleMaps)在地图中应用样式或更改颜色