How to find reason for Generic GDI+ error when saving an image?
Asked Answered
C

11

46

Having a code that works for ages when loading and storing images, I discovered that I have one single image that breaks this code:

const string i1Path = @"c:\my\i1.jpg";
const string i2Path = @"c:\my\i2.jpg";

var i = Image.FromFile(i1Path);
i.Save(i2Path, ImageFormat.Jpeg);

The exception is:

System.Runtime.InteropServices.ExternalException occurred

A generic error occurred in GDI+.

at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
at System.Drawing.Image.Save(String filename, ImageFormat format)
at ...

As far as I can see, there is nothing special about the image. It is approx 250 pixels in size and can be opened in e.g. Windows Image Viewer or Paint.NET:

enter image description here

(Since the image above, after being uploaded to Stack Overflow does not produce the error anymore, I've put the original image here)

What I discovered is that upon calling the Save method, the destination image file is being created with zero bytes.

I am really clueless on what causes the error.

My questions:

  • Can you think of any special thing that would hinder .NET from saving the image?
  • Is there any way (beside panicing) to narrow down these kind of errors?
Conscious answered 22/3, 2013 at 13:2 Comment(2)
MSDN says a Bitmap loaded from a Stream requires the Stream to remain in existence as long as the Bitmap exists.Christoper
Unreleated to your problem: But the same exception occoures if the path does not exist (took me a while to figure out I had a typo). Might help someone else.Caudillo
C
63

While I still did not find out the reason what exactly caused the error when saving the image, I found a workaround to apply:

const string i1Path = @"c:\my\i1.jpg";
const string i2Path = @"c:\my\i2.jpg";

var i = Image.FromFile(i1Path);

var i2 = new Bitmap(i);
i2.Save(i2Path, ImageFormat.Jpeg);

I.e. by copying the image internally into a Bitmap instance and saving this image instead of the original image, the error disappeared.

I'm assuming that by copying it, the erroneous parts the caused the original Save call to fail are being removed an/or normalized, thus enabling the save operation to succeed.

saved image i2.jpg

Interestingly, the so stored image has a smaller file on disk (16 kB) than its original source (26 kB).

Conscious answered 24/3, 2013 at 6:35 Comment(5)
This worked for me as well. I had to force garbage collection afterwards, on account of the 'out of memory exception' that was caused.Hostetter
Worked for me too - no idea why. Only had the issue with jpg images (png etc were fine)Manic
I had this issue with .bmp, .jpg, and .png but I wasn't loading a file, I was creating it in memory and trying to save it. CAUSE: the original bitmap is tied to the stream it loaded from (FileStream or MemoryStream). The cloned bitmap it not tied to a stream, as it copied the pixel bytes. It might also have worked to Freeze the original bitmap before saving it.Christoper
I got this error for the second time, some how the first time I used the same solution as u. but the second time it's not workingBefuddle
i have an issue of the picture quality dropping rapidly, how do i fix thisLanguishing
S
21

First of all make sure, that the desired folder has Read/Write permissions. Changing the permissions solved this problem for me.

Sistrunk answered 16/2, 2014 at 5:50 Comment(2)
That's like 90% of the cases :-)Shattuck
Its almost always a 'cant write' error. So also make sure the filename doesn't contain slashes or something.Osbert
D
9

Solution is here, you must dispose image object to release the memory on the server. Try use using statement. Make sure destination directory on server exists too.

Downwards answered 28/4, 2014 at 12:53 Comment(5)
This sounds like a really bad answer to me.Conscious
"Make sure destination directory on server exists" was my issueGallous
@UweKeim - a using on a temporary IDisposable object just ensures the GC is called for it as soon as it is safe to do so.Christoper
"Make sure destination directory on server exists" was my issue as wellBarram
"Make sure destination directory on server exists" was my issue as well. So easy to overlook.Purism
P
6

The reason may be that the image is loaded lazily and the loading process is not yet finished when you try to save it.

Following what's said in this blog post (assuming you're German by the picture you linked in your question) provides a possible solution. Also this SO question's accepted answer indicates this is due to the fact the image file you're trying to save to is locked.

