如何从System.Drawing.Bitmap对象中提取原始图像流?

时间:2010-04-28 15:15:31

标签: c# resources resx system.drawing

我使用.resx文件将图像嵌入到我的程序集中。在运行时,我需要将图像保存到独立文件中,恢复原始内容。如何从System.Drawing.Bitmap实例中提取原始文件流?我知道我可以使用Bitmap.Save()创建一个流,但这会对图像进行转码(实际上是膨胀),即使将PNG保存为PNG也是如此。

或许我的错误是首先从Resource读取Bitmap

5 个答案:

答案 0 :(得分:2)

是的,一旦您将其作为Bitmap对象读取,就无法恢复原始文件流。 Bitmap对象仅包含未压缩的数据,而不包含原始数据。

您应该将资源读取为字节数据intead。您可以从资源流中读取并写入文件:

using (Stream source = this.GetType().Assembly.GetManifestResourceStream("WindowsApplication1.filename.jpg")) {
  using (FileStream dest = File.Create(fileName)) {
    byte[] buffer = new byte[4096];
    while (true) {
      int len = source.Read(buffer, 0, buffer.Length);
      if (len == 0) break;
      dest.Write(buffer, 0, len);
    }
  }
}

注意:这需要将图像添加为嵌入式资源,而不是托管资源。您可以使用Image从<{1}}创建Image.FromStream()

答案 1 :(得分:2)

我没有遇到问题。 PNG是一种无损格式,您将获得完全相同的图像。是的,当你保存()时,你不一定得到完全相同的字节。它是一种压缩格式,压缩器在压缩和速度之间达到最佳平衡所花费的时间可能不一样。但是,那又怎么样?

如果这是一个真正的问题,那么您不应该将图像添加为托管资源。您可以将其作为嵌入式资源添加到项目中,并使用Assembly.GetManifestResourceStream()从元数据中读取它。您将获得原始图像文件字节。使用Image.FromStream()转换为图像。

答案 2 :(得分:1)

答案 3 :(得分:1)

如果您实际上没有在应用程序中使用Bitmap进行显示(即您只是将资源提取为位图,以便将其保存为文件),那么最简单的方法是只需将资源作为Stream并将其保存到文件中。

本教程介绍如何将资源作为流获取:

http://devhood.com/Tutorials/tutorial_details.aspx?tutorial_id=75

在示例中,作者获取一个流并将其传递给Bitmap.FromStream方法。您要做的只是将该流直接保存到文件中(完全绕过Bitmap)。

答案 4 :(得分:0)

事实证明问题在于使用托管资源--resx builder从图像文件创建 Bitmap 对象并序列化这些对象,不存储原始文件流。但是,嵌入式资源可以存储平面二进制文件。

我现在使用以下.csproj条目嵌入我的images文件夹中的所有文件:

<EmbeddedResource Include="Images\*.jpg" />
<EmbeddedResource Include="Images\*.png" />
<EmbeddedResource Include="Images\*.gif" />

Visual Studio将它们显示为正常的项目内文件,Build Action设置为Embedded Resource

然后,从我的代码中,我用以下内容加载原始文件流:

var assembly = GetType().Assembly;
var regex = new Regex("\\.(png|jpg|gif))$");
foreach (var bitmap in assembly.GetManifestResourceNames())
{
  if(!regex.IsMatch(bitmap)
    continue;

  var stream = assembly.GetManifestResourceStream(bitmap);
  //handle the stream here
}