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

发布于 2024-07-04 21:05:16 字数 284 浏览 8 评论 0原文

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

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

我的问题是,有没有一种方法可以为 WPF 世界做类似的事情,让我获得可用的图像编码器/解码器列表

System.Windows.Media.Imaging.BitmapDecoder / BitmapEncoder

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苯莒 2024-07-11 21:05:19

您一定会喜欢 .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;
                    }
                }
            }
        }
    }
}

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;
                    }
                }
            }
        }
    }
}
北方的韩爷 2024-07-11 21:05:19

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

据我了解,为什么 ImageCodecInfo.GetImageDecoders() 在 System.Drawing 中是必需的,这与 System.Drawing 本身的混乱本质有关:System.Drawing 是 GDI+ 的托管包装器,而 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 中的类,那么您可能需要安装您自己的自定义类与您的申请。

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文