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

Fre*_*ger 6 c# image xamarin xamarin.forms

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

我使用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";  
Run Code Online (Sandbox Code Playgroud)

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

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

谢谢你的每一个答案

嗨迪米特里斯

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

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

var assembly = this.GetType().GetTypeInfo().Assembly;
Run Code Online (Sandbox Code Playgroud)

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

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

您编写://您可以将"this.GetType()"替换为"typeof(MyType)",其中MyType是程序集中的任何类型.

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

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

感谢您的进一步回复.

更新#2:

第一,谢谢你的耐心......

不幸的是在VS2013中,我没有找到任何显示我缺少使用的功能"解析" - 但我发现了使用我自己的缺失:-)
同时我添加了使用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选择另一个图像,我可以访问流,问题是,从默认图像(在每个平台中)成为字节数组.

再次感谢您的帮助......

Dim*_*kos 12

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

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
Run Code Online (Sandbox Code Playgroud)

编辑:

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

public class MyCustomPage : ContentPage {}
Run Code Online (Sandbox Code Playgroud)

......这就是你要通过的: typeof(MyCustomPage)

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

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

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

在Xamarin Studio中单击鼠标右键

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

更多关于在Xamarin形成图像这里.


Fre*_*ger 7

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

结论:

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

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

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

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

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

在我的应用程序启动代码(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.";
Run Code Online (Sandbox Code Playgroud)

其中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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

//Avatar.Source = "SymbolMann.jpg";  // Load from default directory
Run Code Online (Sandbox Code Playgroud)

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

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

AvatarErfassung = GV.ByteSymbolMann;
Run Code Online (Sandbox Code Playgroud)

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

Avatar.Source = ImageSource.FromStream(() => new MemoryStream(GV.ByteSymbolFrau)); 
AvatarErfassung = GV.ByteSymbolFrau;
Run Code Online (Sandbox Code Playgroud)

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

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

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

而且......最后还要感谢Dimitris


noe*_*cus 7

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

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

    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;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  5. 如果需要在ImageView控件中引用加载的数据,请执行以下操作:
    ImageView.Source = ImageSource.FromStream(() => new MemoryStream(imageData));

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

  • 这是一个非常有用的总结 - 谢谢!特别是关于嵌入式资源和assembly.GetManifestResourceNames()的注释 - 你是一个传奇 (2认同)

Bra*_*ick 5

添加到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;
}
Run Code Online (Sandbox Code Playgroud)

例子

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;
    }
}
Run Code Online (Sandbox Code Playgroud)