When I try to save a BitmapSource that I loaded earlier, a System.IO.IOException is thrown stating another process is accessing that file and the filestream cannot be opened.
If I only save whithout loading earlier, everything works fine.
The loading code:
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = uri;
if (decodePixelWidth > 0)
image.DecodePixelWidth = decodePixelWidth;
image.EndInit();
the saving code:
using (FileStream fileStream = new FileStream(Directory + "\\" + FileName + ".jpg", FileMode.Create))
{
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create((BitmapImage)image));
encoder.QualityLevel = 100;
encoder.Save(fileStream);
}
It seems like after loading the image data, the file is still locked an can never be overwritten while the application who opened it is still running. Any ideas how to solve this? Thanks alot for any solutions.
Inspired by the comments I got on this issue, I solved the problem by reading all bytes into a memorystream and using it as the BitmapImage's Sreamsource.
This one works perfectly:
if (File.Exists(filePath))
{
MemoryStream memoryStream = new MemoryStream();
byte[] fileBytes = File.ReadAllBytes(filePath);
memoryStream.Write(fileBytes, 0, fileBytes.Length);
memoryStream.Position = 0;
image.BeginInit();
image.StreamSource = memoryStream;
if (decodePixelWidth > 0)
image.DecodePixelWidth = decodePixelWidth;
image.EndInit();
}
Here is another solution, based upon the original loading code:
var image = new BitmapImage();
image.BeginInit();
// overwrite cache if already exists, to refresh image
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
// load into memory and unlock file
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = uri;
if (decodePixelWidth > 0) image.DecodePixelWidth = decodePixelWidth;
image.EndInit();
Add the following line to your loading code:
image.CacheOption = BitmapCacheOption.OnLoad;
This will load open the file, read it into memory, and close it all during image.EndInit. The default of BitmapCacheOption.Default has the odd behavior of opening the file, reading it into memory, but not yet closing it during image.EndInit.
Now i'm not sure if this can be applied to BitmapImage but i had a very similar problem with saving a modified image to the original file in GDI+ here
The method of loading the image from file keeps a lock open on the file until the image object is disposed.
Maybe it's the same thing with bitmapimage.urisource. Without playing around could you copy the image in memory and dispose the original thus unlocking the file?
Setting CacheOption to BitmapCacheOption.OnLoad, will not solve your problem. I think there is a bug, but I had the same problem. Finally i loaded my image to a memory stream and disposed the BitmapImage before saving the image to the file.
Related
I have a WPF application that takes a snapshot image from a video file. The user can define the timestamp from which to take the image. The image is then saved to a temporary location on disk, and is then rendered into an <image> element.
The user should then be able to select a different timestamp, which then overwrites the temporary file on disk - this should then be displayed within the <image> element.
Using Image.Source = null;, I can clear the image file from the <image> element, so it displays a blank space instead. However, if the source image file is then overwritten with a new image (with the same name) and loaded into the <image> element, it still shows the old image.
I am using the following logic:
// Overwrite temporary file file here
// Clear out the reference to the temporary image
Image_Preview.Source = null;
// Load in new image (same source file name)
Image = new BitmapImage();
Image.BeginInit();
Image.CacheOption = BitmapCacheOption.OnLoad;
Image.UriSource = new Uri(file);
Image.EndInit();
Image_Preview.Source = Image;
The image displayed in the <image> element does not change, even though the original file has been completely replaced. Is there an image caching issue here that I am not aware of?
By default, WPF caches BitmapImages that are loaded from URIs.
You can avoid that by setting the BitmapCreateOptions.IgnoreImageCache flag:
var image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(file);
image.EndInit();
Image_Preview.Source = image;
Or you load the BitmapImage directly from a Stream:
var image = new BitmapImage();
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
Image_Preview.Source = image;
I have a WPF application that takes a snapshot image from a video file. The user can define the timestamp from which to take the image. The image is then saved to a temporary location on disk, and is then rendered into an <image> element.
The user should then be able to select a different timestamp, which then overwrites the temporary file on disk - this should then be displayed within the <image> element.
Using Image.Source = null;, I can clear the image file from the <image> element, so it displays a blank space instead. However, if the source image file is then overwritten with a new image (with the same name) and loaded into the <image> element, it still shows the old image.
I am using the following logic:
// Overwrite temporary file file here
// Clear out the reference to the temporary image
Image_Preview.Source = null;
// Load in new image (same source file name)
Image = new BitmapImage();
Image.BeginInit();
Image.CacheOption = BitmapCacheOption.OnLoad;
Image.UriSource = new Uri(file);
Image.EndInit();
Image_Preview.Source = Image;
The image displayed in the <image> element does not change, even though the original file has been completely replaced. Is there an image caching issue here that I am not aware of?
By default, WPF caches BitmapImages that are loaded from URIs.
You can avoid that by setting the BitmapCreateOptions.IgnoreImageCache flag:
var image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(file);
image.EndInit();
Image_Preview.Source = image;
Or you load the BitmapImage directly from a Stream:
var image = new BitmapImage();
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
Image_Preview.Source = image;
I have a WPF application that takes a snapshot image from a video file. The user can define the timestamp from which to take the image. The image is then saved to a temporary location on disk, and is then rendered into an <image> element.
The user should then be able to select a different timestamp, which then overwrites the temporary file on disk - this should then be displayed within the <image> element.
Using Image.Source = null;, I can clear the image file from the <image> element, so it displays a blank space instead. However, if the source image file is then overwritten with a new image (with the same name) and loaded into the <image> element, it still shows the old image.
I am using the following logic:
// Overwrite temporary file file here
// Clear out the reference to the temporary image
Image_Preview.Source = null;
// Load in new image (same source file name)
Image = new BitmapImage();
Image.BeginInit();
Image.CacheOption = BitmapCacheOption.OnLoad;
Image.UriSource = new Uri(file);
Image.EndInit();
Image_Preview.Source = Image;
The image displayed in the <image> element does not change, even though the original file has been completely replaced. Is there an image caching issue here that I am not aware of?
By default, WPF caches BitmapImages that are loaded from URIs.
You can avoid that by setting the BitmapCreateOptions.IgnoreImageCache flag:
var image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(file);
image.EndInit();
Image_Preview.Source = image;
Or you load the BitmapImage directly from a Stream:
var image = new BitmapImage();
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read))
{
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
}
Image_Preview.Source = image;
I have the following function to get BitmapImage of file.
public static BitmapImage GetThumbnail(string filePath)
{
ShellFile shellFile = ShellFile.FromFilePath(filePath);
BitmapSource shellThumb = shellFile.Thumbnail.ExtraLargeBitmapSource;
BitmapImage bImg = new BitmapImage();
PngBitmapEncoder encoder = new PngBitmapEncoder();
MemoryStream memoryStream = new MemoryStream();
encoder.Frames.Add(BitmapFrame.Create(shellThumb));
encoder.Save(memoryStream);
bImg.BeginInit();
bImg.StreamSource = memoryStream;
bImg.EndInit();
return bImg;
}
When I get Video's Thumbnail it always works.
When I get Presentation (pptx) Thumbnail it doesn't work properly (I have no idea when it does and when it doesn't).
For example, I have 2 files in directory:
And this is how it looks in my program - 1 is ok and 1 isn't (sometimes both are ok, and sometimes both aren't):
I would appreciate if you could tell me what's the problem or maybe give me another way of getting the Thumbnail that will not fail...
p.s.
I would like to remind that with video files it works 100% fine (.mp3, .mp4, .wmv - thats what I tested)
Since I wanted to get pptx thumbnail, I came up with the following solution:
1. I extracted the thumbnail using DotNetZip
2. I got the thumbnail which is located in docProps directory
3. I extracted the thumbnail to memoryStream
4. I converted the memoryStream to BitmapImage and returned it.
here's the code:
public static BitmapImage GetPPTXThumbnail(string filePath)
{
using (ZipFile zip = ZipFile.Read(filePath))
{
ZipEntry e = zip["docProps/thumbnail.jpeg"];
BitmapImage bImg = new BitmapImage();
MemoryStream memoryStream = new MemoryStream();
bImg.BeginInit();
e.Extract(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
bImg.StreamSource = memoryStream;
bImg.EndInit();
return bImg;
}
}
Cant fail with this solution, this solution is only to get PPTX Thumbnail, I assume it works with all office xml files such as docx, xlsx, etc...
I'm using the following code to load an image from file into a bitmap image class to display to the user at a particular size:
BitmapImage resized = new BitmapImage();
FileStream fs = new FileStream(ImageSource, FileMode.Open);
MemoryStream ms = new MemoryStream();
fs.CopyTo(ms);
fs.Close();
resized.BeginInit();
resized.CacheOption = BitmapCacheOption.OnDemand;
resized.DecodePixelHeight = (int)(_imageBaseHeight * zoomRate);
resized.DecodePixelWidth = (int)(_imageBaseWidth * zoomRate);
resized.StreamSource = ms;
resized.EndInit();
ImageDisplay = resized;
The problem is that sometimes, on particularly large images, this will fail silently and display a blank image without raising an exception. Is there a flag that I can check after EndInit() to be sure the image has loaded?
Use the resized.DownloadFailed event to get informed.
You can also use the ImageFailed event.