Pack URI to image embedded in a resx file

3 浏览
0 Comments

Pack URI to image embedded in a resx file

如何构建指向资源文件中图像的Pack URI?

我有一个名为MyAssembly.Resources.dll的程序集,其中有一个名为Images的文件夹,然后在其中有一个名为Assets.resx的资源文件。这个资源文件包含了我的图像(名为MyImage.png)。我的代码行如下:

uri = new Uri("pack://application:,,,/MyAssembly.Resources,Culture=neutral,PublicKeyToken=null;component/Images/Assets/MyImage.png");

然而,当我尝试将这个URI提供给一个新的BitmapImage的构造函数时,我得到一个IOException,错误消息为:

无法找到资源“images/assets/myimage.png”。

请注意,我在同一个程序集中还有其他的松散图像,我可以使用pack URI正确检索这些图像,这些图像的构建操作设置为Resource但它们没有嵌入在resx文件中。我应该在路径中包含resx文件的名称吗?

(我希望将图像嵌入到resx文件中,以便可以利用UI区域设置来检索正确的图像(图像包含文本))。

0
0 Comments

Pack URI to image embedded in a resx file(嵌入在resx文件中的图像的打包URI)问题的出现是因为从resx文件中获取的是System.Drawing.Bitmap对象,而需要将其转换为System.Windows.Media.ImageSource或其子类型。

解决方法是使用一个简单的代理,通过这个代理从resx文件中获取图像。首先,定义一个ValueConverter来提供ImageSource。然后,在XAML中使用这个ValueConverter来绑定Image的Source属性。

代码示例如下:


    
        
        
    
    

AssetsProxy:

namespace MyAssembly.Resources
{
    public class AssetsProxy : Images.Assets
    {
        public AssetsProxy() : base() { }
    }
}

Bitmap to ImageSource conversion:

using System;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Windows.Data;
using System.Windows.Media.Imaging;
namespace MyAssembly.Resources
{
    public class BitmapToImageSourceConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            BitmapImage bitmapImage = null;
            if (value is System.Drawing.Image)
            {
                bitmapImage = ((System.Drawing.Image)value).ToBitmapImage();
            }
            return bitmapImage;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    public static class BitmapExtensions
    {
        public static BitmapImage ToBitmapImage(this System.Drawing.Image bitmap)
        {
            BitmapImage bitmapImage = null;
            if (bitmap != null)
            {
                using (MemoryStream memory = new MemoryStream())
                {
                    bitmapImage = new BitmapImage();
                    bitmap.Save(memory, ImageFormat.Png);
                    memory.Position = 0;
                    bitmapImage.BeginInit();
                    bitmapImage.StreamSource = memory;
                    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                    bitmapImage.EndInit();
                }
            }
            return bitmapImage;
        }
    }
}

以上是解决Pack URI to image embedded in a resx file问题的方法。

0
0 Comments

Pack URI to image embedded in a resx file问题的出现原因是因为在使用Resx编辑器添加图像时,它会将图像标记为嵌入资源,并将其存储为System.Drawing.Bitmap类型。而WPF期望的是System.Windows.Media.ImageSource类型。

解决方法是将资源文件中的图像标记为Resource Build Action。这样WPF就能够正确识别资源文件中的图像。

下面是一个示例项目,其中包含两个图像。通过文件名可以明显看出,cat_embedded.jpg使用的是Embedded Resource Build Action,而cat_resource.jpg使用的是Resource Build Action。

在ILSpy中查看这两个文件时,可以看到cat_resource.jpg位于ImageLib.g.resources部分。这就是WPF查找资源的位置。路径名也是资源名称的一部分。因此,当使用以下路径时:

var uri = new Uri("pack://application:,,,/ImageLib;component/Images/cat_resource.jpg");

需要在单词;component之后指定匹配的路径。

