WPF BitmapSource ImageSource - c#

I am binding an Image.Source property to the result of the property shown below.
public BitmapSource MyImageSource
{
get
{
BitmapSource source = null;
PngBitmapDecoder decoder;
using (var stream = new FileStream(#"C:\Temp\logo.png", FileMode.Open, FileAccess.Read, FileShare.Read))
{
decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
if (decoder.Frames != null && decoder.Frames.Count > 0)
source = decoder.Frames[0];
}
return source;
}
}
For some reason this is failing during the rendering of the image (Deep in the PresentationCore assembly). I am certain the image is not corrupt as I can successfully show the same image w/o the binding
<Image Name="FooImage" Source="/logo.png" />
I have to bind the image source in code because I will eventually be creating the image stream from a base64 string.
Anyone know if this is a bug w/ WPF? or am I doing something incorrectly?

The problem was the BitmapCacheOption option, changing to BitmapCacheOption.OnLoad works.
With BitmapCacheOption.None the BitmapSource isn’t decoded until the image is rendered, but the stream with the png in it is already disposed at that point. If you cache OnLoad, it’ll decode right away and cache the results, rather than trying to decode later when the stream no longer exists.

Also, have you tried just using a BitmapImage to load the image? It works fine with PNG, BMP, and JPEG.
It's also a specialized type of BitmapSource, so you could just replace your code in your property with this:
BitmapImage img = new BitmapImage(new Uri(#"C:\Temp\logo.png"));
return img;

Are you positive it's a PNG and not just a renamed Bitmap or Jpeg? If you create a new Bitmap image and then just rename it and change the file extension, this error is reproducible.
If I use a known PNG with your code, I don't get your issue, but a COM exception is thrown:
The handle is invalid. (Exception from HRESULT: 0x80070006 (E_HANDLE))
Can you try it out with a random PNG off the web and see if you get the same result?

Related

Image.GetThumbnailImage throws OutOfMemoryException

The following C# 3.5 code throws an exception in GetThumbnailImage:
Image img = null;
Image scaledImg = null;
byte[] imageData = File.ReadAllBytes("11001.jpg");
MemoryStream stream = new MemoryStream(imageData);
img = Image.FromStream(stream);
stream.Close();
stream.Dispose();
scaledImg = img.GetThumbnailImage(64, 64, null, IntPtr.Zero);
The problem is the disposing of the stream. If I remove the Close() and Dispose() statement, everything works fine. Does anyone know why this exception is thrown? Using a callback instead of null as parameter does not change the behavior.
I don't need a solution, I can use new Bitmap(img, new Size(width, height) for scaling. This is probably better and shoud have been used from the beginning.
Edit: Sorry, I forgot to mention that the exception only occurs in WindowsXP. Win7 and Win8 seem to handle the above code just fine.
GetThumbnailImage is a native method, using the same stream you passed while creating the Image. Only the .NET methods are using the actual data from the stream (it's loaded as the last thing while creating the image from a stream).
It's a pretty typical leaky abstraction. You thought you have an Image object that already has its data loaded, but the data is only loaded in the .NET part. Any method that works directly with the GDI+ image handle will still need the stream to be live.
Another example of the same problem is while trying to save the image in a different format. When you try to save with the same format, .NET just saves the byte data it has in memory, simple. If it's not the same, it will use the GDI+ method SaveImageToFile, which again requires the original stream to be preserved.
If you don't mind having the stream alive, you can just move the Dispose after everything you do with the images produced from that stream:
using (var stream = new MemoryStream(imageData))
{
var img = Image.FromStream(stream);
var scaledImg = img.GetThumbnailImage(64, 64, null, IntPtr.Zero);
scaledImg.Save(...);
}
If you do mind, the easiest thing you can do is this:
var bmp = new Bitmap(Image.FromStream(stream));
The Bitmap constructor will copy the image data, and you no longer need to keep the stream.
I think that GetThumbnailImage uses the stream to do its job so it needs it to be open.You can do it like this :
Image img = null;
Image scaledImg = null;
byte[] imageData = File.ReadAllBytes("11001.jpg");
using(MemoryStream stream = new MemoryStream(imageData))
{
img = Image.FromStream(stream);
scaledImg = img.GetThumbnailImage(64, 64, null, IntPtr.Zero);
}
(using closes and disposes the MemoryStream but it also handles exceptional situations to avoid memory leaks)
The Image object uses lazy evaluation. As you have already closed the stream, when it actually tries to read the image in order to get the thumbnail, it's not there anymore. Hence the error.

How to convert BitmapFrame into BitmapImage

My program uses some WPF APIs to process images in a folder. I need to parse EXIF data from the images if there is any in order to get the value of the DateTimeOriginal property. I've been using a BitmapImage to load the image from a MemoryStream, but I need a BitmapFrame object to get at the BitmapMetadata object.
Here's my original code before I was given the requirement to get the DateTimeOriginal EXIF property:
BitmapImage src = new BitmapImage();
try {
using ( MemoryStream memoryStream = new MemoryStream( snapshot.ImageData ) ) {
src.BeginInit();
src.CacheOption = BitmapCacheOption.OnLoad;
src.StreamSource = memoryStream;
src.EndInit();
}
} catch ( NotSupportedException ex ) {
. . .
}
Now, to get the BitmapFrame, I need to create a BitmapDecoder and use the Frames[0] property. So I added the following right after the using statement:
BitmapDecoder decoder = BitmapDecoder.Create( memoryStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad );
This decodes the bitmap and gets the first Frame, which is cool. I still need to create the BitmapImage. I can do that by resetting the MemoryStream's position back to the beginning and keeping the code that's already there, but this will decode the same image a second time.
Is there a way I can convert the BitmapFrame into a BitmapImage? I thought I would cast the BitmapFrame into a BitmapSourceobject and then set the BitmapImage's Source propert, but the BitmapImage class doesn't seem to have a Source property.
Is this possible? If so, how is it done?
There should be no need for this conversion. The Remarks section in the BitmapImage MSDN page says:
BitmapImage primarily exists to support Extensible Application Markup
Language (XAML) syntax and introduces additional properties for bitmap
loading that are not defined by BitmapSource.
When using bitmaps, your application should usually always use the BitmapSource or ImageSource base classes. For example when you assign the Source property of the WPF Image control, you can use an instance of any type derived from ImageSource, because that is the type of the Source property.
So you could directly use a BitmapFrame because it also derives from ImageSource:
var bitmap = BitmapFrame.Create(
memoryStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
image.Source = bitmap;

Image cropped in rendering with GDI+

I am using my own class for image processing , like load , thumbnail , ....
In general , this code create images object;
Bitmap result = new Bitmap(width, height, PixelFormat.Format32bppArgb);
and this code post it to response object to show in browser.
HttpContext.Current.Response.AddHeader("ContentType", "image/png");
using (MemoryStream memStream = new MemoryStream())
{
memStream.Seek(0, SeekOrigin.Begin);
Result.Save(memStream, ImageFormat.Png);
memStream.WriteTo(HttpContext.Current.Response.OutputStream);
}
Result.Dispose();
In some cases , the browser(s) show the correct image but sometimes show the cropped image like this.
Is this image breaking related to my code or related to browsers ?
If the image format is PNG, you need to use an intermediate MemoryStream (because PNGs require a seekable stream to be saved). Try using jpg file to see that your code is working.
Check ASP.NET [Image Handler]

Bad RawFormat when loading emf file

I'm trying to load an emf file in to an Image Object, however the RawFormat is always incorrect {[ImageFormat: b96b3cac-0728-11d3-9d7b-0000f81ef32e]} instead of Emf. I've tried loading from a file stream and memory stream. I've also tried creating a MetaFile object instead of an Image but to no avail. Is this a bug or there some other trick I don't know about?
MemoryStream stream = new MemoryStream(imageData);//imageData is a byte array
Image tempImage = Image.FromStream(stream);
Does this help?
System.Drawing.Imaging.ImageFormat.Emf.Guid = {b96b3cac-0728-11d3-9d7b-0000f81ef32e}
Dan

.NET BitmapSource is locking file

I am using this C# code to access an image file in order to read metadata from it.
BitmapSource img = BitmapFrame.Create(uri);
Unfortunately the image file specified by uri becomes locked until the program ends. How do I prevent the image from being locked?
maybe this could help ?
edit
BitmapSource img = BitmapFrame.Create(uri,BitmapCreateOptions.None,BitmapCacheOption.OnLoad);
BitmapCreateOptions.None = default option
BitmapCacheOption.OnLoad = Caches the entire image into memory at load time. All requests for image data are filled from the memory store.
from here
If you want to be able to delete/change the file immediately afterwards, read the whole file into memory, and then give it the MemoryStream instead. For example:
MemoryStream data = new MemoryStream(File.ReadAllBytes(file));
BitmapSource bitmap = BitmapFrame.Create(data);
You can also use generic stream:
Stream stream = File.OpenRead(filename);
Bitmap template = new Bitmap(stream); // or (Bitmap) Bitmap.FromStream(stream)
stream.Close();

Categories

Resources