Destroying stream cause destroying the bitmap - c#

I have something like:
public Bitmap GetBitmap()
{
Byte[] byteArray= bring it from somewhere
using (Stream stream = new MemoryStream(byteArray))
{
return new Bitmap(stream);
}
}
When I use this method outside the Bitmap is crushed. but if I stepped into the "using" scope the bitmap will be exists and works fine. it seems that disposing the stream cause disposing the bitmap..
the question is:
Do I need some deep copy? how should I perform it?

When you dispose the Bitmap will be lost, so indeed you need so perform a deep copy.
Eventually your code should be:
public static Bitmap GetBitmap()
{
byte[] byteArray = bring it from somewhere
using (Stream stream = new MemoryStream(byteArray))
{
var tempBitmap = new Bitmap(stream);
return new Bitmap(tempBitmap); // This will deep-copy the Bitmap
}
}
By the way, usually primitive types, like byte are written in small case.

Related

Returning Image using Image.FromStream

I know there are similar posts but I haven't got any answer for my problem and hence posting this.
I have a method that retrieves and returns image from a image path. Below is the code snippet I used. This fails in some cases as the image is lost after returning.
public static Image GetImageFromPicPath(string strUrl)
{
WebResponse wrFileResponse;
wrFileResponse = WebRequest.Create(strUrl).GetResponse();
using (Stream objWebStream = wrFileResponse.GetResponseStream())
{
return Image.FromStream(objWebStream);
}
}
If I use Bitmap class and return the image, metadata is lost.
If I use MemoryStream (as shown below) and I don't dispose MemoryStream it works . But there is possible memory leak here. If I use using block, the image is lost.
MemoryStream ms = new MemoryStream();
objWebStream.CopyTo(ms, 8192);
return System.Drawing.Image.FromStream(ms);
Can someone suggest me best approach to solve this issue.
Thanks in advance!!
This is why it's not working for you (from https://msdn.microsoft.com/en-us/library/93z9ee4x(v=vs.110).aspx) :
Here's a post that covers the issue a bit more: Loading an image from a stream without keeping the stream open
Try this:
public static Image GetImageFromPicPath(string strUrl)
{
using (WebResponse wrFileResponse = WebRequest.Create(strUrl).GetResponse())
using (Stream objWebStream = wrFileResponse.GetResponseStream())
{
MemoryStream ms = new MemoryStream();
objWebStream.CopyTo(ms, 8192);
return System.Drawing.Image.FromStream(ms);
}
}
In your consuming code do something like this:
using (var image = GetImageFromPicPath("http://imgur.com/123456.png"))
{
//use image
}
By wrapping "var image" in a using statement, Dispose() will be called on image which will also Dispose() and release the underlying MemoryStream in use by the Image.
Use the MemoryStream and don't explicitly close it. The Bitmap will close it in its Dispose method. There's no memory leak, as long as you remember to Dispose() the Bitmap when you're done with it. (And even if you didn't, the MemoryStream would eventually get garbage collected provided you let go of the Bitmap at some point and the Bitmap's the only thing holding a reference to it.)
https://support.microsoft.com/en-us/kb/814675

Returning image created by Image.FromStream(Stream stream) Method

