Exceptions thrown by BitmapImage and BitmapFrame

Scott Hanselman blogged about an ArgumentException that can be thrown when loading an image with a corrupted colour profile. Coincidentally, we had been unifying the exception handling for BitmapImage in the Logos 4 code that same day. These are all the exceptions we have found WPF (or WIC) to throw when loading a BitmapImage (by setting its StreamSource or UriSource property) or BitmapFrame (by calling BitmapFrame.Create).

ArgumentException

Sample Call Stack

    System.ArgumentException: The image has corrupted metadata header.
     ---> System.Runtime.InteropServices.COMException (0x88982F63): Exception from HRESULT: 0x88982F63
       --- End of inner exception stack trace ---
       at System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri,
         Stream stream, BitmapCacheOption cacheOption, Guid& clsId, Boolean&
         isOriginalWritable, Stream& uriStream, UnmanagedMemoryStream&
         unmanagedMemoryStream, SafeFileHandle& safeFilehandle)
       at System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri,
         Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption,
         RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
       at System.Windows.Media.Imaging.BitmapDecoder.Create(Stream bitmapStream,
         BitmapCreateOptions createOptions, BitmapCacheOption cacheOption)
       at System.Windows.Media.Imaging.BitmapFrame.CreateFromUriOrStream(Uri baseUri, Uri uri,
         Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption,
         RequestCachePolicy uriCachePolicy)
       at System.Windows.Media.Imaging.BitmapFrame.Create(Stream bitmapStream,
         BitmapCreateOptions createOptions, BitmapCacheOption cacheOption)

Cause and Workaround

An ArgumentException generally seems to be caused by a corrupted image header or metadata. Scott Hanselman suggests using BitmapCreateOptions.IgnoreColorProfile to ignore potentially corrupt colour profile information; we don’t know of any workarounds for other types of corruption.

COMException

