如何显示Windows元文件?

11

我需要使用WPF显示一个Windows元文件(EMF),该如何操作?

编辑:

我希望保持图像的矢量化。


请参考这个问题 - Clemens
2个回答

15

请查看第三方库Ab2d.ReadWmf

更新 #1: 概述

首先,这篇文章称微软不打算在WPF中支持EMF文件。这并不意味着无法完成,只是微软将不提供支持。

查看关于WMF / EMF格式的维基百科页面,我发现它将EMF描述为:

实质上,WMF文件存储了必须向Windows GDI(图形设备接口)层发出的函数调用列表,在屏幕上显示图像。由于某些GDI函数接受指向回调函数的指针以进行错误处理,因此WMF文件可能会错误地包含可执行代码。

如果您经常使用WPF,您就知道WPF与GDI根本不同。可以在此处获得快速概述:此处。这意味着您需要读取EMF文件并将GDI调用转换为WPF调用。这里讨论了该过程。对我来说,这听起来是很多工作。

幸运的是,微软提供了一个接口来读取Windows图元文件。请参阅此处的帖子以获取示例和此处的文档,但这只能让您完成一半,因为它不是WPF可视化对象。此时,我认为最简单的解决方案是在WPF应用程序中创建一个WinForms控件,并将其托管在WindowsFormsHost控件内部。

更新 #2:代码示例

要在WPF应用程序中显示EMF文件:

  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>

请在您的答案中更新重要的示例或参考资料,通用链接并不有用。 - gliderkite
+1 对于你最后一次更新,能否展示如何创建表单解决方案以显示 EMF? - gliderkite

12

这里有一个实用函数,可以加载 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应用程序中,但这不应该是一个大问题。


2
它可以正常工作+1。但EMF是用于矢量图形的,而BitmapSource(如您所知)是光栅图像。我该怎么解决这个问题? - gliderkite
3
在您的问题中没有指定希望保持图像为矢量图。如果需要这样做,您需要将EMF记录转换为纯XAML格式。这是一项艰苦的工作(可能还会占用大量CPU资源),并且并非免费提供 :-) 可以参考Dan Busha的答案获取转换工具。 - Simon Mourier
注意:如果您的解决方案不支持“System.Drawing.Imaging”,则可以使用NuGet包:“System.Drawing.Common”。 - peaceoutside

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接