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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15023/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-01 08:49:24  来源:igfitidea点击:

How to get list of installed BitmapEncoders/Decoders (the WPF world)?

提问by

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

在 WindowsForms 世界中,您可以获得可用图像编码器/解码器的列表

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

我的问题是,有没有办法为 WPF 世界做一些类似的事情,让我获得可用的列表

System.Windows.Media.Imaging.BitmapDecoder / BitmapEncoder

回答by Kevin Crumley

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?"

如果我错了,希望有人能纠正我,但我认为 WPF 中没有类似的东西。但希望这是技术进步使我们习惯做事的方式过时的众多案例之一。就像“我如何为我的数字手表上弦?”

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.

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

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.

另一方面,在 WPF 中,标准编码器和解码器内置于框架中,如果我没记错的话,不要依赖任何不能保证安装为框架一部分的东西。以下类继承自 BitmapEncoder,可在 WPF 中开箱即用:BmpBitmapEncoder、GifBitmapEncoder、JpegBitmapEncoder、PngBitmapEncoder、TiffBitmapEncoder、WmpBitmapEncoder。所有相同格式都有 BitmapDecoder,还有 IconBitmapDecoder 和 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.

您可能正在处理我无法想象的情况,但在我看来,如果您必须使用从 BitmapEncoder 继承但未包含在 WPF 中的类,那么您可能会安装自己的自定义类与您的应用程序。

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

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

回答by Frank Krueger

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:

您必须喜欢 .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

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 CodecInfoproperty of the encoder decoders. This class will give you human readable names among other factoids.

您现在需要做的就是实例化编码器和解码器以使用它们。此外,您可以通过检索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;
                    }
                }
            }
        }
    }
}