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;
}
I Tried many solutions to remove Generic error Occured in GDI + but nothing is working for me , I am posting Codes that i had used.This error occured in server machine
Images bytes are stored successfully in Database but doesnt retrieve on PictureBox.
1st Method :
ODetail.InsuranceCardImages Contains Bytes of Images From Database.
pcinsurance is my PictureBox
System.Byte[] imagefront = (byte[])oDetail.InsuranceCardImage;
//this.pcInsurance.Image = Utility.byteArrayToImage(oDetail.InsuranceCardImage);
MemoryStream ms = new MemoryStream(imagefront);
try
{
//Process currentProcess1 = Process.GetCurrentProcess();
Image returnImage = Image.FromStream(ms);
pcInsurance.Image= returnImage;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
try
{
ms.Flush();
ms.SetLength(0);
ms.Close();
ms.Dispose();
ms = null;
//GC.Collect();
}
catch
{
}
}
2nd Method :
where pcinsurance is my PictureBox
byte[] byteArray = oDetail.InsuranceCardImage;
var imageStream = new MemoryStream(byteArray);
var image = (Bitmap)Bitmap.FromStream(imageStream);
pcInsurance.Image = image;
Still cant fix this issue ,
Kindly provide your solutions so that i will carry on my work
Thank You.
Why do you use ms.Close();,ms.Dispose(); and ms = null;?
You dispose this stream twice and afterwards set it to null.
Finally is performed always so MemoryStream is always disposed.
I suspect that all resources are released before they're used by GDI. I experienced similar problem some time ago.
According to MSDN:
http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx
You must keep the stream open for the lifetime of the Image.
The solution was a creation a Bitmap object:
Bitmap bmp = new Bitmap(ms);
this.pcInsurance.Image = bmp;
In fact I used using statement to simplify code, closing stream before final braces. Works exactly the same but is shorter and in my opinion more readable.
Bitmap and picturebox.Imageobjects must be disposed before setting another picture.
Hope this helps.
I am doing a project in which a built in class for DICOM giving me the ImageSource,I want to use that ImageSource in My silverlight Image control. This conversion I am doing through WCF services. I found WCF does not support ImageSource, so I need to convert the output of built in class into Image or else in byte[]. So that I can send that output to Silverlight and in Silverlight client I'll reconvert it to ImageSource and can assign it to Image Control easily.
I googled for this but I did not find any help in there. Can anybody help me to fix this problem or provide me any alternate solution for this. Any help will be appreciated, Thanks in advance.
Note:- I do not have any permission for code modification on the built in class. As its a third party library.
UPDATE:-
Brief Description:
I have a class let say GetImageSource and in that I have a method say giveImgSource(). Now my questions is:
In WCF I have to call this method and after getting ImageSource from this method I need to pass it to my silverlight Client. As WCF doesn't know about ImageSource, so I need to convert the output of this method to some one out of the following or any alternate if you knows:
byte[]
Image
FileStream
MemoryStream etc
Is it a png image? Then use this to convert to byte[]:
var image = (BitmapSource)value;
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
using (var ms = new MemoryStream())
{
encoder.Save(ms);
return ms.ToArray();
}
UPDATE:
Decoding:
var bytes = (byte[])value;
var image = new BitmapImage();
image.BeginInit();
if (bytes == null)
{
// Processing null case
}
else
{
using (var ms = new MemoryStream(bytes))
{
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = ms;
image.EndInit();
}
}
return image;
Please refer to the below links for converting ImageSource to byte[]. They use the BitmapSource and WriteableBitmap classes which are available under PresentationCore library.
(1) How to Convert ImageSource to byte[]?
(2) How to Convert ImageSource to byte[] and back to ImageSource?
Hope that it will solve your problem.
The following two helper methods should be able to do the trick:
public BitmapImage ImageFromBuffer(Byte[] bytes)
{
MemoryStream stream = new MemoryStream(bytes);
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = stream;
image.EndInit();
return image;
}
public Byte[] BufferFromImage(BitmapImage imageSource)
{
Stream stream = imageSource.StreamSource;
Byte[] buffer = null;
if (stream != null && stream.Length > 0)
{
using (BinaryReader br = new BinaryReader(stream))
{
buffer = br.ReadBytes((Int32)stream.Length);
}
}
return buffer;
}
Is there a way to convert a BitmapImage (Windows.UI.Xaml.Media.BitmapImage) to an Byte[] Array? Nothing I've tried work....
Another possible scenario (if BitmapImage cannot be converted to Byte array) is to download the image from web and then convert it to an array...
But I don't know how I can do that...
It would be really nice, if someone have an idea.
Current try:
HttpClient http = new HttpClient();
Stream resp = await http.GetStreamAsync("http://localhost/img/test.jpg");
var ras = new InMemoryRandomAccessStream();
await resp.CopyToAsync(ras.AsStreamForWrite());
BitmapImage bi = new BitmapImage();
bi.SetSource(ras);
byte[] pixeBuffer = null;
using (MemoryStream ms = new MemoryStream())
{
int i = bi.PixelHeight;
int i2 = bi.PixelWidth;
WriteableBitmap wb = new WriteableBitmap(bi.PixelWidth, bi.PixelHeight);
Stream s1 = wb.PixelBuffer.AsStream();
s1.CopyTo(ms);
pixeBuffer = ms.ToArray();
}
But it doesn't work... i & i2 are always set to 0. So ras doesn't work correctly.... What's going on?
Thanks
In your code you're never waiting for the BitmapImage to load the image from the web, so it does not know its PixelWidth/PixelHeight when you access them. You could wait for it to load - for example using the AsyncUI library by calling "await bi.WaitForLoadedAsync()". This would not really help you here if you want to access the decoded pixels since BitmapImage does not give you access to the pixels and there is currently no API to convert a BitmapImage into a WriteableBitmap.
You can check an earlier question about the topic. You would need to get the image file from the web with something like HttpClient.GetAsync(), then load it using something like BitmapDecoder.
My goal is to upload and download images using a web service. I understand that in order to do that the images need to be converted to a byte array. However, I’m getting “Unspecified error” when converting a byte array into a BitmapImage.
I’ve create a test rig that converts an image (from a PhotoChooserTask) into a byte array and back again that recreates my problem. The code that does the conversion is listed below with the problem line highlighted.
Any help would be appreciated!
private void PhotoChooserTaskCompleted(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
//Display the photo
BitmapImage PhotoBitmap = new BitmapImage();
PhotoBitmap.SetSource(e.ChosenPhoto);
Photo.Source = PhotoBitmap;
//Convert the photo to bytes
Byte[] PhotoBytes = new byte[e.ChosenPhoto.Length];
e.ChosenPhoto.Read(PhotoBytes, 0, PhotoBytes.Length);
//Convert the bytes back to a bitmap
BitmapImage RestoredBitmap = new BitmapImage();
MemoryStream stream = new MemoryStream(PhotoBytes);
BitmapImage image = new BitmapImage();
RestoredBitmap.SetSource(stream); //<------ I get "Unspecified error" on this line
//Display the restored photo
RestoredPhoto.Source = RestoredBitmap;
}
}
The first time you use e.ChosePhoto as source, the stream is read and the Position property is advanced to the end. You can inspect the PhotoBytes array in the debugger to see that after your read operation it actually does not have any content (or check the return value of the Read method to confirm zero bytes are read).
What you need to do is reset that Position to zero before you read from it again:
//Convert the photo to bytes
Byte[] PhotoBytes = new byte[e.ChosenPhoto.Length];
// rewind first
e.ChosenPhoto.Position = 0;
// now succeeds
e.ChosenPhoto.Read(PhotoBytes, 0, PhotoBytes.Length);
I would bet that this is what's happening (comments inline):
//Display the photo
BitmapImage PhotoBitmap = new BitmapImage();
PhotoBitmap.SetSource(e.ChosenPhoto); // This is reading from the stream
Photo.Source = PhotoBitmap;
//Convert the photo to bytes
Byte[] PhotoBytes = new byte[e.ChosenPhoto.Length];
e.ChosenPhoto.Read(PhotoBytes, 0, PhotoBytes.Length); // Fails to read the full stream
// because you already read from it
//Convert the bytes back to a bitmap
BitmapImage RestoredBitmap = new BitmapImage();
MemoryStream stream = new MemoryStream(PhotoBytes); // You're creating a stream that
// doesn't contain the image
BitmapImage image = new BitmapImage();
RestoredBitmap.SetSource(stream); // Fails because your stream is incomplete
Seek to 0 in the stream before you attempt to read from it. And check the return value from the Read call to make sure it matches PhotoBytes.Length.
This:
//Display the photo
BitmapImage PhotoBitmap = new BitmapImage();
PhotoBitmap.SetSource(e.ChosenPhoto);
Photo.Source = PhotoBitmap;
uses the Stream of the e.ChosenPhoto and might not rewind the Position of the Stream.
So when you do this:
Byte[] PhotoBytes = new byte[e.ChosenPhoto.Length];
e.ChosenPhoto.Read(PhotoBytes, 0, PhotoBytes.Length);
you are starting at the end of the stream reading nothing.
Use Seek to reset the Position of the stream.
Did you check out my other post where I already did this?
I had receive a pretty good rating from it.
BitmapImage to byte[] and byte[] to BitmapImage