tags:

views:

509

answers:

4

I have some JPEG files that I can't seem to load into my C# application. They load fine into other applications, like the GIMP. This is the line of code I'm using to load the image:

System.Drawing.Image img = System.Drawing.Image.FromFile(@"C:\Image.jpg");

The exception I get is: "A generic error occurred in GDI+.", which really isn't very helpful. Has anyone else run into this, or know a way around it?

Note: If you would like to test the problem you can download a test image that doesn't work in C#.

A: 

This thread from MSDN Forums may be useful.

The error may mean the data is corrupt or there is some underlying stream that has been close too early.

sigint
.NET definitely sees the image as corrupt, but I know that it's fine because it loads in the image editor "GIMP".
Jon Tackabury
Assuming it isn't a permissions problem, does it open properly in Paint.NET (because that uses .NET too)?
sigint
It doesn't work in Paint.NET either. :(
Jon Tackabury
the-locster is probably correct then; this means that image is slightly borked so that the .NET Jpeg-handling libraries can't accept it, whereas image processing apps like the GIMP don't have this problem.
sigint
I just tested the test image you provided. It opens for me on Paint.NET v3.36 on Windows 7 RC. Since Windows 7 has the latest .NET 3.5 bits, maybe it's a problem specific to the framework you're using? Have you tried applying the latest service pack for your framework?
sigint
@sigint: I'm on Windows XP with all the latest .NET 3.5 updates. I'll try it on Windows 7. Maybe there was an update to the behind-the-scenes GDI+ in Windows 7.
Jon Tackabury
A: 

The error can be a permission problem. Especially if your application is an ASP.NET application. Try moving the file to the same directory as your executable (if Win forms) or the root directory of your web application (if asp.net).

Tundey
I can load other image files from that same location. It doesn't matter where the image file is, it won't load.
Jon Tackabury
+1  A: 

.Net isn't handling the format of that particular image, potentially because the jpeg data format is slightly broken or non-standard. If you load the image into GIMP and save to a new file you can then load it with the Image class. Presumably GIMP is a bit more forgiving of file format problems.

locster
It's true, re-saving the image does fix the problem. What I want to know is why C# can't load this image, when non-.NET applications have no problem with it.
Jon Tackabury
Most likely the internal structure of the file violates the jpeg standard - and GIMP and other programs are capable of handling this. This is not an uncommon situation whereby early implementations of some standard contain an error or the spec was vague, and that error becomes a defacto standard. Either that or the Image class genuinely contains a bug or doesn't fully support the JPEG standard.
locster
+1  A: 

There's an exact answer to this problem. We ran into this at work today, and I was able to prove conclusively what's going on here.

The JPEG standard defines a metadata format, a file that consists of a series of "chunks" of data (which they call "segments"). Each chunk starts with FF marker, followed by another marker byte to identify what kind of chunk it is, followed by a pair of bytes that describe the length of the chunk (a 16-bit little-endian value). Some chunks (like FFD8, "Start of Image") are critical to the file's usage, and some (like FFFE, "Comment") are utterly meaningless.

When the JPEG standard was defined, they also included the so-called "APP markers" --- types FFE0 through FFEF --- that were supposed to be used for "application-specific data." These are abused in various ways by various programs, but for the most part, they're meaningless, and can be safely ignored, with the exception of APP0 (FFE0), which is used for JFIF data: JFIF extends the JPEG standard slightly to include additional useful information like the DPI of the image.

The problem with your image is that it contains an FFE1 marker, with a size-zero chunk following that marker. It's otherwise unremarkable image data (a remarkable image, but unremarkable data) save for that weird little useless APP1 chunk. GDI+ is wrongly attempting to interpret that APP1 chunk, probably attempting to decode it as EXIF data, and it's blowing up. (My guess is that GDI+ is dying because it's attempting to actually process a size-zero array.) GDI+, if it was written correctly, would ignore any APPn chunks that it doesn't understand, but instead, it tries to make sense of data that is by definition nonstandard, and it bursts into flames.

So the solution is to write a little routine that will read your file into memory, strip out the unneeded APPn chunks (markers FFE1 through FFEF), and then feed the resulting "clean" image data into GDI+, which it will then process correctly.

We currently have a contest underway here at work to see who can write the JPEG-cleaning routine the fastest, with fun prizes :-)


For the naysayers: That image is not "slightly nonstandard." The image uses APP1 for its own purposes, and GDI+ is very wrong to try to process that data. Other applications have no trouble reading the image because they rightly ignore the APP chunks like they're supposed to.

Sean Werkema
Excellent details! I'll give this a try, thanks. :)
Jon Tackabury