How to set the source of a BitmapImage to a Stream? - wpf

I am trying to show an image in WPF. I use this:
Stream fs = File.Open(path, FileMode.Open);
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = fs;
bmp.EndInit();
img.Source = bmp;
fs.Close();
This does not work with or without closing the stream. What does work:
BitmapImage bmp = new BitmapImage(new Uri(path));
img.Source = bmp;
I would use the second method except for the fact that I need to close the stream. What is wrong with this?

To anyone looking for this in the future: I fixed this by adding the following line before setting StreamSource:
bmp.CacheOption = BitmapCacheOption.OnLoad;
Full Code:
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.StreamSource = fs;
bmp.EndInit();
img.Source = bmp;

Related

On changing the ImageSource of the Image using file picker, pop up raised that the file is in use

I am having an Image with default ImageSource, on picking up the new image using file picker it loads fine then on again the picking the previously used file, pop up raised that the file is still in use. When every time a new image is picked, it is working fine.
Is there any way to close or dispose the previously picked file or its ImageSource?
<Image x:Name="image" Source="Assets\RoadView.jpeg"></Image>
private void change_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Image Files ( *.png, *.bmp *.jpg, *.gif, *.tif)|*.png;*.bmp;*.jpg;*.gif;*.tif";
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
if (openFileDialog.ShowDialog() == true)
{
Stream stream = File.Open(openFileDialog.FileName, FileMode.Open);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
image.Source = bitmapImage;
}
}
You don't close the FileStream, hence the file is kept open and can't be opened a second time.
The easiest way to close the FileStream is to dispose of the object by means of a using block. In order to load the BitmapImage immediately before closing the stream, you also need to set BitmapCacheOption.OnLoad.
var bitmapImage = new BitmapImage();
using (var stream = File.Open(openFileDialog.FileName, FileMode.Open))
{
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
}
image.Source = bitmapImage;

How can I get Image class from MemoryStream of jpg Image?

Now I am trying to get a Image Class from jpg Image.
I already tried to use BitmapSource linked at here.
The error is not english, but the meaning is "the image header is broken. so, it is impossible to decode.".
The other formats like gif, png, bmp has no problem.
only jpg format faced on this problem.
< Sequence >
An Zip Archive file(jpg file is in this file.) -> unzip library -> MemoryStream(jpg file) -> BitmapSource
imageSource.BeginInit();
imageSource.StreamSource = memoryStream;
imageSource.EndInit();
this code makes the error.
I think the reason is the memory stream has raw binary of jpg, and it is not Bitmap format. So, BitmapSource cannot recognize this memory stream data as a bitmap image.
How can I solve this problem?
My goal is that Input : "ZIP File(in jpg)" -> Output : Image Class.
Thank you!
< My Code >
using (MemoryStream _reader = new MemoryStream())
{
reader.WriteEntryTo(_reader); // <- input jpg_data to _reader
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = _reader;
bitmap.EndInit();
bitmap.Freeze();
Image tmpImg = new Image();
tmpImg.Source = bitmap;
}
Rewind the stream after writing. While apparently only JpegBitmapDecoder is affected by a source stream's Position, you should generally do this for all kinds of bitmap streams.
var bitmap = new BitmapImage();
using (var stream = new MemoryStream())
{
reader.WriteEntryTo(stream);
stream.Position = 0; // here
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
bitmap.Freeze();
}
var tmpImg = new Image { Source = bitmap };
And just in case you don't actually care about whether your Image's Source is a BitmapImage or a BitmapFrame, you may reduce your code to this:
BitmapSource bitmap;
using (var stream = new MemoryStream())
{
reader.WriteEntryTo(stream);
stream.Position = 0;
bitmap = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
var tmpImg = new Image { Source = bitmap };

error in my byte[] to WPF BitmapImage conversion?

I'm saving a BitmapImage to a byte[] for saving in a DB. I'm pretty sure the data is being saved and retrieved accurately so it's not an issue there.
On my byte[] to BitmapImage conversion I keep getting an exception of "System.NotSupportedException: No imaging component suitable to complete this operation was found."
Can anyone see what I'm doing wrong with my two functions here?
private Byte[] convertBitmapImageToBytestream(BitmapImage bi)
{
int height = bi.PixelHeight;
int width = bi.PixelWidth;
int stride = width * ((bi.Format.BitsPerPixel + 7) / 8);
Byte[] bits = new Byte[height * stride];
bi.CopyPixels(bits, stride, 0);
return bits;
}
public BitmapImage convertByteToBitmapImage(Byte[] bytes)
{
MemoryStream stream = new MemoryStream(bytes);
stream.Position = 0;
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = stream;
bi.EndInit();
return bi;
}
Does this StackOverflow question helps?
byte[] to BitmapImage in silverlight
EDIT:
Try this, not sure it will work:
public BitmapImage convertByteToBitmapImage(Byte[] bytes)
{
MemoryStream stream = new MemoryStream(bytes);
stream.Position = 0;
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.DecodePixelWidth = ??; // Width of the image
bi.StreamSource = stream;
bi.EndInit();
return bi;
}
UPDATE 2:
I found these:
Load a byte[] into an Image at Runtime
BitmapImage from byte[] on a non UIThread
Apart from that, I don't know.
How do you know that the byte[] format you are creating is what the BI expects in the Stream? Why don't you use the BitmapImage.StreamSource to create the byte[] that you save? Then you know the format will be compatible.
http://www.codeproject.com/KB/vb/BmpImage2ByteArray.aspx
http://social.msdn.microsoft.com/forums/en-US/wpf/thread/8327dd31-2db1-4daa-a81c-aff60b63fee6/
[I did not try any of this code, but you can]
Turns out the bitmapimage CopyPixels isn't right. I take the output of the bitmapimage and convert it to something usable in this case a jpg.
public static Byte[] convertBitmapImageToBytestream(BitmapImage bi)
{
MemoryStream memStream = new MemoryStream();
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bi));
encoder.Save(memStream);
byte[] bytestream = memStream.GetBuffer();
return bytestream;
}

