使用 C# 生成 EMF 矢量图形文件

前言

公众号上有网友询问我如何生成 EMF 文件的问题:

5f7d0227587f40e0211d2ae91a399855.png

本以为非常简单,我快速给出了解决方案:

var bitmap = new Bitmap(640, 480);var g = Graphics.FromImage(bitmap);g.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 100, 100);bitmap.Save("MyIO.emf",ImageFormat.Emf);

结果,网友告诉我,这是错误的:

1a5abdbc2eb63346bb3b133889e7f0a6.png

用编辑器查看文件内容,发现实际生成的是PNG格式文件:

914587265c6a14bcfed28d8f30272f0a.png

这是怎么回事呢?

原因

在官方文档上找到这样一段话:

当使用Save此方法将图形图像另存为Windows元文件格式 (WMF) 或增强的图元文件格式 (EMF) 文件时,生成的文件将改为保存为可移植网络图形 (PNG) 文件。发生此行为是因为.NET Framework的GDI+组件没有可用于将文件另存为 .wmf 或 .emf 文件的编码器。

不理解这样设计的原因,不支持应该抛出异常吧?!

实现

不过还好,从文档上我们也找到了解决方案,那就是使用Metafile类。

可是在实现时,又踩了不少坑。

创建实例失败

按照示例代码,使用文件名创建实例:

var metafile = new Metafile("MyIO.emf");

结果报了个通用异常,完全没有指导意义:

08d01fe7f9064062e93b75fbe5006fb4.png

只好反编译代码查错。

发现,底层实现使用的GdipCreateMetafileFromFileAPI:

public Metafile(string filename)
{Path.GetFullPath(filename);SafeNativeMethods.Gdip.CheckStatus(SafeNativeMethods.Gdip.GdipCreateMetafileFromFile(filename, out IntPtr metafile));SetNativeImage(metafile);
}

342592d83967975baf933a919caaa446.png

也就是说,参数必须是一个已存在的 EMF 文件名

查看其他构造函数的实现,发现传递referenceHdc的构造函数使用的是GdipRecordMetafileFileNameAPI:

public Metafile(string fileName, IntPtr referenceHdc, EmfType type, string? description)
{Path.GetFullPath(fileName);SafeNativeMethods.Gdip.CheckStatus(SafeNativeMethods.Gdip.GdipRecordMetafileFileName(fileName, referenceHdc, type, IntPtr.Zero, MetafileFrameUnit.GdiCompatible, description, out IntPtr metafile));SetNativeImage(metafile);
}

6dc170c1a7e34306a22b853c0b657844.png

也就是说,这个 API 可以创建 EMF 文件。看来可以用。

referenceHdc可以使用Graphics.GetHdc()得到。

于是,实现代码如下:

using (Graphics g1 = Graphics.FromHwnd(IntPtr.Zero))
{using (var metafile = new Metafile("MyIO.emf", g1.GetHdc())){using (Graphics g2 = Graphics.FromImage(metafile)){ g2.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 100, 100);g2.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 200, 200);}}
}

生成的确实是矢量图形文件:

f0e5db2222bd6e1c2a280f4a85d4245a.gif

绘制位置错误

可以明显看到,第一个My IO绘制的位置是错误的,绘制到了左上角,而不是(100, 100)

再次查找构造函数,发现可以传递Rectangle参数:

6bbcf694086bddc19956a95768c11e6c.png

修改实现代码如下:

using (Graphics g1 = Graphics.FromHwnd(IntPtr.Zero))
{using (var metafile = new Metafile("MyIO.emf", g1.GetHdc(), new Rectangle(0, 0, 300, 300), MetafileFrameUnit.Pixel)){using (Graphics g2 = Graphics.FromImage(metafile)){g2.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 100, 100);g2.DrawString("My IO", new Font(FontFamily.GenericSerif, 10), Brushes.Blue, 200, 200);}}
}

这次总算成功了:

0e41c28927ae4b0198a4e8f8478bc985.gif

结论

后来发现,生成的图片实际是375 x 375像素,这应该是因为我的显示属性设置了缩放的原因(375 / 300 = 1.25):

