Xamarin.Forms:如何将Resources中的图像加载到字节数组中?

我有一个(希望)简单的问题(我没有找到答案,这符合我的所有搜索)。

我使用Xamarin.Forms 1.4.1-Pre-1。 在我的应用程序中,我有:

byte[] AvatarErfassung; // Bytearray, to later update the webservice var Avatar = new Image { HeightRequest = 71, WidthRequest = 61, HorizontalOptions = LayoutOptions.Start }; Avatar.Source = "SymbolMann.jpg"; 

其中包含图像“SymbolMann.jpg” 作为项目资源 (在每个项目中)并显示在页面上(没有问题)。
我现在想将图像放在一个字节数组中,以将其发送到我们的Web服务。 我没有找到任何方法来访问图像“SymbolMann.jpg”(以字节数组加载)或使用(但是)Avatar.Source。

题:
如何将图像“SymbolMann.jpg”放入字节数组“AvatarErfassung”中?

谢谢你的每一个答案

嗨迪米特里斯

感谢您的(快速)重播。
正如我写的那样,我和Xamarin一起工作。 表格
图像存储为资源 :\ Resources \ Drawable \(对于Android),\ Resources \(对于iOS)和根(对于WP)。 我必须在内容页面上加载图像。

如果我超越你的代码,就行:

 var assembly = this.GetType().GetTypeInfo().Assembly; 

我有错误信息(翻译成英文):
“System.Type不包含GetTypeInfo方法的定义(使用丢失?)”

我是否必须添加特定的使用?

你写://你可以用“typeof(MyType)”替换“this.GetType()”,其中MyType是程序集中的任何类型。

我有什么要作为类型放置?

= typeof(????)。GetTypeInfo()。程序集:

感谢您的进一步回复。

更新#2:

第一,谢谢你的耐心……

不幸的是在VS2013中 ,我没有找到任何显示我缺少使用function的“解决方案” – 但是我发现了使用我自己的缺失:-)
与此同时,我添加了使用System.Reflection;

现在,行:var assembly = this.GetType()。GetTypeInfo()。Assembly;

解决和编译没有错误

此外,我已将.jpg的类型从“Android资源”更改为“嵌入式资源”。
然后应用程序在行中崩溃 :long length = s.Length; 因为它似乎是null(我认为没有找到jpg)

此外 – 如果我将类型更改为“嵌入式资源” – Xamarin.Forms(Avatar.Source =“SymbolMann.jpg”;)不再找到图像

如果我将.jpg的类型更改为“编译”,我无法编译应用程序。
错误消息:命名空间不能直接包含字段或方法等成员。

