需要帮助在 C# (winform) 中从仅资源 DLL 在图片框中显示图像

问题描述 投票:0回答:2

我是 Visual Studio 的新手,正在创建 winform,根据用户通过某些单选按钮组的输入,选择并在图片框中显示特定图像。 整个界面运行良好。

我通过项目本身内的 resx 资源使用大约 50 张图片进行了测试,效果也很好。

问题 -> 我将使用大约 3500 个图像(最初为 3500 个,当项目完成时将是 10.000+ 个图像),每当我将所有这些图像添加到 resx 中时,它就会停止工作。

可能的解决方案:

  1. 从外部文件结构加载图片(可以做到并且很容易,但我希望能够对其进行编译,以便最终用户无法查看、下载或修改“图像” - 图像应该只能通过应用程序)。 如果有一种方法可以包含文件夹结构(隐藏/编码在exe中),那将是我的首选,但我似乎找不到。 (然后我可以混淆 exe 并获得“一些”保护) 这是一个非常简单的“文件夹结构”(4 个文件夹,每个文件夹最终在所有模块完成后包含 1000 到 3500 张图像)

  2. 仅使用 DLL 资源存档并将其包含在构建中。 我正在对此进行测试(首先使用少量图像使其正常工作),但我遇到了一些问题。 我制作了一个仅包含一些 resx 资源(一组 png 图像)的 DLL - 第一次这样做,不确定是否应该添加或更改其中的一些设置??? (我将资源设为“公开”) 我在主应用程序的表单中引用了这个 DLL。我还在上面做了“使用...”。 当我尝试将资源加载到图片框中时,我能够看到资源。 该程序抛出一个错误,无法将“字节”转换为“图像”。 我遵循了这里一个非常旧的线程的建议,它表明直接引用 DLL 公共资源的方法应该可行......但事实并非如此。

对于使用系统 1 或 2 有什么建议以及可能的帮助或解决方案吗? 或者我忽略或不知道的更好的想法? (每张图片为 277kb,重要的是用户无法直接访问它们来复制/粘贴/分发/...)。 如果可能的话,我更喜欢在“构建中”拥有图像资源,而不是“类似云的解决方案”,因为我希望在“无互联网场景”中可以访问所有内容,例如在飞机上等。

lib reference

lib activated

old thread related to this

error message

Picbox command + error code

c# winforms dll compilation
2个回答
0
投票

当您说您将图像添加到 .resx 时,我不确定您是如何做到这一点的。但我会尝试的一件事是通过直接操作 .csproj 文件来嵌入它们。我尝试生成 3500 个交替测试图像(你说 277kb,这些恰好是 244kb)。

接下来,我生成了可以复制到 .csproj 中的标签

// Copy to cs.proj file
for (int i = 0; i <= 3500; i++) 
{
    Debug.WriteLine(@$"    <EmbeddedResource Include=""Images\sample-image-{i.ToString("D5")}.png"" />");
}

.csproj 中的最终结果为:


  <ItemGroup>
      <EmbeddedResource Include="Images\sample-image-00000.png" />
      <EmbeddedResource Include="Images\sample-image-00001.png" />
      <EmbeddedResource Include="Images\sample-image-00002.png" />
      <EmbeddedResource Include="Images\sample-image-00003.png" />
      <EmbeddedResource Include="Images\sample-image-00004.png" />
      <EmbeddedResource Include="Images\sample-image-00005.png" />
      <EmbeddedResource Include="Images\sample-image-00006.png" />
      <EmbeddedResource Include="Images\sample-image-00007.png" />
      <EmbeddedResource Include="Images\sample-image-00008.png" />
      <EmbeddedResource Include="Images\sample-image-00009.png" />
      <EmbeddedResource Include="Images\sample-image-00010.png" />
      <EmbeddedResource Include="Images\sample-image-00011.png" />
      .
      .
      .
      <EmbeddedResource Include="Images\sample-image-03497.png" />
      <EmbeddedResource Include="Images\sample-image-03498.png" />
      <EmbeddedResource Include="Images\sample-image-03499.png" />
      <EmbeddedResource Include="Images\sample-image-03500.png" />
  </ItemGroup>

