C# out of memory exception in GetThumbnailImage on a server - c#

I am running the below code to create a thumbnail when a user sends us an image:
public int AddThumbnail(byte[] originalImage, File parentFile)
{
File tnFile = null;
try
{
System.Drawing.Image image;
using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(originalImage))
{
image = System.Drawing.Image.FromStream(memoryStream);
}
Log.Write("Original image width of [" + image.Width.ToString() + "] and height of [" + image.Height.ToString() + "]");
//dimensions need to be changeable
double factor = (double)m_thumbnailWidth / (double)image.Width;
int thHeight = (int)(image.Height * factor);
byte[] tnData = null;
Log.Write("Thumbnail width of [" + m_thumbnailWidth.ToString() + "] and height of [" + thHeight + "]");
using (System.Drawing.Image thumbnail = image.GetThumbnailImage(m_thumbnailWidth, thHeight, () => false, IntPtr.Zero))
{
using (System.IO.MemoryStream tnStream = new System.IO.MemoryStream())
{
thumbnail.Save(tnStream, System.Drawing.Imaging.ImageFormat.Jpeg);
tnData = new byte[tnStream.Length];
tnStream.Position = 0;
tnStream.Read(tnData, 0, (int)tnStream.Length);
}
}
//there is other code here that is not relevant to the problem
}
catch (Exception ex)
{
Log.Error(ex);
}
return (tnFile == null ? -1 : tnFile.Id);
}
This works fine on my machine, but when I run it on a test server I always get an out of memory exception on the line:
using (System.Drawing.Image thumbnail = image.GetThumbnailImage(m_thumbnailWidth, thHeight, () => false, IntPtr.Zero))
It is not manipulating a large image: it is trying to convert a 480*640 image into a 96*128 thumbnail. I don't know how to investigate / resolve this issue. Has anyone got any suggestions? It always happens, even after I have restarted IIS. I did initially think that the image might be corrupt but the dimensions are correct.
Thanks.

We also had similar problems using GDI+ Operations in our ASP.Net server. Your mention of your code running on a server made me think, that this could be the same problem.
Please be aware, that the usage of classes in the System.Drawing Namespace is not supported on a server. The fatal thing is, that it may work for some time and suddenly (even without code changes) errors occur.
We had to rewrite a significant part of our server code.
See the comment:
Caution note
Classes within the System.Drawing namespace are
not supported for use within a Windows or ASP.NET service. Attempting
to use these classes from within one of these application types may
produce unexpected problems, such as diminished service performance
and run-time exceptions. For a supported alternative, see Windows
Imaging Components.
Source:
http://msdn.microsoft.com/de-de/library/system.drawing(v=vs.110).aspx

Many thanks #vcsjones for pointing me in the right direction. Instead of using image.GetThumbnailImage I call:
public static Image ResizeImage(Image imgToResize, Size size)
{
return (Image)(new Bitmap(imgToResize, size));
}
The troublesome line of code is now:
using(Image thumbnail = ResizeImage(image, new Size(m_thumbnailWidth, thHeight)))
I got this line from Resize an Image C#
It now works!

Related

Access image object from resource file

In my project, I need to retrieve a custom image file (from disk). If the image file does not exist at the path provided, then the app will use a default image (embedded resource). Once I have the image, I need to resize it for use futher on in my application.
If I attempt to access only the embedded resource (Code Section 1), everything works as expected. If attempt to place a condition on the image (Code Section 2), the object comes back with all kinds of exceptions on the object, most notably for my purposes:
((System.Drawing.Image)(ReportLogoToUse)).Height' threw an exception of type 'System.ArgumentException' int {System.ArgumentException}
((System.Drawing.Image)(ReportLogoToUse)).Width' threw an exception of type 'System.ArgumentException' int {System.ArgumentException}
Here is my code
// Code Section 1
using (var myImage = Resources.sie_logo_petrol_rgb){
// resize the image to max allowed dimensions (64 x 233)
var resizedImage = Helpers.ResizeImage(myImage, (int)maxWidth, (int)maxHeight); // this code executes with no errors
pictureBox1.Image = resizedImage;
}
// Code Section 2
using (var ReportLogoToUse = Helpers.ReportLogo(filePath)){
// resize the image to max allowed dimensions (64 x 233)
var resizedImage = Helpers.ResizeImage(ReportLogoToUse, (int)maxWidth, (int)maxHeight); // Invalid Parameter error
pictureBox2.Image = resizedImage;
}
public static Bitmap ReportLogo(string filePath){
try{
var myImage = Image.FromFile(filePath, true);
return (Bitmap)myImage;
}
catch (Exception ex){
// use the embedded logo
using (var myResourceImage = Resources.sie_logo_petrol_rgb){
var myImage = myResourceImage;
return (Bitmap)myImage;
}
}
}
What is the difference between the objects in Code Section 1 and Code Section 2? Aren't they returning the same kind of object?
By removing the using... block in the catch... section, and just returning the file itself, it appears to be functioning now.
public static Bitmap ReportLogo(string filePath){
try{
return (Bitmap)Image.FromFile(filePath, true);
}
catch (Exception ex){
// use the embedded logo
return Resources.sie_logo_petrol_rgb;
}
}
Any insight as to why it works now would be greatly appreciated (because I am completely baffled).

