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?
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.
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);
Related
I try to retrieve the content of a .gif located on an URL into a string -and eventually save it to disk-, ran from a WPF appliactions using the webbrowser. After trying dozens of solutions I am not further than I was yesterday. I thought that the code below would do the job, but the saved string cGif contains...the url itself. From http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.gifbitmapdecoder.aspx I then thought I needed GifBitmapEncoder instead, but the sample suggests that this creates an empty gif instead of a downloaded one.
(PS: what I basically want to do is to retrieve the GIF bytes straight from the WPF webbrowser but I haven't found anything working there either)
private void GifSave()
{
var uri = new Uri(#"http://www.archivearts.com/GIRAFFE2.gif");
var Img = new GifBitmapDecoder(uri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
string cGif = Img.ToString();
}
Modified from a sample on the GifBitmapDecoder MSDN page:
// Open a Stream and decode a GIF image
var uri = new Uri(#"http://www.archivearts.com/GIRAFFE2.gif");
GifBitmapDecoder decoder = new GifBitmapDecoder(uri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
BitmapSource bitmapSource = decoder.Frames[0];
Then use the CopyPixels() method of the BitmapSource to copy the pixel data into an array. Then convert the array into a string?
I haven't done this, I just took a look at MSDN to get some hints.
May be this sound stupid but, which one is the most efficient way to load image?
A
BitmapImage bmp = new BitmapImage();
using(FileStream fileStream = new FileStream(source_path, FileMode.Open))
{
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.StreamSource = fileStream;
bmp.EndInit();
if (bmp.CanFreeze)
bmp.Freeze();
images.source = bmp;
}
B
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
bmp.UriSource = new Uri(source_path);
bmp.EndInit();
if (bmp.CanFreeze)
bmp.Freeze();
images.Source = bmp;
I remember I read somewhere that loading from a stream completely disables the cache. If thats true, does it means loading from a stream is better in term on memory management?
As far as i have understood, when you load a BitmapImage by setting its UriSource property, the image is always cached. I don't know of any way to avoid this. At least setting BitmapCreateOptions.IgnoreImageCache only ensures that an image is not retrieved from the cache, but it does not prevent that the image is stored in the cache.
The "Remarks" in BitmapCreateOptions says that
When IgnoreImageCache is selected, any existing entries in the image
cache are replaced even if they share the same Uri
My conclusion from this is that caching is only performed when an image is loaded by an Uri. In other words, if you really need to inhibit image caching, you will have to load an image by its StreamSource property.
However, if this is really "better in terms of memory management" is perhaps worth an experiment. You could try out both alternatives and see if you observe any significant difference in memory consumption.
I have created a silverlight project that captures the image through the webcam and stores it in my local hard, but I don't want to save it on the local hard I want to store it in my project folder then store the path in SQL database.
Please Help!
You could try and save the image directly as a bitstream to the DB maybe?
private static ImageElementContract ImageToImageElementContract(Image image)
{
WriteableBitmap bmp = new WriteableBitmap(image, null);
ImageTools.ExtendedImage myImage = new ImageTools.ExtendedImage();
myImage = ImageExtensions.ToImage(bmp);
MemoryStream mStream = new MemoryStream();
JpegEncoder encoder = new JpegEncoder();
encoder.Quality = 100;
encoder.Encode(myImage, mStream);
imageContract.ImageStream = mStream.ToArray();
return imageContract;
}
Should give you a stream, which you can pass to the DB and put back together if you need it again. It's hard to tell what your using it for. There's not much detail in your question
I have a very large image (600mb) 30000x30000 and want to load it into a wpf image control.
I can watch this image with the Windows Photo Viewer!
I set my testapp to 64bit and used the following code.
var image = new BitmapImage();
image.BeginInit();
// load into memory and unlock file
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = uri;
image.EndInit();
imagecontrol.source = image;
The test app just shows a white screen with this large image.
Smaller ones like 100mb and 7000x7000 are working.
What am I doing wrong? Sry for my bad english and thanks in advance.
64-Bit Applications.
As with 32-bit Windows operating systems, there is a 2GB limit on the size of an object you can create while running a 64-bit managed application on a 64-bit Windows operating system.
Picture can be fetched directly from the hard drive to reduce a memory usage.
You can use BitmapCacheOption
Code bellow will read the image directly from the HDD and small thumbnail will be generated without the original image cache:
public BitmapImage memoryOptimizedBitmapRead(string url,FrameworkElement imageContainer)
{
if (string.IsNullOrEmpty(url) || imageContainer.ActualHeight<= 0)
{
return null;
}
var bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.None;
bi.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
bi.DecodePixelHeight = (int)imageContainer.ActualHeight;
bi.UriSource = new Uri(url, UriKind.Absolute);
// End initialization.
bi.EndInit();
bi.Freeze();
return bi;
}
Max thumbnail size is determined by the image container size.
Method usage example:
var image= new Image();
image.Source = memoryOptimizedBitmapRead(...);
I'd divide it into 10 (3000x3000) segments and put them into 10 files.
Also check what format you're using it. It may be filling up the threshold for file size or for that particular format. Try TIF format, then try JPG, then try BMP, etc.. Also see if you can compress it with the JPG format to 40-50% and see if that changes anything.
Let me know what you find out.
I have an image that was originally a PNG that I have converted to a byte[] and saved in a database. Originally, I simply read the PNG into a memory stream and converted the stream into a byte[]. Now I want to read the byte[] back and convert it to a BitmapImage, so that I can bind a WPF Image control to it.
I am seeing a lot of contradictory and confusing code online to accomplish the task of converting a byte[] to a BitmapImage. I am not sure whether I need to add any code due to the fact that the image was originally a PNG.
How does one convert a stream to a BitmapImage?
This should do it:
using (var stream = new MemoryStream(data))
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = stream;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
}
The BitmapCacheOption.OnLoad is important in this case because otherwise the BitmapImage might try to access the stream when loading on demand and the stream might already be closed.
Freezing the bitmap is optional but if you do freeze it you can share the bitmap across threads which is otherwise impossible.
You don't have to do anything special regarding the image format - the BitmapImage will deal with it.
using (var stream = new MemoryStream(data))
{
var bi = BitmapFrame.Create(stream , BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnLoad);
}