tags:

views:

752

answers:

2

In WindowsForms world you can get a list of available image encoders/decoders with

System.Drawing.ImageCodecInfo.GetImageDecoders() / GetImageEncoders()

My question is, is there a way to do something analogous for the WPF world that would allow me to get a list of available

System.Windows.Media.Imaging.BitmapDecoder / BitmapEncoder
A: 

Hopefully someone will correct me if I'm wrong, but I don't think there's anything like that in WPF. But hopefully this is one of the many cases where advances in the technology have rendered obsolete the way we're used to doing things. Like "how do I wind my digital watch?"

To my understanding, the reason why ImageCodecInfo.GetImageDecoders() is necessary in System.Drawing has to do with the kludgy nature of System.Drawing itself: System.Drawing is a managed wrapper around GDI+, which is an unmanaged wrapper around a portion of the Win32 API. So there might be a reason why a new codec would be installed in Windows without .NET inherently knowing about it. And what's returned from GetImageDecoders() is just a bunch of strings that are typically passed back into System.Drawing/GDI+, and used to find and configure the appropriate DLL for reading/saving your image.

On the other hand, in WPF, the standard encoders and decoders are built into the framework, and, if I'm not mistaken, don't depend on anything that that isn't guaranteed to be installed as part of the framework. The following classes inherit from BitmapEncoder and are available out-of-the-box with WPF: BmpBitmapEncoder, GifBitmapEncoder, JpegBitmapEncoder, PngBitmapEncoder, TiffBitmapEncoder, WmpBitmapEncoder. There are BitmapDecoders for all the same formats, plus IconBitmapDecoder and LateBoundBitmapDecoder.

You may be dealing with a case I'm not imagining, but it seems to me that if you're having to use a class that inherits from BitmapEncoder but wasn't included with WPF, it's probably your own custom class that you would install with your application.

Hope this helps. If I'm missing a necessary part of the picture, please let me know.

kcrumley
+1  A: 

You've got to love .NET reflection. I worked on the WPF team and can't quite think of anything better off the top of my head. The following code produces this list on my machine:

Bitmap Encoders:
System.Windows.Media.Imaging.BmpBitmapEncoder
System.Windows.Media.Imaging.GifBitmapEncoder
System.Windows.Media.Imaging.JpegBitmapEncoder
System.Windows.Media.Imaging.PngBitmapEncoder
System.Windows.Media.Imaging.TiffBitmapEncoder
System.Windows.Media.Imaging.WmpBitmapEncoder

Bitmap Decoders:
System.Windows.Media.Imaging.BmpBitmapDecoder
System.Windows.Media.Imaging.GifBitmapDecoder
System.Windows.Media.Imaging.IconBitmapDecoder
System.Windows.Media.Imaging.LateBoundBitmapDecoder
System.Windows.Media.Imaging.JpegBitmapDecoder
System.Windows.Media.Imaging.PngBitmapDecoder
System.Windows.Media.Imaging.TiffBitmapDecoder
System.Windows.Media.Imaging.WmpBitmapDecoder

There is a comment in the code where to add additional assemblies (if you support plugins for example). Also, you will want to filter the decoder list to remove:

System.Windows.Media.Imaging.LateBoundBitmapDecoder

More sophisticated filtering using constructor pattern matching is possible, but I don't feel like writing it. :-)

All you need to do now is instantiate the encoders and decoders to use them. Also, you can get better names by retrieving the CodecInfo property of the encoder decoders. This class will give you human readable names among other factoids.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Media.Imaging;

namespace Codecs {
    class Program {
        static void Main(string[] args) {
            Console.WriteLine("Bitmap Encoders:");
            AllEncoderTypes.ToList().ForEach(t => Console.WriteLine(t.FullName));
            Console.WriteLine("\nBitmap Decoders:");
            AllDecoderTypes.ToList().ForEach(t => Console.WriteLine(t.FullName));
            Console.ReadKey();
        }

        static IEnumerable<Type> AllEncoderTypes {
            get {
                return AllSubclassesOf(typeof(BitmapEncoder));
            }
        }

        static IEnumerable<Type> AllDecoderTypes {
            get {
                return AllSubclassesOf(typeof(BitmapDecoder));
            }
        }

        static IEnumerable<Type> AllSubclassesOf(Type type) {
            var r = new Reflector();
            // Add additional assemblies here
            return r.AllSubclassesOf(type);
        }
    }

    class Reflector {
        List<Assembly> assemblies = new List<Assembly> { 
            typeof(BitmapDecoder).Assembly
        };
        public IEnumerable<Type> AllSubclassesOf(Type super) {
            foreach (var a in assemblies) {
                foreach (var t in a.GetExportedTypes()) {
                    if (t.IsSubclassOf(super)) {
                        yield return t;
                    }
                }
            }
        }
    }
}
Frank Krueger