Sample Call Stack

    System.Runtime.InteropServices.COMException (0x80070000): An invalid character was found in text content.
      at System.Windows.Media.ColorContextHelper.OpenColorProfile(IntPtr pProfile)
      at System.Windows.Media.ColorContext.FromRawBytes(Byte[] data, Int32 dataLength)
      at System.Windows.Media.ColorContext.FromStream(Stream stm, String filename)
      at System.Windows.Media.ColorContext.Initialize(Uri profileUri, Boolean isStandardProfileUriNotFromUser)
      at System.Windows.Media.ColorContext..ctor(PixelFormat pixelFormat)
      at System.Windows.Media.Imaging.BitmapSource.CreateCachedBitmap(BitmapFrame frame,
        BitmapSourceSafeMILHandle wicSource, BitmapCreateOptions createOptions, BitmapCacheOption
        cacheOption, BitmapPalette palette)
      at System.Windows.Media.Imaging.BitmapFrameDecode.FinalizeCreation()
      at System.Windows.Media.Imaging.BitmapFrameDecode..ctor(Int32 frameNumber,
        BitmapSourceSafeMILHandle sourceHandle, BitmapCreateOptions createOptions,
        BitmapCacheOption cacheOption, BitmapDecoder decoder)
      at System.Windows.Media.Imaging.BitmapDecoder.SetupFrames(BitmapDecoder decoder,
        ReadOnlyCollection`1 frames)
      at System.Windows.Media.Imaging.BitmapDecoder.get_Frames()
      at System.Windows.Media.Imaging.BitmapFrame.CreateFromUriOrStream(Uri baseUri, Uri uri,
        Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption,
        RequestCachePolicy uriCachePolicy)
      at System.Windows.Media.Imaging.BitmapFrame.Create(Uri bitmapUri, RequestCachePolicy uriCachePolicy)
      at System.Windows.Media.Imaging.BitmapFrame.Create(Uri bitmapUri)

Cause and Workaround

This particular exception was caused by an invalid system colour profile (set in the Advanced tab in Color Management in Control Panel). The user with this problem got an error message when he opened that dialog, but once he reset the device profile to the system default, this COMException stopped being thrown.

Advanced Color Management dialog

Note that the exception message (“An invalid character was found”) is completely unrelated to the actual problem; the error handling logic in ColorContextHelper has a bug.

FileFormatException

Sample Call Stack

    System.IO.FileFormatException: The image format is unrecognized.
     ---> System.Runtime.InteropServices.COMException (0x88982F07): Exception from HRESULT: 0x88982F07
      --- End of inner exception stack trace ---
      at System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri,
        Stream stream, BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable,
        Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream,
        SafeFileHandle& safeFilehandle)
      at System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri,
        Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption,
        RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
      at System.Windows.Media.Imaging.BitmapImage.FinalizeCreation()
      at System.Windows.Media.Imaging.BitmapImage.EndInit()

Cause and Workaround

This can be caused by trying to load a file that isn’t an image. It can also be caused by loading an image from a Stream that is not at the origin. To work around this bug, see my previous blog post and the sample RebasedStream source code.

InvalidOperationException

Sample Call Stack

    System.InvalidOperationException: Object must be initialized before operation can be performed.
     ---> System.Runtime.InteropServices.COMException (0x88982F0C): Exception from HRESULT: 0x88982F0C
      --- End of inner exception stack trace ---
      at System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri, Stream stream,
        BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable,
        Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream,
        SafeFileHandle& safeFilehandle)
      at System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri,
        Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption,
        RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
      at System.Windows.Media.Imaging.BitmapFrame.CreateFromUriOrStream(Uri baseUri, Uri uri,
        Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption,
        RequestCachePolicy uriCachePolicy)
      at System.Windows.Media.Imaging.BitmapFrame.Create(Uri bitmapUri,
        BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy)
      at System.Windows.Media.Imaging.BitmapFrame.Create(Uri bitmapUri, BitmapCreateOptions createOptions,
        BitmapCacheOption cacheOption)

Cause and Workaround

The underlying error code represents WINCODEC_ERR_NOTINITIALIZED, but the exact cause is unclear. In our experience, this error is thrown on multiple systems when opening the same image file, so it appears to be image-related, not installation-related. As for NotSupportedException below, re-saving or re-encoding the image in a different format may help.

NotSupportedException

Sample Call Stack

    System.NotSupportedException: No imaging component suitable to complete this operation was found.
     ---> System.Runtime.InteropServices.COMException (0x88982F50): Exception from HRESULT: 0x88982F50
      --- End of inner exception stack trace ---
      at System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri,
        Stream stream, BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable,
        Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream,
        SafeFileHandle& safeFilehandle)
      at System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri,
        Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption,
        RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
      at System.Windows.Media.Imaging.BitmapFrame.CreateFromUriOrStream(Uri baseUri, Uri uri,
        Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption,
        RequestCachePolicy uriCachePolicy)
      at System.Windows.Media.Imaging.BitmapFrame.Create(Uri bitmapUri, RequestCachePolicy uriCachePolicy)
      at System.Windows.Media.Imaging.BitmapFrame.Create(Uri bitmapUri)

Cause and Workaround

This error is typically due to bad metadata in the image. Curiously, we see this error the most often on Windows 7 (and a Vista system may load the same image just fine!); maybe this is due to WIC changes in Windows 7. For images we control, opening and saving them again in Paint.NET (or some other image editing program) overwrites the bad metadata and allows WPF/WIC to load the image.

An alternate suggestion (from SwimmingPool.net) is to recreate some WIC registry keys that may be missing.

OutOfMemoryException

Cause and Workaround

If there is already memory pressure on the system (e.g., from other components in your application), and the image being loaded is very large, there may not be enough virtual address space for WIC/WPF to allocate the storage it needs to decode the bitmap. (And, sometimes, both native and managed buffers are required, which doubles memory usage!)

Setting BitmapImage.DecodePixelWidth or BitmapImage.DecodePixelHeight (to something smaller than the actual size) can dramatically reduce memory usage and allow the image to be loaded. This is especially useful if your application only needs to show a thumbnail in the UI; it’s also much more efficient than loading the original image and scaling it in XAML.

IOException / UnauthorizedAccessException

Sample Call Stack

    System.IO.IOException: Cannot locate resource 'images/icon.png'.
      at MS.Internal.AppModel.ResourcePart.GetStreamCore(FileMode mode, FileAccess access)
      at System.IO.Packaging.PackagePart.GetStream(FileMode mode, FileAccess access)
      at System.IO.Packaging.PackWebResponse.CachedResponse.GetResponseStream()
      at System.IO.Packaging.PackWebResponse.GetResponseStream()
      at System.IO.Packaging.PackWebResponse.get_ContentType()
      at System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri,
        Stream stream, BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable,
        Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream,
        SafeFileHandle& safeFilehandle)
      at System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri,
        Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption,
        RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
      at System.Windows.Media.Imaging.BitmapImage.FinalizeCreation()
      at System.Windows.Media.Imaging.BitmapImage.EndInit()
      at System.Windows.Media.Imaging.BitmapImage..ctor(Uri uriSource, RequestCachePolicy uriCachePolicy)
      at System.Windows.Media.Imaging.BitmapImage..ctor(Uri uriSource)

Cause and Workaround

If you’re loading an image from a file: URI, any normal filesystem-related exceptions that come from opening local files could be thrown. Or, if you’re using pack: URIs, an exception will be thrown if there’s a typo in the URI or the named resource is missing.

###

Summary

The BitmapImage and BitmapFrame creation functions can throw a wide variety of exception types–the list above may very well not be exhaustive (and the documentation provides no information on what else may be thrown). Since these exceptions can depend on many environmental factors (client OS, file permissions, memory pressure, etc.), code that loads bitmaps needs to anticipate failure when loading any image and gracefully handle this situation.

Posted by Bradley Grainger on July 31, 2010