【问题标题】:how to use GetResourceData如何使用获取资源数据
【发布时间】:2013-02-10 15:27:35
【问题描述】:

我使用以下命令创建了一个包含 PNG 文件的资源文件:

resgen.exe Test3.resx Test3.resources

我可以遍历资源,并且可以成功地看到它们被包含在内, 我还可以看到每个元素的数据类型是System.Drawing.Bitmap, 但是我无法将字节数组转换回位图,

要么 PNG 需要不同的检索和转换,要么我快疯了

有人知道我错过了什么吗?

   Public Function GetImageResources() As Dictionary(Of String, Bitmap)

    Dim resourceReader As New ResourceReader(".\Test3.resources")
    Dim resourcesEnumerator As IDictionaryEnumerator = resourceReader.GetEnumerator()
    Dim resourcesFound As New Dictionary(Of String, Bitmap)

    Do While resourcesEnumerator.MoveNext()

        Dim dataType As String = Nothing
        Dim data() As Byte = Nothing
        resourceReader.GetResourceData(resourcesEnumerator.Key, dataType, data)

        Dim finalImage As New Bitmap(New MemoryStream(data))
        'RUNTIME ERROR: Parameter is not valid
        'dataType value = System.Drawing.Bitmap, System.Drawing, ...

        resourcesFound.Add(resourcesEnumerator.Key.ToString(), finalImage)

    Loop
    resourceReader.Close()


    Return resourcesFound
End Function