EDIT
For Ulysses Alves, from the linked blog entry: If you load an image using Image.FromFile() it remains locked until it is disposed of. This prevents calls to Save().

pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg");
pictureBox1.Image.Save("C:\\test\\test2.jpg");

The above code throws an error.

To make it work, you need to copy the image. The following code works:

pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg");
Image copy = pictureBox1.Image;
copy.Save("C:\\test\\test2.jpg")
Plucky answered 22/3, 2013 at 13:3 Comment(2)
I couldn't find anything related with this subject in the linked post. Could you please provide us a code example in your answer?Hultgren
My guess is that the line Image copy = pictureBox1.Image; is not creating a copy, but merely creating a new reference.Heidelberg
M
4

I found this question because I also faced the similar error and the file was actually created with zero length (if you don't see any file, first check the permissions to write into folder as other answers suggest). Although my code was slightly different (I use stream to read the image from memory, not from file), I think my answer may be helpful to anyone facing similar problem.

It may looks counter-intuitive, but you can't really dispose memory stream until you finish with image.

NOT WORKING:

Image patternImage;

using (var ms = new MemoryStream(patternBytes)) {
    patternImage = new Bitmap(ms);
}

patternImage.Save(patternFile, ImageFormat.Jpeg);

Just don't dispose the stream until you done with image.

WORKS:

using (var ms = new MemoryStream(patternBytes)) {
    patternImage = new Bitmap(ms);
    patternImage.Save(patternFile, ImageFormat.Jpeg);
}

What is misleading:

  • Error message doesn't really tell you anything
  • You can see the image properties, like width and height, but can't save it
Moises answered 25/12, 2018 at 0:9 Comment(2)
I had a similar kind of issue and this solution worked for me as well. Thanks.Dabber
is it mentioned in the documentation about reading an image and converting it into a bitmap before it is saved?Longterm
S
3

my solution was to make, write temp content (File.WriteAllText) just before saving the file

Here is the code:

var i = Image.FromFile(i1Path);
File.WriteAllText(i2Path, "empty");  // <---- magic goes here
i.Save(i2Path, ImageFormat.Jpeg);

Please try and let me know

Selinaselinda answered 17/12, 2014 at 14:13 Comment(1)
I can see where that would change when/where you got the exception if you did not have permission to create that file. :) :) But it would be weird if this resolves the other issues in the OP. bitmap.Freeze(); bitmap.Save(...); or var other = new Bitmap(bitmap); other.Save(...); Both of these ensure that the bitmap being saved is not bound to a stream before Save is called.Christoper
L
3

In my case I have accidentally deleted the directory where image was getting stored.

Latent answered 14/1, 2020 at 14:52 Comment(0)
H
1

Key Information:

// Using System.Drawing.Imaging:
new Bitmap(image).Save(memoryStream, ImageFormat.Jpeg);

You MUST Cast the Image to a Bitmap to Save it.

Using:

// Using System.Drawing.Imaging:
image.Save(memoryStream, ImageFormat.Jpeg);

WILL throw the Error:

Generic GDI+ error when saving an image

Halfassed answered 22/3, 2013 at 13:2 Comment(1)
Your code doesn't cast the Image to a Bitmap. A Bitmap is an Image type. Your example constructs a new Bitmap object from an existing Image object. The image object may already be a Bitmap object, merely referenced as an Image type.Rothman
V
1

Just use the visual studio as administrator or run the application created by the code as administrator it should work smoothly. It is user access rights issue. I faced the same and resolved it by running visual studio as administrator.

Vacua answered 20/3, 2020 at 18:34 Comment(0)
H
1

In my case, I set validateImageData to false:

Image.FromStream(stream, validateImageData: false);

solution:

Image.FromStream(stream, validateImageData: true);
Hostel answered 31/10, 2022 at 12:13 Comment(0)
P
0

Open in the program

const string i1Path = @"c:\my\i1.jpg";

const string i2Path = @"c:\my\i2.jpg";

var i = Image.FromFile(i1Path);

i.Save(i2Path, ImageFormat.Jpeg);

i.Dispose();
Poker answered 23/7, 2017 at 14:14 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.