I need to get the URI of an in-memory bitmap because the class I want to use accepts only bitmap URIs, not byte[] data. Also, I don't want to create temporary files for this purpose but operate only with the memory. In .NET Framework I can do this:
Uri GetMemoryBitmapUri()
{
MemoryStream packStream = new MemoryStream();
Package pack = Package.Open(packStream, FileMode.Create, FileAccess.ReadWrite);
Uri packUri = new Uri("packUri:");
PackageStore.AddPackage(packUri, pack); // we don't have PackageStore in .NET
Uri packPartUri = new Uri("/bitmap.jpg", UriKind.Relative);
PackagePart packPart = pack.CreatePart(packPartUri, System.Net.Mime.MediaTypeNames.Image.Jpeg);
var bitmapBytes = GetInMemoryBitmapData();
packPart.GetStream().Write(bitmapBytes, 0, bitmapBytes.Length);
return PackUriHelper.Create(packUri, packPart.Uri);
}
And it works - the reference returned from GetMemoryBitmapUri() can be passed to the method of the class I would like to use and the bitmap is drawn.
But I have a problem when trying to do this in .NET 7 since there is no longer PackageStore class in System.IO.Packaging and so I cannot make PackageStore.AddPackage call. How can I handle this problem?
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;
}
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.
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.
I have found how to do this in .NET 4.0, but I think JpegBitmapEncoder doesn't exist in Silverlight:
MemoryStream memStream = new MemoryStream();
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(imageC));
encoder.Save(memStream);
var bytes = memStream.GetBuffer();
How can I convert an image to bytes[] in silverlight?
UPDATE:
I have a Contact model, which has a Photo property. Whenever I add a new Contact, I would like to load a local default Image and convert it and set the Photo property to it.
var bitmapImage = new BitmapImage
{
UriSource = new Uri("pack://application:,,,/xxx;component/Images/default.JPG")
};
var image = new Image{Source = bitmapImage};
Is this the correct way to load an image in first place?
Use
myImage.Save(memStream, ImageFormat.Jpeg);
return memStream.ToArray();
UPDATE
OK it turns out that the image is a BitmapImage.
It seems that BitmapImage does not expose the functionality to save the image. The solution is to get the image from the embedded resource:
Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourcePath);
byte[] buffer = new byte[s.Length];
s.Read(buffer, 0, buffer.Length);
Have a look at this library: Imagetools
It contains some nice utilities and jpg and png encoders,