【问题讨论】:

    标签: .net vb.net winforms bitmap embedded-resource


    【解决方案1】:

    还不知道如何使用 GetResourceData,但我至少这段代码能达到同样的效果:

    Public Function GetImageResources() As Dictionary(Of String, Bitmap)
    
        Dim resourcesFound As New Dictionary(Of String, Bitmap)
    
        Dim resourceReader As New ResourceReader(".\Test3.resources")
        Dim resourcesEnumerator As IDictionaryEnumerator = resourceReader.GetEnumerator()
        Dim resourceSet As New ResourceSet(".\Test3.resources")
    
        Do While resourcesEnumerator.MoveNext()
    
            Dim retrievedObject As Object = resourceSet.GetObject(resourcesEnumerator.Key.ToString())
    
            Dim convertedBitmap As Bitmap = DirectCast(retrievedObject, Bitmap)
            resourcesFound.Add(resourcesEnumerator.Key.ToString(), convertedBitmap)
    
        Loop
        resourceReader.Close()
        resourceSet.Close()
    
        Return resourcesFound
    End Function
    

    【讨论】:

      【解决方案2】:

      我在同样的问题上苦苦挣扎。我发现当保存到资源文件时,字节数组的前面会添加四个字节。我不知道为什么,也没有找到任何文档。无论如何,以下内容将有助于正确地将您的图像数据转换回来:

      public Image FixImageDataFromResourceFile(byte[] byteArrayFromResourceFile)
      {
          byte[] fixedImageData = new byte[byteArrayFromResourceFile.Length - 4];
          Array.Copy(byteArrayFromResourceFile, 4, fixedImageData, 0, fixedImageData.Length);
          MemoryStream ms = new MemoryStream(fixedImageData);
          Image retval = Bitmap.FromStream(ms);
          ms.Close();
          return retval;
      }
      

      如果有人知道这四个字节的用途或可以找到有关它的文档,我很想知道它。我唯一的猜测是这四个字节用于识别资源文件中的数据类型,但肯定会使任何信息在没有适当通知的情况下无用。

      【讨论】:

        【解决方案3】:

        我也遇到了同样的问题。由于 DataType: ResourceTypeCode.Stream 始终存在偏移量 4,我很难读取资源流。您可以在Microsoft code in MSDN 中看到该偏移量(该代码非常适合位图)。

        我在GitHub做了一个关于资源读取和uri的小项目

        对于构建操作定义为“资源”的图像(在文件夹“[YourProject]/Icons/About.png”中):

                System.IO.Stream stream = HQ.Util.General.ResourceHelper.LoadResourceFromUri(
                    HQ.Util.General.ResourceHelper.GetLocationUri("Icons/About.png"));
        
                Image image = new Bitmap(stream);
        

        这是我的 ResourceHelper 文件(如果它可以帮助你)...

        using System;
        using System.Collections;
        using System.Collections.Generic;
        using System.Diagnostics;
        using System.Drawing;
        using System.IO;
        using System.Linq;
        using System.Reflection;
        using System.Resources;
        using System.Runtime.Serialization.Formatters.Binary;
        using System.Text;
        using System.Threading.Tasks;
        using System.Windows.Resources;
        
        namespace HQ.Util.General
        {
            public static class ResourceHelper
            {
                // ******************************************************************
                /// <summary>
                /// The resource should be defined as 'Resource' not as 'Embedded resource'.
                /// </summary>
                /// <param name="resourcePath">The resource path</param>
                /// <param name="assembly">If null, then use calling assembly to find the resource</param>
                /// <returns></returns>
                public static Uri GetLocationUri(string resourcePath, Assembly assembly = null)
                {
                    if (assembly == null)
                    {
                        assembly = Assembly.GetCallingAssembly();
                    }
        
                    resourcePath = resourcePath.Replace('\\', '/');
        
                    return new Uri(@"pack://application:,,,/" + assembly.GetName().Name + ";component" +
                        (resourcePath[0] == '/' ? resourcePath : "/" + resourcePath), UriKind.Absolute);
                }
        
                // ******************************************************************
                /// <summary>
                /// Will load resource from any assembly that is part of the application.
                /// It does not rely on Application which is specific to a (UI) frameowrk.
                /// </summary>
                /// <param name="uri"></param>
                /// <param name="asm"></param>
                /// <returns></returns>
                public static Stream LoadResourceFromUri(Uri uri, Assembly asm = null)
                {
                    Stream stream = null;
        
                    if (uri.Authority.StartsWith("application") && uri.Scheme == "pack")
                    {
                        string localPath = uri.GetComponents(UriComponents.Path, UriFormat.UriEscaped);
        
                        int indexLocalPathWithoutAssembly = localPath.IndexOf(";component/");
                        if (indexLocalPathWithoutAssembly == -1)
                        {
                            indexLocalPathWithoutAssembly = 0;
                        }
                        else
                        {
                            indexLocalPathWithoutAssembly += 11;
                        }
        
                        if (asm != null) // Take the provided assembly, do not check for the asm in the uri.
                        {
                            stream = GetAssemblyResourceStream(asm, localPath.Substring(indexLocalPathWithoutAssembly));
                        }
                        else
                        {
                            if (uri.Segments.Length > 1)
                            {
                                if (uri.Segments[0] == "/" && uri.Segments[1].EndsWith(";component/"))
                                {
                                    int index = uri.Segments[1].IndexOf(";");
                                    if (index > 0)
                                    {
                                        string assemblyName = uri.Segments[1].Substring(0, index);
        
                                        foreach (Assembly asmIter in AppDomain.CurrentDomain.GetAssemblies())
                                        {
                                            if (asmIter.GetName().Name == assemblyName)
                                            {
                                                stream = GetAssemblyResourceStream(asmIter, localPath.Substring(indexLocalPathWithoutAssembly));
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
        
                            if (stream == null)
                            {
                                asm = Assembly.GetCallingAssembly();
                                stream = GetAssemblyResourceStream(asm, localPath.Substring(indexLocalPathWithoutAssembly));
                            }
                        }
                    }
                    return stream;
                }
        
                // ******************************************************************
                /// <summary>
                /// The path separator is '/'.  The path should not start with '/'.
                /// </summary>
                /// <param name="asm"></param>
                /// <param name="path"></param>
                /// <returns></returns>
                public static Stream GetAssemblyResourceStream(Assembly asm, string path)
                {
                    // Just to be sure
                    if (path[0] == '/')
                    {
                        path = path.Substring(1);
                    }
        
                    // Just to be sure
                    if (path.IndexOf('\\') == -1)
                    {
                        path = path.Replace('\\', '/');
                    }
        
                    Stream resStream = null;
        
                    string resName = asm.GetName().Name + ".g.resources"; // Ref: Thomas Levesque Answer at:
                    // http://stackoverflow.com/questions/2517407/enumerating-net-assembly-resources-at-runtime
        
                    using (var stream = asm.GetManifestResourceStream(resName))
                    {
                        using (var resReader = new System.Resources.ResourceReader(stream))
                        {
                            string dataType = null;
                            byte[] data = null;
                            try
                            {
                                resReader.GetResourceData(path.ToLower(), out dataType, out data);
                            }
                            catch (Exception ex)
                            {
                                DebugPrintResources(resReader);
                            }
        
                            if (data != null)
                            {
                                switch (dataType) // COde from 
                                {
                                    // Handle internally serialized string data (ResourceTypeCode members).
                                    case "ResourceTypeCode.String":
                                        BinaryReader reader = new BinaryReader(new MemoryStream(data));
                                        string binData = reader.ReadString();
                                        Console.WriteLine("   Recreated Value: {0}", binData);
                                        break;
                                    case "ResourceTypeCode.Int32":
                                        Console.WriteLine("   Recreated Value: {0}", BitConverter.ToInt32(data, 0));
                                        break;
                                    case "ResourceTypeCode.Boolean":
                                        Console.WriteLine("   Recreated Value: {0}", BitConverter.ToBoolean(data, 0));
                                        break;
                                    // .jpeg image stored as a stream.
                                    case "ResourceTypeCode.Stream":
                                        ////const int OFFSET = 4;
                                        ////int size = BitConverter.ToInt32(data, 0);
                                        ////Bitmap value1 = new Bitmap(new MemoryStream(data, OFFSET, size));
                                        ////Console.WriteLine("   Recreated Value: {0}", value1);
        
                                        const int OFFSET = 4;
                                        resStream = new MemoryStream(data, OFFSET, data.Length - OFFSET);
        
                                        break;
                                    // Our only other type is DateTimeTZI.
                                    default:
                                        ////// No point in deserializing data if the type is unavailable.
                                        ////if (dataType.Contains("DateTimeTZI") && loaded)
                                        ////{
                                        ////    BinaryFormatter binFmt = new BinaryFormatter();
                                        ////    object value2 = binFmt.Deserialize(new MemoryStream(data));
                                        ////    Console.WriteLine("   Recreated Value: {0}", value2);
                                        ////}
                                        ////break;
                                        break;
                                }
        
                                // resStream = new MemoryStream(resData);
                            }
                        }
                    }
        
                    return resStream;
                }
        
                // ******************************************************************
                private static void DebugPrintResources(System.Resources.ResourceReader reader)
                {
                    Debug.Print("Begin dump resources: ---------------------");
                    foreach (DictionaryEntry item in reader)
                    {
                        Debug.Print(item.Key.ToString());
                    }
                    Debug.Print("End   dump resources: ---------------------");
                }
        
                // ******************************************************************        // ******************************************************************
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-04-18
          • 1970-01-01
          • 1970-01-01
          • 2020-02-06
          • 1970-01-01
          • 1970-01-01
          • 2011-02-05
          相关资源
          最近更新 更多