WPF: how to store image in a serializable object with JpegBitmapEncoder and use it again with JpegBitmapDecoder?

I have this code to decode a memory stream, but, its not woring, I get this error:
"No imaging component suitable to complete this operation was found."
MemoryStream stream = new MemoryStream(value, false);
stream.Seek(0, SeekOrigin.Begin);
JpegBitmapDecoder JpegBitmapDecoder = new JpegBitmapDecoder(
stream, BitmapCreateOptions.None,
BitmapCacheOption.None);
image.Source = JpegBitmapDecoder.Frames[0];
image.Height = hh;
image.Width = ww;
stream.Close();
UIVisual.Background = null;
UIVisual.Child = image;
UIVisual.UpdateLayout();
image = null;
And here is how I converted the image to bytes:
JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
jpgEncoder.Frames.Add(bitmapFrame);
Byte[] _imageArray;
MemoryStream memStream = new MemoryStream();
jpgEncoder.Save(memStream);
return memStream.ToArray();
so, I store memStream.ToArray() to use it later, I create MemoryStream from the stored memStream.ToArray() and use it with JpegBitmapDecoder like the code above.
Why I can't retrieve the stored bytes ?? is there some wrong I doing ??
Thanks
Hi you have two options return as Byte[] or MemoryStream, see the following code.
Hope it can help
Shalom Keynan
private static MemoryStream GetImageAsMemoryStream(BitmapSource bitmapSource)
{
JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
jpgEncoder.Frames.Add(BitmapFrame.Create(bitmapSource));
// Byte[] _imageArray;
MemoryStream memStream = new MemoryStream();
jpgEncoder.Save(memStream);
//_imageArray= memStream.ToArray();
memStream.Seek(0, SeekOrigin.Begin); // you MUST rewind before decoding
return memStream;
}
private static Byte[] GetImageAsByte(BitmapSource bitmapSource)
{
JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
jpgEncoder.Frames.Add(BitmapFrame.Create(bitmapSource));
Byte[] _imageArray;
MemoryStream memStream = new MemoryStream();
jpgEncoder.Save(memStream);
_imageArray = memStream.ToArray();
return _imageArray;
}
good luck!

Creating WPF BitmapImage from MemoryStream png, gif

I am having some trouble creating a BitmapImage from a MemoryStream from png and gif bytes obtained from a web request. The bytes seem to be downloaded fine and the BitmapImage object is created without issue however the image is not actually rendering on my UI. The problem only occurs when the downloaded image is of type png or gif (works fine for jpeg).
Here is code that demonstrates the problem:
var webResponse = webRequest.GetResponse();
var stream = webResponse.GetResponseStream();
if (stream.CanRead)
{
Byte[] buffer = new Byte[webResponse.ContentLength];
stream.Read(buffer, 0, buffer.Length);
var byteStream = new System.IO.MemoryStream(buffer);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.DecodePixelWidth = 30;
bi.StreamSource = byteStream;
bi.EndInit();
byteStream.Close();
stream.Close();
return bi;
}
To test that the web request was correctly obtaining the bytes I tried the following which saves the bytes to a file on disk and then loads the image using a UriSource rather than a StreamSource and it works for all image types:
var webResponse = webRequest.GetResponse();
var stream = webResponse.GetResponseStream();
if (stream.CanRead)
{
Byte[] buffer = new Byte[webResponse.ContentLength];
stream.Read(buffer, 0, buffer.Length);
string fName = "c:\\" + ((Uri)value).Segments.Last();
System.IO.File.WriteAllBytes(fName, buffer);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.DecodePixelWidth = 30;
bi.UriSource = new Uri(fName);
bi.EndInit();
stream.Close();
return bi;
}
Anyone got any light to shine?
Add bi.CacheOption = BitmapCacheOption.OnLoad directly after your .BeginInit():
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
...
Without this, BitmapImage uses lazy initialization by default and stream will be closed by then. In first example you try to read image from possibly garbage-collected closed or even disposed MemoryStream. Second example uses file, which is still available.
Also, don't write
var byteStream = new System.IO.MemoryStream(buffer);
better
using (MemoryStream byteStream = new MemoryStream(buffer))
{
...
}
I'm using this code:
public static BitmapImage GetBitmapImage(byte[] imageBytes)
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = new MemoryStream(imageBytes);
bitmapImage.EndInit();
return bitmapImage;
}
May be you should delete this line:
bi.DecodePixelWidth = 30;

Resources