Как получить список установленных BitmapEncoders / Decoders (мир WPF)?

В мире WindowsForms вы можете получить список доступных кодировщиков / декодеров изображений с помощью

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

Мой вопрос: есть ли способ сделать что-то аналогичное для мира WPF, которое позволило бы мне получить список доступных

System.Windows.Media.Imaging.BitmapDecoder / BitmapEncoder

Ответов (2)

Надеюсь, кто-нибудь поправит меня, если я ошибаюсь, но я не думаю, что в WPF есть что-то подобное. Но, надеюсь, это один из многих случаев, когда достижения в области технологий сделали устаревшими методы, которые мы привыкли делать. Например, "как завести мои цифровые часы?"

Насколько я понимаю, причина, по которой ImageCodecInfo.GetImageDecoders () необходим в System.Drawing, связана с непонятной природой самого System.Drawing: System.Drawing - это управляемая оболочка для GDI +, которая является неуправляемой оболочкой для части API Win32. Так что может быть причина, по которой новый кодек будет установлен в Windows без ведома .NET. И то, что возвращается из GetImageDecoders (), - это просто набор строк, которые обычно передаются обратно в System.Drawing / GDI + и используются для поиска и настройки соответствующей DLL для чтения / сохранения вашего изображения.

С другой стороны, в WPF стандартные кодировщики и декодеры встроены в фреймворк и, если я не ошибаюсь, не зависят от чего-либо, что не гарантируется для установки как части фреймворка. Следующие классы наследуются от BitmapEncoder и доступны без дополнительных настроек с WPF: BmpBitmapEncoder, GifBitmapEncoder, JpegBitmapEncoder, PngBitmapEncoder, TiffBitmapEncoder, WmpBitmapEncoder. Есть BitmapDecoders для всех тех же форматов, плюс 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;
                    }
                }
            }
        }
    }
}