System.Drawing.Image Performance


As I mentioned earlier, I wrote an application called JPEG Hammer for manipulating and viewing EXIF data in digital photos. As a .NET Application the single biggest performance bottleneck has been:


Image photo = Image.FromFile(fileName, true);

For a 6.1 megapixel (3008 x 2000) 1.47 MB JPEG it took on the order of 631 milliseconds to load. Multiply this by 50 or so photos and you are talking about 32 seconds to fully load these pictures. Then add the time necessary to draw the UI for the app, update thumbnails etc. On a 1.8 ghz Pentium 4 I’d expect more… and lets just say it’s no where near as fast as the XP Shell (or other non .NET phot apps), so what gives?


Well, after much Googling (with no success) I tried http://support.microsoft.com/ and I came across this gem (Microsoft KB 831419):


FIX: Slow performance when you call System.Drawing.Image.FromStream to load a bitmap image


So, curious as I am, I get my hands on this hotfix which updates:



  • System.Windows.Forms.dll
  • System.Design.dll
  • System.Drawing.dll

Specifically, this update adds a new method to System.Drawing.Imaging:


System.Drawing.Image.FromStream(Stream stream, bool useICM, bool validateImageData)

This is essentially a new signature for an existing method:


System.Drawing.Image.FromStream(Stream stream, bool useICM)

As you can see, validateImageData is a new parameter. Setting it to true is the default behavior that we have today (essentially the same as calling FromStream(Stream stream, bool useICM)).


So I made a change to my application. Before my code looked like this:


using (Image photo = Image.FromFile(this.fileInfo.FullName, true))
{
//do stuff
}

So I changed it to:


using (FileStream fs = new FileStream(this.fileInfo.FullName, FileMode.Open, FileAccess.ReadWrite))
{
using (Image photo = Image.FromStream(fs, true, false))
{
// do stuff
}
}

And here are the results. The average time it took to process 37 JPEGs taken from the same camera and roughly the same size went from 631ms to 6.76ms. So, this new method is 93x faster. Holy Cow!!! I thought that maybe something was wrong, so I re-ran the tests many times, and always got the same result. Simply mind boggling. This probably brings the .NET implementation to the same speed as writing native C++ code against GDI+.


The good news is that the article mentions that this fix will get rolled into the next Service Pack. However, you’ll need to modify your code as I did to take advantage of this.


Update: you can download this fix in SP1 of the .NET Framework 1.1:


http://www.microsoft.com/downloads/details.aspx?FamilyID=a8f5654f-088e-40b2-bbdb-a83353618b38&DisplayLang=en

Comments (18)

  1. Is a hotfix that needs to be installed on the user’s machine as well, or just the developers? If just the developers, then I’m definitely going to install this little sucker as well.

  2. Paschal says:

    This is another proof that MS should release a .Net 1.2 before whidbey !

    One of the multiple patches which are so necessary.

  3. CC says:

    Do you think that there will be a .Net 1.1 SP this year? Does anyone actually know?

  4. Omar Shahine says:

    This patch would need to be installed on each end user’s machine. I’m not sure what the mechanism is like for rolling hotfixes into the MSI installer for instance, but I’m sure it’s possible or else these hotfixes would be useless.

    As for future releases of .NET I have no idea…

  5. Paschal says:

    Can you publish or send me the patch ?

  6. Omar Shahine says:

    I believe you need to "contact PSS" per the KB article to get the patch. I happen to get it internally, and I’m not sure I can distribute it. I wouldn’t even know who to ask really (remember, I work on Mac stuff ;-)).

    The KB article states:

    "To resolve this problem immediately, contact Microsoft Product Support Services to obtain the hotfix. For a complete list of Microsoft Product Support Services phone numbers and information about support costs, visit the following Microsoft Web site:

    http://support.microsoft.com/default.aspx?scid=fh;[LN];CNTACTMS"

    I would just try and send them an e-mail asking for it.

    Try this link:

    https://webresponse.one.microsoft.com/oas/public/assistedintro.aspx

  7. RichB says:

    It looks like this new method opens up the potential for a security hole. The .Net team have mitigated it by requiring unmanaged permissions. The KB says:

    "Note To use the new API, the caller must have permission to run unmanaged code. "

    So, if you were using nGallery on a hosted website, you would not have unmanaged permissions and nGallery wouldn’t be able to take advantage of this API.

  8. Notes! It was 1am, so I didn’t read about the hotfix too much. Guess we’ll have to wait and see if they come out with something better in Whidbey,

  9. [.NET]System.Drawing.Image Performance

  10. I’ve gone ahead and written a helper method that does the same thing, but doesn’t require that you install a hot-fix. The hot-fix has additional features, like improving WinForms performance in some cases, but I’m sure a quick, easily distributed fix might be better for most applications.

    http://weblogs.asp.net/justin_rogers/archive/2004/03/31/105296.aspx

  11. Also, Omar, if you would be so kind as to possibly test my method within your framework to see if it offers the same speed I would be appreciative. While the code-paths I’m running should demonstrate a truncated version of what even the updated methods are doing, I’m not 100% certain they aren’t also adding additional performance benefits. Thanks.

  12. Jeff Cubinski says:

    Omar,

    Thanks for posting this. I have applied the hot fix and now my image is retrieved in much faster time. The problem I have now is that the winform displays with the database data I have retrieved before the image actually displays in the picture box – how can I get all to come up at the same time? This is a scanning program for access to facility – speed is Important! I have reduced it from 2 seconds over VPN to .6 second with this but the display isn;t good when data shows first then picture (JPG).

    Thanks.