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 need a generic function to convert images to a target format. (Format8bppIndexed in this case) The goal is to be able to handle a reasonable range of regular .NET supported images. We have many clients with hundreds of Terabytes of images of varying types and I plan to loop through them all with this code.
Here is an example Image I am trying to convert which throws the errors:
I realize this code has multiple inner try-catches, however I wanted to illustrate the problem.
Within each try below I have comments showing the exception and error I receive.
public static Bitmap ConvertToFormat(this Bitmap Source, PixelFormat TargetFormat)
{
try
{
//This throws OutOfMemoryException: "Out of memory."
return Source.Clone(new Rectangle(0, 0, Source.Width, Source.Height), TargetFormat);
}
catch (OutOfMemoryException)
{
try
{
MemoryStream ResultStream = new MemoryStream();
// This throws ExternalException: "A generic error occurred in GDI+"
Source.Save(ResultStream, ImageFormat.Gif);
ResultStream.Position = 0;
return new Bitmap(ResultStream);
}
catch (ExternalException)
{
// this is just an attempt to break the process down further to try and find the cause:
ImageCodecInfo myImageCodecInfo = GetCodecInfo(ImageFormat.Gif);
EncoderParameters myEncoderParameters = new EncoderParameters(2);
myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Compression, (long)EncoderValue.CompressionLZW); ;
myEncoderParameters.Param[1] = new EncoderParameter(Encoder.Quality, 0L);
MemoryStream ResultStream = new MemoryStream();
// This throws ExternalException: "A generic error occurred in GDI+"
Source.Save(ResultStream, myImageCodecInfo, myEncoderParameters);
ResultStream.Position = 0;
return new Bitmap(ResultStream);
}
}
}
private static ImageCodecInfo GetCodecInfo(ImageFormat TargetFormat)
{
return ImageCodecInfo.GetImageEncoders().ToList().Find(
delegate (ImageCodecInfo codec)
{ return codec.FormatID == TargetFormat.Guid; });
}
I know the source image is good as I can read the pixels just fine using LockBits(). I am considering using a loop to create a new image pixel by pixel using this, but I would prefer to use the more direct clone option as it automatically handles color palette creation, color matching and dithering.
UPDATE:
I found the code causing the issue, but I am unsure why.
I did not want the file to be locked, so I was using the code below to load the image into memory and then unlock the file. Apparently this was causing issues, but only when calling the Clone() method. When I use that same image with LockBits() it allows me to access every pixel via the memory pointer just fine and also it displays just fine in a PictureBox. Does anyone know why this method is causing a .Clone() error and also how can I load an Image file into memory and then immediatly release the file?
using (Stream s = File.OpenRead(SourceFileName))
{
return (Bitmap)Bitmap.FromStream(s);
}
I am having a bit of a hard time converting MemoryStream into BitmapImage. There are a lot of questions on SO regarding similar situations, but after trying everything on them, I've been unable to fix this, so I turn to you. Note that I'm working with Magick.NET (ImageMagick.NET) and Tessnet2 -- that is what some of that code is.
I use Bitmap class to do most of the work in Magick.NET and Tessnet2. BitmapImage is used for displaying purposes.
First, I load up the PDF and extract a cropped bitmap from its first page:
public Task PdfToBmp(string path)
{
return Task.Run(() =>
{
using (var image = new MagickImage())
{
MagickNET.SetGhostscriptDirectory("./");
var settings = new MagickReadSettings
{
Density = new MagickGeometry(300, 300),
FrameCount = 1
};
image.Read(path, settings);
image.Crop(new MagickGeometry(1850, 200, 600, 140));
// ImageStream is a MemoryStream property.
ImageStream = new MemoryStream();
image.Write(ImageStream, MagickFormat.Bmp);
ImageStream.Position = 0;
}
});
}
That is when I save the bitmap into the MemoryStream. Once I have MemoryStream loaded up, I move onto working with it. I instantiate a Bitmap, so that I may use it for Tessnet2 related work and then try to instantiate a BitmapImage.
public Task DoOcr()
{
if (ImageStream == null)
{
return null;
}
TargetImage = new Bitmap(ImageStream);
ImageStream.Position = 0;
// ----------------------- Problem Area ----------------------- //
DisplayImage = new BitmapImage();
DisplayImage.BeginInit();
DisplayImage.StreamSource = ImageStream;
DisplayImage.CacheOption = BitmapCacheOption.OnLoad;
DisplayImage.EndInit();
//ImageStream.Close();
// ------------------------------------------------------------ //
return Task.Run(() =>
{
var ocr = new Tesseract();
ocr.Init("tessdata", "eng", false);
var results = ocr.DoOCR(TargetImage, Rectangle.Empty);
Dispatcher.Invoke(() =>
{
Results = new ObservableCollection<Word>(results);
});
});
}
This is where I'm having a problem. Without that DisplayImage block, the program runs fine and I just don't get the displayed image. I'm even able to save the Bitmap (TargetImage) to a file with no problems. However, with the DisplayImage block, I get System.NullReferenceException:
System.NullReferenceException occurred
_HResult=-2147467261
_message=Object reference not set to an instance of an object.
HResult=-2147467261
IsTransient=false
Message=Object reference not set to an instance of an object.
Source=System
StackTrace:
at System.Uri.CreateThisFromUri(Uri otherUri)
InnerException:
I'm unable to pinpoint where it occurs exactly, because the ImageStream object looks "fine" upon inspection. It contains data and is at position 0. If I try to close it, or do anything with it, after assigning it as the StreamSource to DisplayImage, I get a null exception on the line that attempts to perform such action. I even tried creating two different streams, to see if that's the problem; however, I was getting the exact same behavior. Debugging this is kind of a pain, considering it doesn't point to any one specific line. There's obviously an issue between this MemoryStream and BitmapImage. Could it be possible that there's some sort of format/conversion problem between the two, but not between MemoryStream and Bitmap in this particular situation?
I tried the file route, where I save MagickImage to a file and load it up into BitmapImage through Uri and it worked flawlessly; however, I would like to be able to perform this in-memory. By the way, setting position to 0 on the MemoryStream did not seem to affect either Bitmap (loads properly) or BitmapImage (same exception).
The temporary fix I currently use is to make DisplayImage a BitmapSource, rather than BitmapImage:
DisplayImage = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
TargetImage.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight(TargetImage.Width, TargetImage.Height));
The Magick.NET's Write() method has some bugs, so we have to use ToBitmap().
image.ToBitmap().Save(ImageStream, System.Drawing.Imaging.ImageFormat.Bmp);
I have a Web service which is connected to a DB, I need to pull out a type BLOB from that BD through the web service and then create an Image. The web service send a bytes array from the blob and I tried with a converter bind to the image in XML (like some suggestions I found) like this
using (Stream ms = new MemoryStream(fileBytes, 0, fileBytes.Length))
{
ms.Write(fileBytes, 0, fileBytes.Length);
ms.Seek(0, SeekOrigin.Begin);
BitmapImage bitmapImage = new BitmapImage();
////////////////Exception here
bitmapImage.SetSource(ms);
return bitmapImage;
}
But then I get this error (Exception from HRESULT: 0x88982F50). Then I found that maybe could be the format of the array of bytes the problem, that maybe could be in base64 so I've changed the web service and now it sends me an 64-Base String and then changed to the array of bytes, but still with the same error.
I found this post but still no luck. Then I've found a lot of solutions like InMemoryRandomAccessStream or Image.FromStream but those solutions are for WP 8.1
Also I used:
image.SaveJpeg(stream, image.PixelWidth, image.PixelHeight, 0, 90);
///////AND////////
image = PictureDecoder.DecodeJpeg(ms);
but still no luck
I'm sure that I'm missing something because every solution point out to these solutions but I really can't figure it out.
I accomplish this (loading a binary object from database into an image) using the following function:
public static BitmapImage LoadImage(byte[] imageData)
{
if (imageData == null || imageData.Length == 0) return null;
var image = new BitmapImage();
using (var mem = new MemoryStream(imageData))
{
mem.Position = 0;
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = null;
image.StreamSource = mem;
image.EndInit();
}
image.Freeze();
return image;
}
As you can see, the function takes a byte[] array as a parameter. I get this array from the database like this:
using (var reader = dataLayer.ExecuteReader(sqlString))
{
if (reader.Read())
{
if (reader["ImageData"] != null && reader["ImageData"] != DBNull.Value)
{
imageBytes = (byte[])reader["ImageData"];
}
}
}
where ImageData is the column name from the database. The LoadImage() function is then called with the imageBytes passed in as a parameter.
I finally get it, it was a error with the DB actually. The data on the column I was getting the array of bytes was corrupt or has another use that I don't understand, so I contact with the DB administrator and he helped me with that so now I have the correct data. the first code really works. Thanks to everyone for the help
I am trying to open a bitmap file and then change it and save it, but I am getting some error. The code is as follow:
var tempFileNamePath = Path.Combine(workingDirectory, fileName);
Bitmap image = new Bitmap(tempFileNamePath);
var newImage = (Bitmap)image.Clone();
image.Dispose();
newImage.EnhanceImage();
newImage.Save(tempFileNamePath, System.Drawing.Imaging.ImageFormat.Jpeg);
newImage.Dispose();
But it fails to save the file with error: A generic error happens in GDI+
Any thought of why tis is happening?
Bitmap.Clone() doesn't do what you hope it does. It is a shallow copy, it still uses the pixel data of the original image. So disposing the original image doesn't release the lock on the file.
To get a deep copy use the Bitmap(Image) constructor:
Bitmap newImage = null;
using (var image = new Bitmap(tempFileNamePath)) {
newImage = new Bitmap(image);
}
Renaming the original file would be cheap alternative that uses less memory, favor this when the image is large:
newImage.EnhanceImage();
var tmpname = tempFileNamePath + ".bak";
System.IO.File.Delete(tmpname);
System.IO.File.Move(tempFileNamePath, tmpname);
try {
newImage.Save(tempFileNamePath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch {
System.IO.File.Move(tmpname, tempFileNamePath);
throw;
}
finally {
newImage.Dispose();
}
System.IO.File.Delete(tmpname);