另一个jpg文件位于程序集中的不同位置,并且在名称中使用了句点(ImageLib.Images.cat_embedded.jpg)。尝试使用多个不同形式的字符串来获取cat_embedded.jpg图像,但WPF将无法找到它。

在另一个示例项目中,有两个图像,其中一个是资源,另一个是通过resx编辑器添加的。与之前嵌入图像示例使用的URI位置相同。

根据你在问题中提到的,你想要实现的是图像的本地化。你是否看过这篇MSDN文章?WPF全球化和本地化概述。

总之,要解决Pack URI to image embedded in a resx file问题,需要将资源文件中的图像标记为Resource Build Action,并使用正确的Pack URI路径来引用图像。

0
0 Comments

从上述内容可以整理出以下问题的出现原因和解决方法:

问题:如何使用Pack URI来引用嵌入在resx文件中的图像资源?

原因:Pack URI方案与规范化的Open Packaging Conventions规范相关,而不是与.NET嵌入式资源相关。因此,无法直接使用Pack URI方案来引用嵌入在resx文件中的图像资源。

解决方法:可以定义自己的URI方案,例如"resx",并在WPF组件的URI中使用它。可以使用WebRequest.RegisterPrefix方法来定义用于此类用途的新URI方案。

以下是一个示例,以WpfApplication1项目为例,该项目中定义了一个Resource1.resx文件,其中包含一个名为"img"的图像资源。

MainWindow.xaml示例代码:


    

URI格式如下:

resx://程序集名称/资源集名称/资源名称

其中,程序集名称是可选的,因此以下格式也是有效的:

resx:///资源集名称/资源名称

需要在App.xaml.cs或其他地方注册新的URI方案,示例代码如下:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        ResXWebRequestFactory.Register();
        base.OnStartup(e);
    }
}

以下是实现该方案的代码:

public sealed class ResXWebRequestFactory : IWebRequestCreate
{
    public const string Scheme = "resx";
    private static ResXWebRequestFactory _factory = new ResXWebRequestFactory();
    private ResXWebRequestFactory()
    {
    }
    // call this before anything else
    public static void Register()
    {
        WebRequest.RegisterPrefix(Scheme, _factory);
    }
    WebRequest IWebRequestCreate.Create(Uri uri)
    {
        return new ResXWebRequest(uri);
    }
    private class ResXWebRequest : WebRequest
    {
        public ResXWebRequest(Uri uri)
        {
            Uri = uri;
        }
        public Uri Uri { get; set; }
        public override WebResponse GetResponse()
        {
            return new ResXWebResponse(Uri);
        }
    }
    private class ResXWebResponse : WebResponse
    {
        public ResXWebResponse(Uri uri)
        {
            Uri = uri;
        }
        public Uri Uri { get; set; }
        public override Stream GetResponseStream()
        {
            Assembly asm;
            if (string.IsNullOrEmpty(Uri.Host))
            {
                asm = Assembly.GetEntryAssembly();
            }
            else
            {
                asm = Assembly.Load(Uri.Host);
            }
            int filePos = Uri.LocalPath.LastIndexOf('/');
            string baseName = Uri.LocalPath.Substring(1, filePos - 1);
            string name = Uri.LocalPath.Substring(filePos + 1);
            ResourceManager rm = new ResourceManager(baseName, asm);
            object obj = rm.GetObject(name);
            Stream stream = obj as Stream;
            if (stream != null)
                return stream;
            Bitmap bmp = obj as Bitmap; // System.Drawing.Bitmap
            if (bmp != null)
            {
                stream = new MemoryStream();
                bmp.Save(stream, bmp.RawFormat);
                bmp.Dispose();
                stream.Position = 0;
                return stream;
            }
            // TODO: add other formats
            return null;
        }
    }
}

感谢Simon的回答。我有几个备选方案,但你的方案基本上满足了我的期望 - 使用这个方案,我可以在需要的代码中保持一致性,而不需要根据图像是松散打包还是嵌入在resx中来复杂化代码。

0