10d195d85c791184fbe659e73e15ee43.png

想了解更多内容,请关注我的个人公众号”My IO“

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/288438.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php register_shutdown_function响应error 配合error_get_last 捕获错误

register_shutdown_function 函数,当我们的脚本执行完成或意外死掉导致PHP执行即将关闭时,我们的这个函数将会 被调用&#xff0c;可以配合 error_get_last 使用&#xff0c;代码如下&#xff0c;注释已经解释了代码了&#xff1a; error_get_last 稍后解释 <?php //a bo…

嵌入式开发linux工具,嵌入式Linux开发入门之MfgTool工具的使用

介绍嵌入式linux开发的环境搭建&#xff1a;一、PC端环境搭建2、Ubuntu装好后&#xff0c;在终端安装minicom工具&#xff0c;安装命令&#xff1a;sudo apt-get install minicom注&#xff1a;该工具在后面烧录开发板可以调试使用&#xff0c;对以后的嵌入式程序开发也是不可获…

SQL Server 2005 cmd工具的使用

您可以使用 sqlcmd 实用工具(Microsoft Win32 命令提示实用工具)来运行特殊的 Transact-SQL 语句和脚本。若要以交互方式使用 sqlcmd,或要生成可使用 sqlcmd 来运行的脚本文件,则需要了解 Transact-SQL。通常以下列方式使用 sqlcmd 实用工具: 在 sqlcmd 环境中,以交互的方…

剑指offer之按层打印树节点

1 问题 按层打印树节点&#xff0c;比如我们有树如下 23 5 1 4 2 3 这样打印&#xff1a;2 3 5 1 4 2 3 2 分析 队列&#xff1a;先进后出&#xff0c;这里我们先打印2&#xff0c;然后再打印3和5&#xff0c;我们这里可以使用队列&#xff0c;我们先把2入队…

基于key/value+Hadoop HDFS 设计的存储系统的shell命令接口

对于hadoop HDFS 中的全部命令进行解析&#xff08;当中操作流程是自己的想法有不允许见欢迎大家指正&#xff09; 接口名称 功能 操作流程 get 将文件拷贝到本地文件系统 。假设指定了多个源文件&#xff0c;本地目的端必须是一个文件夹。 &#xff08;1&#xff09;依照…

【足迹C++primer】52、,转换和继承虚函数

转换和继承,虚函数 Understanding conversions between base and derived classes is essential to understanding how object-oriented programming works in C. 理解基类和派生类之间的转换是不可缺少的 理解面向对象编程在。 Like built-in pointers, the smart pointer cla…

python人脸识别训练模型生产_深度学习-人脸识别DFACE模型pytorch训练(二)

首先介绍一下MTCNN的网络结构&#xff0c;MTCNN有三种网络&#xff0c;训练网络的时候需要通过三部分分别进行&#xff0c;每一层网络都依赖前一层网络产生训练数据供当前训练网络&#xff0c;这样也推动了两个网络之间的最小损耗。PnetRnetOnetMTCNN的人脸模型按照以上结构按照…

聊一聊Redis的离线分析

背景 Redis 或许是我们大部分场景都会用到的一个利器&#xff0c;虽然是利器&#xff0c;用的姿势不对的话&#xff0c;终究还是会整出幺蛾子的。比较常见的问题&#xff0c;不外乎内存暴增&#xff0c;慢查询等情况。那么对于内存问题&#xff0c;可以借助redis自带的bigkey分…

C# 实现Winform全屏后不遮挡任务栏,显示任务栏

最近在忙中抽闲&#xff0c;看我的桌面太过死了&#xff0c;不生动&#xff0c;不可爱。。。 然后默默的想写一个动态桌面的一个小东西活泼一下。。。 随后拿起来了N久不碰的C#&#xff08;本人C#渣&#xff0c;不&#xff0c;应该说什么都渣。。。&#xff09; 结果在winfo…

SQL Server 2005登录名,用户名,角色,架构之间的关系

SQL Server 2005对2000进行了很大的改进,而用户关系这部分也变得相当复杂了,很多朋友都对此一知半解!下面,我将把我应用中总结的和大家分享下,先从概念入手,希望对不理解的朋友有点提示。 今天我们要说的包括服务器登录名ServerLogin,服务器角色Server Role,数据库用户…