那么……资源的正确类型是什么(因此可以使用assembly.GetManifestResourceStream()加载它?

我是否必须在文件名中添加一些内容(SymbolMann.jpg)以便找到它?

我如何更改Avatar.Source =“SymbolMann.jpg”以便找到它(如果我将类型从“Android资源”更改为其他任何内容)?

我的需求再一次:
在注册页面上,默认图像(符号)在标准Xamarin.Forms图像(avatar.source =“SymbolMann.jpg”/“SymbolFrau.jpg”)中显示为男人和女人的化身。
.jpg存储在每个项目(Android,iOS和WP)的标准目录中,可以在没有图像对象问题的情况下访问它们。
然后,用户可以使用其中一个默认图像或通过mediapicker加载另一个默认图像。
如果用户点击“注册”按钮,我必须从Image创建一个字节数组,通过json将其发送到我们的webservice。
如果用户通过mediapicker选择另一个图像,我可以访问流,问题是,从默认图像(在每个平台中)成为字节数组。

再次感谢您的帮助……

您可以通过从程序集中读取资源流来轻松完成此操作:

 var assembly = this.GetType().GetTypeInfo().Assembly; // you can replace "this.GetType()" with "typeof(MyType)", where MyType is any type in your assembly. byte[] buffer; using (Stream s = assembly.GetManifestResourceStream("SymbolMann.jpg”)) { long length = s.Length; buffer = new byte[length]; s.Read(buffer, 0, (int)length); } // Do something with buffer 

编辑:

要获取包含项目的嵌入资源的程序集,您需要在该程序集中包含的类型上调用GetTypeInfo方法。 因此, typeof(X) ,其中“X”是程序集中的任何类型。 例如,如果您使用名为MyCustomPage的自定义页面:

 public class MyCustomPage : ContentPage {} 

…这就是你要传递的: typeof(MyCustomPage)

您需要Type任何实例(这是typeof关键字基本返回的内容)。 另一种方法是在项目中包含的任何对象上调用GetType()方法。

请注意,如果在项目中未包含的类型上调用typeof(X) ,则无法获得正确的程序集。 例如。 调用typeof(ContentPage).GetTypeInfo().Assembly ,将返回ContentPage类型所在的程序集。哪个包含您的资源。 我希望这不会令人困惑。 如果是,请告诉我。

现在, GetTypeInfo方法是System.Reflection命名空间中包含的扩展方法。 当Xamarin Studio中的文本编辑器无法识别某些内容时,它会用红色突出显示它。 右键单击它将在上下文菜单中为您提供Resolve选项:

在Xamarin Studio中单击鼠标右键

如果可以解析类型或方法,它将显示该选项。

更多关于Xamarin Forms中的图像。

首先,非常感谢Dimitris指导我走向正确的方向!

结论:

基地:
我使用VS2013 – 更新2,Xamarin.Forms(1.4.1-Pre1),我的应用程序基于模板“空白应用程序(Xamarin.Forms共享)” (不是PCL),我使用所有平台(Android,iOS, WP)。

在用户注册页面上,用户可以选择图像作为化身(稍后显示给他的post)。 根据用户的性别,有两个默认图像(一个用于男性,一个用于女性)。 然后,用户可以超过其中一个默认图像或从媒体选择器中选择另一个图像。
默认图像存储在内容图像的默认位置(对于Android,例如在/ Resources / Drawable /下 )。
图像显示在XF-Standard-Image-Object中,Image-Source =“xxx.jpg”。
这没有问题。

问题:
由于用户数据(包括头像)存储在SQL-Server上(通过Json-web-service),我必须将图像数据转换为字节数组(然后将其与其他数据一起发送为字符串到网络服务)。
问题是, 从默认目录加载图像并将其转换为字节数组(由此文件访问是问题 – >无法访问)。

解决方案:
感谢Dimitris,我指导了我正确的方向,我实施了以下解决方案:

在所有项目(Android,iOS和WP)中,我添加了一个新目录“\ Embedded \”(直接位于根目录下) 。 然后,我在这个目录中复制了我的两个jpg(“SymbolMann.jpg”和“SymbolFrau.jpg”)(适用于所有平台)。
然后,我将资源类型更改为图像,例如“AndroidResource”到“Embedded Resource” (适用于所有类型相同的平台)。

在我的应用程序启动代码(app.cs)中,我添加了:

 // string cNameSpace = ""; switch (Device.OS) { case TargetPlatform.WinPhone: cNameSpace = "MatrixGuide.WinPhone"; break; case TargetPlatform.iOS: cNameSpace = "MatrixGuide.iOS"; break; case TargetPlatform.Android: cNameSpace = "MatrixGuide.Droid"; break; } GV.cEmbeddedAblage = cNameSpace + ".Embedded."; 

其中GV.cEmbeddedAblage只是一个全局变量。
要检查命名空间名称,我必须右键单击每个平台的项目,并查看已确定的命名空间名称(可能在您的项目中有所不同)。
.Embedded。 是新创建的目录(在所有平台上都是相同的名称)。

另外,我为男性形象(GV.ByteSymbolMann)和女性形象(GV.ByteSymbolFrau)创建了全局字节数组。

在注册页面的启动代码中,我添加了:

 string cFilename = ""; if (GV.ByteSymbolMann == null) // not yet loaded { cFilename = GV.cEmbeddedAblage + "SymbolMann.jpg"; var assembly = this.GetType().GetTypeInfo().Assembly; byte[] buffer; using (Stream s = assembly.GetManifestResourceStream(cFilename)) { long length = s.Length; buffer = new byte[length]; s.Read(buffer, 0, (int)length); GV.ByteSymbolMann = buffer; // Overtake byte-array in global variable for male } } // if (GV.ByteSymbolFrau == null) // not yet loaded { cFilename = GV.cEmbeddedAblage + "SymbolFrau.jpg"; var assembly = this.GetType().GetTypeInfo().Assembly; byte[] buffer; using (Stream s = assembly.GetManifestResourceStream(cFilename)) { long length = s.Length; buffer = new byte[length]; s.Read(buffer, 0, (int)length); GV.ByteSymbolFrau = buffer; // Overtake byte-array in global variable for female } } 

将.jpg加载到图像对象的代码,我不得不改为:

 //Avatar.Source = "SymbolMann.jpg"; // Load from default directory 

 Avatar.Source = ImageSource.FromStream(() => new MemoryStream(GV.ByteSymbolMann)); // Load (stream) from byte-array 

然后我在另一个字节数组中接管选定的字节数组(与显示图像并行)(以便稍后以字符串forms上传到Web服务)

 AvatarErfassung = GV.ByteSymbolMann; 

如果用户更改选择(例如,更改为女性):

 Avatar.Source = ImageSource.FromStream(() => new MemoryStream(GV.ByteSymbolFrau)); AvatarErfassung = GV.ByteSymbolFrau; 

注意:如果用户从mediapicker中选择另一个图像,我可以直接访问该流,因此这绝不是问题所在。

此解决方案适用于所有平台(Android,iOS,WP)。

我希望这可以帮助其他一些用户…

而且……最后还要感谢Dimitris

谢谢@FredWenger和@Dimitris – 这是我的解决方案,基于你的答案:

  1. 将您的图像添加到Xamarin Forms(便携式)项目中,无论您喜欢什么。 我只是去了根: MyProject\DaffyDuck.jpg
  2. 将图像标记为Embedded Resource (文件属性 – >构建操作)
  3. 调用引用嵌入式资源的函数,如下所示: ImageDataFromResource("MyProject.DaffyDuck.jpg")
    请注意,您需要包含项目名称以获取程序集名称*。
  4. 这是function:

     public byte[] ImageDataFromResource(string r) { // Ensure "this" is an object that is part of your implementation within your Xamarin forms project var assembly = this.GetType().GetTypeInfo().Assembly; byte[] buffer = null; using (System.IO.Stream s = assembly.GetManifestResourceStream(r)) { if (s != null) { long length = s.Length; buffer = new byte[length]; s.Read(buffer, 0, (int)length); } } return buffer; } 
  5. 如果需要在ImageView控件中引用加载的数据,请执行以下操作:
    ImageView.Source = ImageSource.FromStream(() => new MemoryStream(imageData));

*注意:如果步骤3不起作用并且您想检查嵌入的资源名称,请调用: var names = assembly.GetManifestResourceNames(); 并查看项目中列出的内容。

让这个工作起来我遇到了很多问题。 我的项目已在其他地方使用FFImageLoading,我发现这是将.png作为流加载的最简单方法:

 using (var stream = await ImageService.Instance.LoadCompiledResource("resource_image.png").AsPNGStreamAsync()) { localBitmap = SKBitmap.Decode(stream); } 

确保您的资源文件在iOS和Droid项目中具有相同的名称。 他们可能已经将他们的构建操作设置为’BundleResource’(iOS)或’AndroidResource’(Droid)。

当然,你必须安装FFImageLoading Nuget,但你会很高兴你做到了。

我使用noelicus给出了想法并打印了ManifestResourceNames数组中的所有名称,我发现我的图像名称为ProjectName.Droid.image_name.jpeg 。然后我刚刚将assembly.GetManifestResourceStream("image_name.jpg")的方法调用更改为assembly.GetManifestResourceStream("ProjectName.Droid.image_name.jpeg") 。它工作正常。 所以正确的答案是:

  1. 将图像存储在PCL的根文件夹中。
  2. 将其作为嵌入式资源在属性中构建操作。
  3. 然后打印var names = assembly.GetManifestResourceNames()数组,这将是一个字符串数组,可以使用

     foreach(var data in names){Debug.WriteLine(data);} 
  4. 在那里,您将看到图像的资源名称,然后使用该方法

     Stream s = assembly.GetManifestResourceStream("resource_name_you_found.format") 

再加上noelicus的回答 :

建立

  1. 将您的图像添加到Xamarin.Forms项目的根文件夹,例如MyProject\pizza.png

  2. 在Visual Studio中,右键单击图像文件,然后选择“ Build Action – >“ EmbeddedResource

在此处输入图像描述

 public byte[] GetImageFromFile(string fileName) { var applicationTypeInfo = Application.Current.GetType().GetTypeInfo(); byte[] buffer; using (var stream = applicationTypeInfo.Assembly.GetManifestResourceStream($"{applicationTypeInfo.Namespace}.fileName")) { if (stream != null) { long length = stream.Length; buffer = new byte[length]; stream.Read(buffer, 0, (int)length); } } return buffer; } 

 public class MyPage() : ContentPage { public MyPage() { var imageAsByteArray = GetImageFromFile("pizza.png"); var pizzaImage = new Image(); pizzaImage.Source = ImageSource.FromStream(() => new MemoryStream(imageAsByteArray)); Content = pizzaImage; } byte[] GetImageFromFile(string fileName) { var applicationTypeInfo = Application.Current.GetType().GetTypeInfo(); byte[] buffer; using (var stream = applicationTypeInfo.Assembly.GetManifestResourceStream($"{applicationTypeInfo.Namespace}.fileName")) { if (stream != null) { long length = stream.Length; buffer = new byte[length]; stream.Read(buffer, 0, (int)length); } } return buffer; } }