开发者

How can I extract the original image stream from a System.Drawing.Bitmap object?

开发者 https://www.devze.com 2022-12-28 17:12 出处:网络
I am embedding images开发者_开发问答 into my assembly using .resx files. Upon runtime, I need to save the images into standalone files, restoring the original content. How can I extract the original f

I am embedding images开发者_开发问答 into my assembly using .resx files. Upon runtime, I need to save the images into standalone files, restoring the original content. How can I extract the original file stream from an System.Drawing.Bitmap instance? I know I can create a stream using Bitmap.Save(), but this transcodes (and in effect - inflates) the images, even when saving a PNG back as PNG.

Or perhaps my mistake is reading them from Resource as Bitmap in the first place?


Yes, once you have read it as a Bitmap object, you can't get the original file stream back. The Bitmap object only contains the uncompressed data, not the original data.

You should read the resource as byte data intead. You can read from the resource stream and write to a file:

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);
    }
  }
}

Note: this requires adding the image as an embedded resource, not a managed resource. You can create an Image from it using Image.FromStream().


I don't get the problem. PNG is a loss-less format, you'll get the exact same image back. Yes, you don't necessarily get the exact same bytes when you Save(). It is a compressed format and the amount of time spent by the compressor on getting the best balance between compression and speed might not be the same. But, so what?

If it is a real problem then you shouldn't add the image as a managed resource. You can add it to your project as an embedded resource and read it from the metadata with Assembly.GetManifestResourceStream(). You'll get the raw image file bytes. Convertible to an Image with Image.FromStream().


HOW TO: Load a Bitmap or Image from a Resource by Using Visual C#


If you're not actually using the Bitmap for display purposes in your appliction (i.e. you're just extracting the resource as a bitmap so you can save it as a file), then the simplest approach is to just get the resource as a Stream and save it to a file.

This tutorial shows how to get resources as streams:

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

In the sample, the author gets a stream and passes it to the Bitmap.FromStream method. What you would do instead is just save that stream directly to a file (bypassing Bitmap entirely).


It turns out the problem was in using managed resources - resx builder creates Bitmap objects from image files and serializes those objects, it does not store the original file stream. However, embedded resources can store flat binary files.

I am now embedding all files from my images folder using the following .csproj entries:

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

Visual Studio shows them as normal in-project files with Build Action set to Embedded Resource.

Then, from my code, I load the original file streams with:

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
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号