views:

459

answers:

3

I need to open all frames from Tiff image in WPF into memory and then delete the source. And after that I eventually need to render that image (resized according to window size). My solution is quite slow and I cannot delete file source before the first require. Any best practices?

+3  A: 

Use CacheOption = BitmapCacheOption.OnLoad

This option can be used with the BitmapImage.CacheOption property or as an argument to BitmapDecoder.Create() If you want to access multiple frames once the images is loaded you'll have to use BitmapDecoder.Create. In either case the file will be loaded fully and closed.

See also my answer to this question

Update

The following code works perfectly for loading in all the frames of an image and deleting the file:

var decoder = BitmapDecoder.Create(new Uri(imageFileName), BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
List<BitmapFrame> images = decoder.Frames.ToList();
File.Delete(imageFileName);

You can also access decoder.Frames after the file is deleted, of course.

This variant also works if you prefer to open the stream yourself:

List<BitmapFrame> images;
using(var stream = File.OpenRead(imageFileName))
{
  var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
  images = decoder.Frames.ToList();
}
File.Delete(imageFileName);

In either case it is more efficient than creating a MemoryStream because a MemoryStream keeps two copies of the data in memory at once: The decoded copy and the undecoded copy.

Ray Burns
Thank you, but how can I access to multiple frames of image in BitmapImage object?
vasek7
You can use BitmapDecoder.Create(), then you can get all the frames. I added a paragraph to my answer to explain this.
Ray Burns
I currently do this, I just don't know how can I convert BitmapFrame to BitmapImage. After I copy all frames to List<BitmapFrame> I cannot delete image file. I need just delete image file right after all frames are loaded into memory.
vasek7
I think you must have made some mistake. `BitmapCacheOption.Onload` really does load all the data and close the source file when used with `BitmapDecoder.Create()`. Perhaps you passed it a `Stream` and forgot to close the stream after the call returned? Perhaps you forgot to add the `OnLoad` option in you test? Perhaps you used `new` instead of the `.Create()` method? I'll update my answer with some code the really does work.
Ray Burns
You are right, it works. My apologize.
vasek7
A: 

I figured it out. I have to use MemoryStream:

MemoryStream ms = new MemoryStream(File.ReadAllBytes(image));
TiffBitmapDecoder decoder = new TiffBitmapDecoder(ms, BitmapCreateOptions.None, BitmapCacheOption.None);
List<BitmapFrame> images = new List<BitmapFrame>();
foreach (BitmapFrame frame in decoder.Frames) images.Add(frame);
vasek7
This is inefficient because it keeps two copies of the file in memory at the same time: The MemoryStream and the data in the BitmapFrames. My answer achieves the same result more efficiently, and it *really* does work.
Ray Burns
A: 

I tried using BitmapDecoder. But if processing more number of files in separate threads getting an Object not initialized exception on bitmapdecoder object.

rsindh