I have this function which returns an Image within the function the image is created using the Image.FromStream method
According to MSDN:
You must keep the stream open for the lifetime of the Image
So I'm not closing the stream(if I do close the steam a GDI+ exception is thrown from the returned image object). My question is whether the stream will be closed/disposed when Image.Dispose() is called somewhere else on the returned Image
public static Image GetImage(byte[] buffer, int offset, int count)
{
var memoryStream = new MemoryStream(buffer, offset, count);
return Image.FromStream(memoryStream);
}
As suggested in one of the answers, using is not the way to go, since it throws an exception:
public static Image GetImage(byte[] buffer, int offset, int count)
{
using(var memoryStream = new MemoryStream(buffer, offset, count))
{
return Image.FromStream(memoryStream);
}
}
public static void Main()
{
var image = GetImage(args);
image.Save(path); <-- Throws exception
}
According to some people explicitly disposing/closing a MemoryStream is not necessary as it doesn't use any unmanaged resources others say the opposite thing so its kind of a dilemma.
Image.Dispose method doesn't dispose the stream ftom which the Image was created
The Image class doesn't hold any reference to the Stream passed to Image.FromStream method so the stream will eventually be collected by the GC...? Hence the exception in Image.Save method
Return a wrapper class which contains a reference to the stream and the Image created by it hence enabling us to dispose both of them...? or simply use the Tag property to keep a reference to the parent stream...?
This problem only seems to happen when using the MemoryStream. If the image is created from ConnectStream nothing bad happens even if the parent stream is disposed.
Despite what others advice to do, you should not close or dispose the stream until the image is disposed.
MSDN states:
You must keep the stream open for the lifetime of the Image.
For some streams, like MemoryStream, disposing doesn't have much use since it doesn't allocate unmanaged resources. File streams on the other hand do, so unless you are very sure the stream is safe, you should always dispose the stream when you are done with the image.
Since you are only constructing an Image and then saving it consider this implementation instead:
public static void GetAndSaveImage(byte[] buffer, int offset, int count,string path)
{
using(var memoryStream = new MemoryStream(buffer, offset, count))
using(var img = Image.FromStream(memoryStream))
{
img.Save(path);
}
}
Disposing the image will not affect the memorystream as the following example demonstrates :
static void Main(string[] args) {
byte[] contents = File.ReadAllBytes(DESKTOP_PATH + "asample.tif");
MemoryStream ms = new MemoryStream(contents);
Image img = Image.FromStream(ms);
img.Dispose();
Image img2 = Image.FromStream(ms);
Console.WriteLine(img2.PixelFormat);
Console.ReadKey();
}
This will output "Format32bppPargb". I suggest wrapping it into a using statement like so :
using (MemoryStream ms = new MemoryStream(contents){
// code here
}

Displaying live images

I have a function that returns an array of bytes containing the data of a bmp img live from a camera (including header).
I write that array in to a MemoryStream object.
That object, I pass to a Image object constructor, which will be passed to a PictureBox.
tl;dr:
byte[] AoB = GetImage();
MemoryStream ms = new MemoryStream();
ms.Write(AoB, 0, AoB.Length);
pictureBoxImage.Image = Image.FromStream(ms);
ms.Dispose();
All of this is done in a timer with a delay of 200 ms (5fps).
It works fine for about a minute or 2 until OutOfMemory exception.
For some reason, even though I dispose of the memory used, it keeps generating new one.
I've also tried to declare ms as global and flush it every time, still no go.
How can I stream the images while using the same memory space?
Try disposing the Image objects when you're done with them as well:
byte[] AoB = GetImage();
using (MemoryStream ms = new MemoryStream()) {
ms.Write(AoB, 0, AoB.Length);
Image old = pictureBoxImage.Image;
pictureBoxImage.Image = Image.FromStream(ms);
if (old != null) {
old.Dispose();
}
}
You definitely should dispose the old images when you are done with them (as adv12 mentioned), however you are also creating two byte[]s in memory. The first one is the one you get from GetImage() the second one is the one stored inside the MemoryStream and that one could be larger than your source array due to its growing algorithms.
Instead use this overload of the MemoryStream constructor to allow you to pass the byte[] directly in and the MemoryStream will reuse that single array for its internal store, reducing the memory requirement.
byte[] AoB = GetImage();
using (MemoryStream ms = new MemoryStream(AoB)) {
Image old = pictureBoxImage.Image;
pictureBoxImage.Image = Image.FromStream(ms);
old.Dispose();
}
Try setting your timer's AutoReset=false and manually starting it over at the end of the last call.
myTimer.AutoReset = false;
Start after image assignment.
byte[] AoB = GetImage();
MemoryStream ms = new MemoryStream();
ms.Write(AoB, 0, AoB.Length);
pictureBoxImage.Image = Image.FromStream(ms);
ms.Dispose();
myTimer.Start().
The timer has the potential to get ahead of the retrieval of the images.

Create Bitmap from Collection of BitmapSources

I would like to create the Bitmap from BitmapSource Collection and Each source source should be one frame.
I wrote the following code
MemoryStream memStream = new MemoryStream();
BitmapEncoder enCoder = new GifBitmapEncoder();
foreach (BitmapSource source in BitmapSources)
enCoder.Frames.Add(BitmapFrame.Create(source));
enCoder.Save(memStream);
_Bitmap = new DrawingCtrl.Bitmap(memStream);
DrawingCtrl.ImageAnimator.Animate(_Bitmap, OnFrameChanged);
and
private void OnFrameChangedInMainThread()
{
DrawingCtrl.ImageAnimator.UpdateFrames(_Bitmap);
Source = GetBitmapSource(_Bitmap);
InvalidateVisual();
}
But it shows "Exception has been thrown by the target of an invocation.". Could anyone help me?
I don’t know about BitmapSources in WPF, but I notice an error in how you use MemoryStream, so maybe this is the issue:
enCoder.Save(memStream);
This will write the content to the memory stream and leave the stream pointer at the end.
_Bitmap = new DrawingCtrl.Bitmap(memStream);
This will then try to read the bitmap from the stream, starting at the end of the stream. Of course that can’t work. Try adding a seek in between:
enCoder.Save(memStream);
memStream.Seek(0, SeekOrigin.Begin);
_Bitmap = new DrawingCtrl.Bitmap(memStream);

Image.Save(..) throws a GDI+ exception because the memory stream is closed

i've got some binary data which i want to save as an image. When i try to save the image, it throws an exception if the memory stream used to create the image, was closed before the save. The reason i do this is because i'm dynamically creating images and as such .. i need to use a memory stream.
this is the code:
[TestMethod]
public void TestMethod1()
{
// Grab the binary data.
byte[] data = File.ReadAllBytes("Chick.jpg");
// Read in the data but do not close, before using the stream.
Stream originalBinaryDataStream = new MemoryStream(data);
Bitmap image = new Bitmap(originalBinaryDataStream);
image.Save(#"c:\test.jpg");
originalBinaryDataStream.Dispose();
// Now lets use a nice dispose, etc...
Bitmap2 image2;
using (Stream originalBinaryDataStream2 = new MemoryStream(data))
{
image2 = new Bitmap(originalBinaryDataStream2);
}
image2.Save(#"C:\temp\pewpew.jpg"); // This throws the GDI+ exception.
}
Does anyone have any suggestions to how i could save an image with the stream closed? I cannot rely on the developers to remember to close the stream after the image is saved. In fact, the developer would have NO IDEA that the image was generated using a memory stream (because it happens in some other code, elsewhere).
I'm really confused :(
As it's a MemoryStream, you really don't need to close the stream - nothing bad will happen if you don't, although obviously it's good practice to dispose anything that's disposable anyway. (See this question for more on this.)
However, you should be disposing the Bitmap - and that will close the stream for you. Basically once you give the Bitmap constructor a stream, it "owns" the stream and you shouldn't close it. As the docs for that constructor say:
You must keep the stream open for the
lifetime of the Bitmap.
I can't find any docs promising to close the stream when you dispose the bitmap, but you should be able to verify that fairly easily.
A generic error occurred in GDI+.
May also result from incorrect save path!
Took me half a day to notice that.
So make sure that you have double checked the path to save the image as well.
Perhaps it is worth mentioning that if the C:\Temp directory does not exist, it will also throw this exception even if your stream is still existent.
Copy the Bitmap. You have to keep the stream open for the lifetime of the bitmap.
When drawing an image: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI
public static Image ToImage(this byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
using (var image = Image.FromStream(stream, false, true))
{
return new Bitmap(image);
}
}
[Test]
public void ShouldCreateImageThatCanBeSavedWithoutOpenStream()
{
var imageBytes = File.ReadAllBytes("bitmap.bmp");
var image = imageBytes.ToImage();
image.Save("output.bmp");
}
I had the same problem but actually the cause was that the application didn't have permission to save files on C. When I changed to "D:\.." the picture has been saved.
You can try to create another copy of bitmap:
using (var memoryStream = new MemoryStream())
{
// write to memory stream here
memoryStream.Position = 0;
using (var bitmap = new Bitmap(memoryStream))
{
var bitmap2 = new Bitmap(bitmap);
return bitmap2;
}
}
This error occurred to me when I was trying from Citrix. The image folder was set to C:\ in the server, for which I do not have privilege. Once the image folder was moved to a shared drive, the error was gone.
A generic error occurred in GDI+. It can occur because of image storing paths issues,I got this error because my storing path is too long, I fixed this by first storing the image in a shortest path and move it to the correct location with long path handling techniques.
I was getting this error, because the automated test I was executing, was trying to store snapshots into a folder that didn't exist. After I created the folder, the error resolved
One strange solution which made my code to work.
Open the image in paint and save it as a new file with same format(.jpg). Now try with this new file and it works. It clearly explains you that the file might be corrupted in someway.
This can help only if your code has every other bugs fixed
It has also appeared with me when I was trying to save an image into path
C:\Program Files (x86)\some_directory
and the .exe wasn't executed to run as administrator, I hope this may help someone who has same issue too.
For me the code below crashed with A generic error occurred in GDI+on the line which Saves to a MemoryStream. The code was running on a web server and I resolved it by stopping and starting the Application Pool that was running the site.
Must have been some internal error in GDI+
private static string GetThumbnailImageAsBase64String(string path)
{
if (path == null || !File.Exists(path))
{
var log = ContainerResolver.Container.GetInstance<ILog>();
log.Info($"No file was found at path: {path}");
return null;
}
var width = LibraryItemFileSettings.Instance.ThumbnailImageWidth;
using (var image = Image.FromFile(path))
{
using (var thumbnail = image.GetThumbnailImage(width, width * image.Height / image.Width, null, IntPtr.Zero))
{
using (var memoryStream = new MemoryStream())
{
thumbnail.Save(memoryStream, ImageFormat.Png); // <= crash here
var bytes = new byte[memoryStream.Length];
memoryStream.Position = 0;
memoryStream.Read(bytes, 0, bytes.Length);
return Convert.ToBase64String(bytes, 0, bytes.Length);
}
}
}
}
I came across this error when I was trying a simple image editing in a WPF app.
Setting an Image element's Source to the bitmap prevents file saving.
Even setting Source=null doesn't seem to release the file.
Now I just never use the image as the Source of Image element, so I can overwrite after editing!
EDIT
After hearing about the CacheOption property(Thanks to #Nyerguds) I found the solution:
So instead of using the Bitmap constructor I must set the Uri after setting CacheOption BitmapCacheOption.OnLoad.(Image1 below is the Wpf Image element)
Instead of
Image1.Source = new BitmapImage(new Uri(filepath));
Use:
var image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(filepath);
image.EndInit();
Image1.Source = image;
See this: WPF Image Caching
Try this code:
static void Main(string[] args)
{
byte[] data = null;
string fullPath = #"c:\testimage.jpg";
using (MemoryStream ms = new MemoryStream())
using (Bitmap tmp = (Bitmap)Bitmap.FromFile(fullPath))
using (Bitmap bm = new Bitmap(tmp))
{
bm.SetResolution(96, 96);
using (EncoderParameters eps = new EncoderParameters(1))
{
eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bm.Save(ms, GetEncoderInfo("image/jpeg"), eps);
}
data = ms.ToArray();
}
File.WriteAllBytes(fullPath, data);
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (String.Equals(encoders[j].MimeType, mimeType, StringComparison.InvariantCultureIgnoreCase))
return encoders[j];
}
return null;
}
I used imageprocessor to resize images and one day I got "A generic error occurred in GDI+" exception.
After looked up a while I tried to recycle the application pool and bingo it works. So I note it here, hope it help ;)
Cheers
I was getting this error today on a server when the same code worked fine locally and on our DEV server but not on PRODUCTION. Rebooting the server resolved it.
public static byte[] SetImageToByte(Image img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
public static Bitmap SetByteToImage(byte[] blob)
{
MemoryStream mStream = new MemoryStream();
byte[] pData = blob;
mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
Bitmap bm = new Bitmap(mStream, false);
mStream.Dispose();
return bm;
}

Categories

Resources