如何获取已安装BitmapEncoders / Decoders的列表(WPF世界)?

时间:2020-03-05 18:40:28  来源:igfitidea点击:

在WindowsForms世界中,我们可以通过以下方式获取可用的图像编码器/解码器的列表:

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

我的问题是,是否有一种方法可以做一些与WPF世界类似的事情,从而使我可以获得可用的列表。

System.Windows.Media.Imaging.BitmapDecoder / BitmapEncoder

解决方案

回答

希望有人会纠正我,如果我错了,但是我认为WPF中没有类似的东西。但是希望这是许多技术进步使我们习惯做事的方式过时的情况之一。就像"我如何上弦电子表吗?"

据我了解,在System.Drawing中需要ImageCodecInfo.GetImageDecoders()的原因与System.Drawing本身的糊涂性质有关:System.Drawing是围绕GDI +的托管包装,它是围绕GDI +的一部分的非托管包装Win32 API。因此,可能有原因会在Windows中没有.NET固有了解的情况下安装新的编解码器。从GetImageDecoders()返回的只是一串字符串,这些字符串通常传递回System.Drawing / GDI +,并用于查找和配置用于读取/保存图像的适当DLL。

另一方面,在WPF中,标准的编码器和解码器内置在框架中,并且,如果我没有记错的话,请不要依赖任何不能保证作为框架一部分安装的内容。以下类继承自BitmapEncoder,并且可与WPF一起使用:BmpBitmapEncoder,GifBitmapEncoder,JpegBitmapEncoder,PngBitmapEncoder,TiffBitmapEncoder,WmpBitmapEncoder。有用于所有相同格式的BitmapDecoder,以及IconBitmapDecoder和LateBoundBitmapDecoder。

我们可能正在处理一个我没有想到的情况,但是在我看来,如果我们必须使用从BitmapEncoder继承但不包含在WPF中的类,则可能是我们自己安装的自定义类与应用程序。

希望这可以帮助。如果我缺少图片的必要部分,请告诉我。

回答

我们必须喜欢.NET反射。我曾在WPF团队工作过,无法想出什么更好的方法。以下代码在我的计算机上生成此列表:

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

代码中有注释,用于在其中添加其他程序集(例如,如果我们支持插件)。另外,我们将要过滤解码器列表以将其删除:

System.Windows.Media.Imaging.LateBoundBitmapDecoder

可以使用构造函数模式匹配进行更复杂的过滤,但是我不想编写它。 :-)

我们现在要做的就是实例化编码器和解码器以使用它们。同样,通过获取编码器解码器的CodecInfo属性,可以获得更好的名称。该类将为我们提供易于理解的名称,包括其他事实。

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;
                    }
                }
            }
        }
    }
}