【模拟】【codeforces】599B Spongebob and Joke

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id282385 就是一个人最开始有一串数a1 a2 ... am 他的熊孩子队友用一组函数f1 f2 ... fn 以及bi fai 把串A换成了串B 现在告诉你B和F&#xff0c;让你把A换回来&#xff0c;能换回来输出A&#xff0c;换回来可能有…

linux磁盘第一个扇区分析,Linux磁盘分区

一、磁盘连接方式与设备文件名的关系计算机常见的磁盘接口有两种&#xff0c;分别是IDE与SATA接口&#xff0c;目前主流接口已经是SATA接口了。一个IDE扁平电缆可以连接两个IDE设备&#xff0c;通常主机又都会提供两个IDE接口&#xff0c;因此最多可以接到四个IDE设备。也就是说…

剑指offer之分行从上到下打印二叉树

1 题目 分行从上到下打印二叉树 23 5 1 4 2 3 我们打印如下 23 51 4 2 3 2 分析 之前这篇博客写了通过队列按层打印剑指offer之按层打印树节点 现在无非就是还要按照条件打印&#xff0c;第一次打印1个&#xff0c;然后第二次打印2个&…

转:char*, char[] ,CString, string的转换

转&#xff1a;char*, char[] ,CString, string的转换 (一) 概述string和CString均是字符串模板类&#xff0c;string为标准模板类&#xff08;STL&#xff09;定义的字符串类&#xff0c;已经纳入C标准之中&#xff1b;CString&#xff08;typedef CStringT > CString&am…

虚拟机VMware安装XP系统错误解决办法

虚拟机给我的编程工作确实带了很多方便&#xff0c;但是虚拟机的一个最大挑战是硬件赶不上&#xff0c;速度太慢了。最近一直在致力于虚拟机上Win7专业版平台上SQL Server 2005Visual Studio 2012系统开发&#xff0c;最初还可以&#xff0c;但是越到后面速度越慢。最后决定重新…

[TP5填坑]关于助手函数input一不小心取不到get值的解决办法

声明&#xff1a;适用于懒人 常规对于这个什么鬼取不到值我也是很绝望的&#xff0c;通常都是看一遍手册就开始写&#xff0c;除非是在没事才跟你认认真真看&#xff0c;所以&#xff0c;我们这类懒人就非常尴尬了&#xff0c;只能动不动查手册。 tp5也出很久了&#xff0c;本…

【Python】猜数小游戏(文件操作)

人生苦短&#xff0c;我用Python 关键词 1.多用户 2.字典记录所有成绩 3.每次游戏轮数&总游戏次数&平均每次游戏需要多少轮 字典Dictionary、列表List、元组Tuple差异化理解 from random import randintname input(请输入你的名字&#xff1a;)#输入玩家名字 #读取文件…

100ms的SQL把服务器搞崩溃了

前言一个项目上线了两个月&#xff0c;除了一些反馈的优化和小Bug之外&#xff0c;项目一切顺利&#xff1b;前期是属于推广阶段&#xff0c;可能使用人员没那么多&#xff0c;当然对于项目部署肯定提前想到并发量了&#xff0c;所以早就把集群安排上&#xff0c;而且还在测试环…

剑指offer之分行从上到下之字行打印二叉树

1 问题 分行从上到下之字行打印二叉树 比如二叉树 23 5 1 4 2 3 3 2 1 5 1 4 2 3 分行从上到下之字行打印二叉树结果如下 2 5 3 1 4 2 3 3 2 4 1 5 1 …

python中sendkeys.sendkeys_python的webbrowser模块和SendKeys模块

今天工作的时候突然遇到个问题&#xff0c;就尝试着按照领导所说要天马行空的想东西&#xff0c;于是那点scrapy的代码逐渐忘了的差不多了&#xff0c;想到用迅雷去下载一些东西&#xff0c;迅雷不知道怎么回事&#xff0c;但知道一点&#xff0c;他监控计算机浏览器&#xff0…