.NET - Bitmap.Save ignores Bitmap.SetResolution on Windows 7

I'm writing a .NET 4 application that imports and saves images for printing. It's important that the saved images resolution (DPI not pixel dimensions) be set to the value we specify so they print correctly.
Some of the images we import come without the resolution value (bad EXIF when they were generated), so we have to correct that before writing them. We use Bitmap.SetResolution for that. It works fine on XP and Windows 8, but when we write (Bitmap.Save) the images on Windows 7, they are always written with the original resolution meta info, ignoring SetResolution.
Here's a test we made, works on XP and 8, not on 7.
string originalFile = #"D:\temp\img\original_img.jpg";
string newFile = #"D:\temp\img\new_img.jpg";
Bitmap bitmap = (Bitmap)Image.FromFile(originalFile);
bitmap.SetResolution(200, 200);
bitmap.Save(newFile, ImageFormat.Jpeg);
Image image = Image.FromFile(newFile);
int dpiX = (int)Math.Round(image.HorizontalResolution, MidpointRounding.ToEven);
int dpiY = (int)Math.Round(image.VerticalResolution, MidpointRounding.ToEven);
Console.WriteLine("DPI is {0} x {1}", dpiX, dpiY);
Before saving, debug always shows the correct resolution assigned by SetResolution, the saved image is where the problem is.
This is probably what was reported here:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/62368caa-05f4-4798-9c59-5d82f881a97c/systemdrawingbitmapsetresolution-is-completely-broken-on-windows-7?forum=netfxbcl
But the issue there seems to remain unsolved. Is there really no way to just make it work? Do I have to use extra libraries for this?
I've found a workaround that will do the job. It's not elegant but...
Instead of applying the resolution to the original image, make a copy of it and work on the copy:
Bitmap bitmap = (Bitmap)Image.FromFile(originalFile);
Bitmap newBitmap = new Bitmap(bitmap)
newBitmap.SetResolution(200, 200);
newBitmap.Save(newFile, ImageFormat.Jpeg);
Now it works on Windows 7. Go figure.
I like Hans Passant's idea, though, it's cleaner. I don't know if what I did messes up with the image, if there is recompression or not.
Hmya, this is a bug in a Windows component. The Windows group is always very reluctant to get bugs like this fixed, breaking changes are postponed to a next Windows version. It did get fixed in Windows 8. Do consider how unusual it is what you are doing, the DPI of an image should always be set by the device that recorded the image. Like the camera or scanner, they never get this wrong. There just isn't any device around that has a 200 dots-per-inch resolution.
If you are desperate enough to find a workaround then you could consider patching the file itself. Not hard to do for a JPEG file, the fields in the file header are pretty easy to get to:
using System.IO;
...
public static void SetJpegResolution(string path, int dpi) {
using (var jpg = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
using (var br = new BinaryReader(jpg)) {
bool ok = br.ReadUInt16() == 0xd8ff; // Check header
ok = ok && br.ReadUInt16() == 0xe0ff;
br.ReadInt16(); // Skip length
ok = ok && br.ReadUInt32() == 0x4649464a; // Should be JFIF
ok = ok && br.ReadByte() == 0;
ok = ok && br.ReadByte() == 0x01; // Major version should be 1
br.ReadByte(); // Skip minor version
byte density = br.ReadByte();
ok = ok && (density == 1 || density == 2);
if (!ok) throw new Exception("Not a valid JPEG file");
if (density == 2) dpi = (int)Math.Round(dpi / 2.56);
var bigendian = BitConverter.GetBytes((short)dpi);
Array.Reverse(bigendian);
jpg.Write(bigendian, 0, 2);
jpg.Write(bigendian, 0, 2);
}
}

Why is my image distorted when decoding as FlateDecode using iTextSharp?

When decoding an image within a PDF as FlateDecode via iTextSharp the image is distorted and I can't seem to figure out why.
The recognized bpp is Format1bppIndexed. If I modify the PixelFormat to Format4bppIndexed the image is recognizable to some degree (shrunk, coloring is off but readable) and is duplicated 4 times in a horizontal manner. If I adjust the pixel format to Format8bppIndexed it is also recognizable to some degree and is duplicated 8 times in a horizontal manner.
The image below is after a Format1bppIndexed pixel format approach. Unfortunately I am unable to show the others due to security constraints.
The code is seen below which is essentially the single solution I have come across littered around both SO and the web.
int xrefIdx = ((PRIndirectReference)obj).Number;
PdfObject pdfObj = doc.GetPdfObject(xrefIdx);
PdfStream str = (PdfStream)(pdfObj);
byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)str);
string filter = ((PdfArray)tg.Get(PdfName.FILTER))[0].ToString();
string width = tg.Get(PdfName.WIDTH).ToString();
string height = tg.Get(PdfName.HEIGHT).ToString();
string bpp = tg.Get(PdfName.BITSPERCOMPONENT).ToString();
if (filter == "/FlateDecode")
{
bytes = PdfReader.FlateDecode(bytes, true);
System.Drawing.Imaging.PixelFormat pixelFormat;
switch (int.Parse(bpp))
{
case 1:
pixelFormat = System.Drawing.Imaging.PixelFormat.Format1bppIndexed;
break;
case 8:
pixelFormat = System.Drawing.Imaging.PixelFormat.Format8bppIndexed;
break;
case 24:
pixelFormat = System.Drawing.Imaging.PixelFormat.Format24bppRgb;
break;
default:
throw new Exception("Unknown pixel format " + bpp);
}
var bmp = new System.Drawing.Bitmap(Int32.Parse(width), Int32.Parse(height), pixelFormat);
System.Drawing.Imaging.BitmapData bmd = bmp.LockBits(new System.Drawing.Rectangle(0, 0, Int32.Parse(width),
Int32.Parse(height)), System.Drawing.Imaging.ImageLockMode.WriteOnly, pixelFormat);
Marshal.Copy(bytes, 0, bmd.Scan0, bytes.Length);
bmp.UnlockBits(bmd);
bmp.Save(#"C:\temp\my_flate_picture-" + DateTime.Now.Ticks.ToString() + ".png", ImageFormat.Png);
}
What do I need to do to so that my image extraction works as desired when dealing with FlateDecode?
NOTE: I do not want to use another library to extract the images. I am looking for a solution leveraging ONLY iTextSharp and the .NET FW. If a solution exists via Java (iText) and is easily portable to .NET FW bits that would suffice as well.
UPDATE: The ImageMask property is set to true, which would imply that there is no color space and is therefore implicitly black and white. With the bpp coming in at 1, the PixelFormat should be Format1bppIndexed which as mentioned earlier, produces the embedded image seen above.
UPDATE: To get the image size I extracted it out using Acrobat X Pro and the image size for this particular example was listed as 2403x3005. When extracting via iTextSharp the size was listed as 2544x3300. I modified the image size within the debugger to mirror 2403x3005 however upon calling Marshal.Copy(bytes, 0, bmd.Scan0, bytes.Length); I get an exception raised.
Attempted to read or write protected memory. This is often an
indication that other memory is corrupt.
My assumption is that this is due to the modification of the size and thus no longer corresponding to the byte data that is being used.
UPDATE: Per Jimmy's recommendation, I verified that calling PdfReader.GetStreamBytes returns a byte[] length equal to widthheight/8 since GetStreamBytes should be calling FlateDecode. Manually calling FlateDecode and calling PdfReader.GetStreamBytes both produced a byte[] length of 1049401, while the widthheight/8 is 2544*3300/8 or 1049400, so there is a difference of 1. Not sure if this would be the root cause or not, an off by one; however I am not sure how to resolve if that is indeed the case.
UPDATE: In trying the approach mentioned by kuujinbo I am met with an IndexOutOfRangeException when I attempt to call renderInfo.GetImage(); within the RenderImage listener. The fact that the width*height/8 as stated earlier is off by 1 in comparison to the byte[] length when calling FlateDecode makes me think these are all one in the same; however a solution still eludes me.
at System.util.zlib.Adler32.adler32(Int64 adler, Byte[] buf, Int32 index, Int32 len)
at System.util.zlib.ZStream.read_buf(Byte[] buf, Int32 start, Int32 size)
at System.util.zlib.Deflate.fill_window()
at System.util.zlib.Deflate.deflate_slow(Int32 flush)
at System.util.zlib.Deflate.deflate(ZStream strm, Int32 flush)
at System.util.zlib.ZStream.deflate(Int32 flush)
at System.util.zlib.ZDeflaterOutputStream.Write(Byte[] b, Int32 off, Int32 len)
at iTextSharp.text.pdf.codec.PngWriter.WriteData(Byte[] data, Int32 stride)
at iTextSharp.text.pdf.parser.PdfImageObject.DecodeImageBytes()
at iTextSharp.text.pdf.parser.PdfImageObject..ctor(PdfDictionary dictionary, Byte[] samples)
at iTextSharp.text.pdf.parser.PdfImageObject..ctor(PRStream stream)
at iTextSharp.text.pdf.parser.ImageRenderInfo.PrepareImageObject()
at iTextSharp.text.pdf.parser.ImageRenderInfo.GetImage()
at cyos.infrastructure.Core.MyImageRenderListener.RenderImage(ImageRenderInfo renderInfo)
UPDATE: Trying varying the varying methods listed here in my original solution as well as the solution posed by kuujinbo with a different page in the PDF produces imagery; however the issues always surface when the the filter type is /FlateDecode and no image is produced for that given instance.
Try copy your data row by row, maybe it will solve the problem.
int w = imgObj.GetAsNumber(PdfName.WIDTH).IntValue;
int h = imgObj.GetAsNumber(PdfName.HEIGHT).IntValue;
int bpp = imgObj.GetAsNumber(PdfName.BITSPERCOMPONENT).IntValue;
var pixelFormat = PixelFormat.Format1bppIndexed;
byte[] rawBytes = PdfReader.GetStreamBytesRaw((PRStream)imgObj);
byte[] decodedBytes = PdfReader.FlateDecode(rawBytes);
byte[] streamBytes = PdfReader.DecodePredictor(decodedBytes, imgObj.GetAsDict(PdfName.DECODEPARMS));
// byte[] streamBytes = PdfReader.GetStreamBytes((PRStream)imgObj); // same result as above 3 lines of code.
using (Bitmap bmp = new Bitmap(w, h, pixelFormat))
{
var bmpData = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.WriteOnly, pixelFormat);
int length = (int)Math.Ceiling(w * bpp / 8.0);
for (int i = 0; i < h; i++)
{
int offset = i * length;
int scanOffset = i * bmpData.Stride;
Marshal.Copy(streamBytes, offset, new IntPtr(bmpData.Scan0.ToInt32() + scanOffset), length);
}
bmp.UnlockBits(bmpData);
bmp.Save(fileName);
}
If you're able to use the latest version (5.1.3), the API to extract FlateDecode and other image types has been simplified using the iTextSharp.text.pdf.parser namespace. Basically you use a PdfReaderContentParser to help you parse the PDF document, then you implement the IRenderListener interface specifically (in this case) to deal with images. Here's a working example HTTP handler:
<%# WebHandler Language="C#" Class="bmpExtract" %>
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.parser;
public class bmpExtract : IHttpHandler {
public void ProcessRequest (HttpContext context) {
HttpServerUtility Server = context.Server;
HttpResponse Response = context.Response;
PdfReader reader = new PdfReader(Server.MapPath("./bmp.pdf"));
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
MyImageRenderListener listener = new MyImageRenderListener();
for (int i = 1; i <= reader.NumberOfPages; i++) {
parser.ProcessContent(i, listener);
}
for (int i = 0; i < listener.Images.Count; ++i) {
string path = Server.MapPath("./" + listener.ImageNames[i]);
using (FileStream fs = new FileStream(
path, FileMode.Create, FileAccess.Write
))
{
fs.Write(listener.Images[i], 0, listener.Images[i].Length);
}
}
}
public bool IsReusable { get { return false; } }
public class MyImageRenderListener : IRenderListener {
public void RenderText(TextRenderInfo renderInfo) { }
public void BeginTextBlock() { }
public void EndTextBlock() { }
public List<byte[]> Images = new List<byte[]>();
public List<string> ImageNames = new List<string>();
public void RenderImage(ImageRenderInfo renderInfo) {
PdfImageObject image = null;
try {
image = renderInfo.GetImage();
if (image == null) return;
ImageNames.Add(string.Format(
"Image{0}.{1}", renderInfo.GetRef().Number, image.GetFileType()
));
using (MemoryStream ms = new MemoryStream(image.GetImageAsBytes())) {
Images.Add(ms.ToArray());
}
}
catch (IOException ie) {
/*
* pass-through; image type not supported by iText[Sharp]; e.g. jbig2
*/
}
}
}
}
The iText[Sharp] development team is still working on the implementation, so I can't say for sure if it will work in your case. But it does work on this simple example PDF. (used above and with a couple of other PDFs I tried with bitmap images)
EDIT: I've been experimenting with the new API too and made a mistake in the original code example above. Should have initialized the PdfImageObject to null outside the try..catch block. Correction made above.
Also, when I use the above code on an unsupported image type, (e.g. jbig2) I get a different Exception - "The color depth XX is not supported", where "XX" is a number. And iTextSharp does support FlateDecode in all the examples I've tried. (but that's not helping you in this case, I know)
Is the PDF produced by third-party software? (non-Adobe) From what I've read in the book, some third-party vendors produce PDFs that aren't completely up to spec, and iText[Sharp] can't deal with some of these PDFs, while Adobe products can. IIRC I've seen cases specific to some PDFs generated by Crystal Reports on the iText mailing list that caused problems, here's one thread.
Is there any way you can generate a test PDF with the software you're using with some non-sensitive FlateDecode image(s)? Then maybe someone here could help a little better.