那么您只需要一个扩展即可将嵌入图像加载到图片框中。

static class Extensions
{
    public static Image FromNamedResource(this string name)
    {
        using (Stream imageStream = typeof(MainForm).Assembly.GetManifestResourceStream(name))
        {
            if (imageStream == null)
            {
                return new Bitmap(0, 0);
            }
            else
            {
                return new Bitmap(imageStream);
            }
        }
    }
}

可执行文件大小高达 3/4 GB,但似乎可以正常构建和运行。也许您可以以此为起点并进一步实验。


这是我用来测试这个答案的代码:

namespace images_from_embedded_resource
{
    public partial class MainForm : Form
    {
        const int MAX_IMAGES = 3500;
        public MainForm()
        {
            InitializeComponent();
            buttonUpArrow.Text = "\u2191";
            buttonDownArrow.Click += (sender, e) => Index = Math.Min(Index + 1, MAX_IMAGES);
            buttonDownArrow.Text = "\u2193";
            buttonUpArrow.Click += (sender, e) => Index = Math.Max(Index - 1, 0);
            pictureBox.BackgroundImageLayout = ImageLayout.Stretch;
            Index = 0;

#if GENERATE_TEST_IMAGES
            for (int i = 2; i <= 3500; i++) 
            {
                // Alternating test images
                if(i%2 == 0)
                {
                    File.Copy(
                        @"D:\Github\stackoverflow\Tozz\images-from-embedded-resource\images-from-embedded-resource\Images\sample-image-00000.png",
                       $@"D:\Github\stackoverflow\Tozz\images-from-embedded-resource\images-from-embedded-resource\Images\sample-image-{i.ToString("D5")}.png",
                       overwrite: true
                    );
                }
                else
                {
                    File.Copy(
                        @"D:\Github\stackoverflow\Tozz\images-from-embedded-resource\images-from-embedded-resource\Images\sample-image-00001.png",
                       $@"D:\Github\stackoverflow\Tozz\images-from-embedded-resource\images-from-embedded-resource\Images\sample-image-{i.ToString("D5")}.png",
                       overwrite: true
                    );
                }
            }
#endif
#if GENERATE_CSPROJ_TAGS
            // Copy to cs.proj file
            for (int i = 0; i <= 3500; i++) 
            {
                Debug.WriteLine(@$"    <EmbeddedResource Include=""Images\sample-image-{i.ToString("D5")}.png"" />");
            }
#endif
            // Make sure resources are embedded
            foreach (var name in typeof(MainForm).Assembly.GetManifestResourceNames().Where(_ => _.Contains(".png")))
            {
                Debug.WriteLine(name);
            }
        }
        int _index = -1;
        public int Index
        {
            get => _index;
            set
            {
                if (!Equals(_index, value))
                {
                    _index = value;
                    pictureBox.BackgroundImage = $"images_from_embedded_resource.Images.sample-image-{Index.ToString("D5")}.png".FromNamedResource();
                    Text = $"{Index.ToString("D5")}";
                }
            }
        }
    }
}

0
投票

我现在已经应用了 IVSoftware 建议的内容。

  • 添加扩展
  • 在主应用程序中手动嵌入 3500 个 png(尚未执行 DLL)

新问题,只要我有“有限”的嵌入资源,我似乎就能够正确加载我的“表单设计器”。 当所有 3500 个文件都嵌入时(即使我可以完美地构建和运行应用程序),在 Visual Studio 中我无法再打开表单设计器,因为它会抛出此错误。 我需要表单设计者能够在未来进行一些附加组件和更改。

有什么想法吗? (我的系统中有 32GB 内存,所以这不会成为问题)

error message on designer load

**** 已修复*** 按照此处所述进行了“devenv / setup”,显然修复了它: 尝试在项目中添加引用时出现“值不在预期范围内”

© www.soinside.com 2019 - 2024. All rights reserved.