Как отобразить метафайл Windows?

Мне нужно отобразить метафайл Windows (EMF) с помощью WPF, как я могу это сделать?

Редактировать:

Я бы оставил изображение на векторной основе.

2 ответа

Решение

Взгляните на стороннюю библиотеку Ab2d.ReadWmf.

Обновление № 1: Обзор

Во-первых, в этом сообщении говорится, что Microsoft не намерена поддерживать файлы EMF в WPF. Это не значит, что это невозможно, просто они их не поддержат.

Глядя на страницу Википедии о формате WMF/EMF, я вижу, что она описывает EMF как:

По сути, файл WMF хранит список вызовов функций, которые должны быть выполнены на уровне интерфейса графического устройства Windows (GDI) для отображения изображения на экране. Поскольку некоторые функции GDI принимают указатели на функции обратного вызова для обработки ошибок, файл WMF может ошибочно включать исполняемый код.

Если вы много работали с WPF, вы знаете, что WPF принципиально отличается от GDI. Краткий обзор доступен здесь. Это означает, что вам нужно прочитать файл EMF и преобразовать вызовы GDI в вызовы WPF. Вот ветка, где обсуждают процесс. Это звучит как большая работа для меня.

К счастью, Microsoft предоставляет интерфейс для чтения в метафайлах Windows. Взгляните на эту ветку для примера и документации, доступной здесь, но это поможет вам только на полпути, так как это не WPF Visual. На данный момент я думаю, что самым простым решением было бы создать элемент управления WinForms в вашем приложении WPF и разместить его внутри элемента управления WindowsFormsHost.

Обновление № 2: Пример кода

Чтобы отобразить файл EMF в приложении WPF:

  1. Создать WinForms UserControl
  2. Загрузите файл EMF в объект MetaFile и нарисуйте его в обработчике OnPaint.
  3. Добавить ссылку на библиотеку WindowsFormsIntegration
  4. Разместите свой элемент управления WinForms внутри элемента WindowsFormsHost

UserControl:

public partial class UserControl1 : UserControl
{
     private Metafile metafile1;

     public UserControl1()
     {
         InitializeComponent();
         metafile1 = new Metafile(@"C:\logo2.emf");
     }

     protected override void OnPaint(PaintEventArgs e)
     {
         e.Graphics.DrawImage(metafile1, 0, 0);
     }
}

XAML:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:app="clr-namespace:WpfApplication1" 
    Title="MainWindow" Height="200" Width="200">

     <Grid>
         <WindowsFormsHost>
             <app:UserControl1/>
         </WindowsFormsHost>
     </Grid>
 </Window>

Вот служебная функция, которая загружает файл EMF и преобразует его в WPF BitmapSource:

public static class Emfutilities
{
        public static BitmapSource ToBitmapSource(string path)
        {
            using (System.Drawing.Imaging.Metafile emf = new System.Drawing.Imaging.Metafile(path))
            using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(emf.Width, emf.Height))
            {
                bmp.SetResolution(emf.HorizontalResolution, emf.VerticalResolution);
                using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
                {
                    g.DrawImage(emf, 0, 0);
                    return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                }
            }
        }
}

Вы просто используете это так:

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            // img is of Image type for example
            img.Source = Emfutilities.ToBitmapSource("SampleMetafile.emf");
        }
    }

}

Недостатком является то, что вам нужно будет ссылаться на System.Drawing.dll (GDI+) в вашем приложении WPF, но это не должно быть большой проблемой.

Другие вопросы по тегам