A generic error occurred in GDI+. (Only if i try it on the server)

Hello I have problem with my resizing and uploading img to server. Everything was ok, but today tell me friend when he want add img to server, he gets "A generic error occurred in GDI+.".. But in my PC all works fine. So can be problem with IIS? (Two days ago he had some problem so admin change something on server).
Bitmap image = KTEditImage.ResizeImage(new Bitmap(file.PostedFile.InputStream), 360, 360);
image.Save(Server.MapPath("~") + "/Static/Img/Zbozi/" + urlName, ImageFormat.Jpeg);
image.Dispose();
Bitmap smallImage = KTEditImage.ResizeImage(new Bitmap(file.PostedFile.InputStream), 230, 230);
smallImage.Save(Server.MapPath("~") + "/Static/Img/Zbozi/Small/" + urlName, ImageFormat.Jpeg);
smallImage.Dispose();
and resize method is
public static Bitmap ResizeImage(Bitmap image, int maxWidth, int maxHeight)
{
return new Bitmap(image, maxWidth, maxHeight);
}
Grant write permission on the target directory to ASPNET account(Windows XP) or NETWORK SERVICE account(Windows Server 2003/2008/Vista/7),
I had something similar to this problem where I was resizing an image and replacing the original with the resized version. I turned out GDI+ Exception was due to the fact that the image that was causing problems was Read Only and was unable to be overwritten.
My goal in the following code is to resize images that exceed a maximum filesize.
for (int i = 0; i < LoadedImgs.Length; i++)
{
info = new FileInfo(LoadedImgs[i].origImgFullPath);
double sizeMB = Math.Round(((double)info.Length / 1048576.0), MidpointRounding.AwayFromZero);
if (sizeMB > (double)numImgMaxSize.Value)
{
Bitmap bmpOrigImg = new Bitmap(LoadedImgs[i].origImgFullPath);
Bitmap bmpResizeImg = null;
bmpResizeImg = ImageUtilities.Resize(bmpOrigImg, sizeMB);
#region Save the resized image over the original
bmpOrigImg.Dispose();
bmpResizeImg.Save(LoadedImgs[i].origImgFullPath);
bmpResizeImg.Dispose();
#endregion
}
}
Also, my resizing algorithm to a specific file size needs tweaking (doesn't include bit compression, etc) but in the name of sharing:
Bitmap origBmp = new Bitmap(image.Width, image.Height);
double ratio = (double)image.Width / (double)image.Height;
double bitDepth = 32.0;//Output BMP default
double newHeight = Math.Sqrt((1024.0 * 1024.0 * 8.0) / (ratio * bitDepth));
int height = (int)Math.Round(newHeight, MidpointRounding.AwayFromZero);
int width = (int)Math.Round(newHeight * ratio);
It is probably a permission issue with saving the file to that path. You need to be sure that the "/Static/Img/Zbozi" and "/Static/Img/Zbozi/Small" directories allow anonymous users to save files.
This problem is due to image resource handled by .Net framework, please use GC.Collect(); after code

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