C# 导出一个控件的矢量图
调用Control.DrawToBitmap(Bitmap) 方法是很容易得到控件的图形的。 但是bitmap是栅格化图形。栅格化图形有很多缺点,比如文件体积比较大、 放大后失真、 不易编辑等等。 这里将给出导出一个控件的矢量图的过程。
一、两个概念
Windows MetaFile
windows MetaFile 是windows 下面的一种矢量图形格式。 事实上WMF 只是记录下来的一串GDI
命令,重新调用一次这一串GDI命令就可以重建之前记录下来的图像。而大部分windows应用程序的界面都是用GDI绘制的,所以理论上都可以导出他们
界面的矢量图。 详细去看:http://en.wikipedia.org/wiki/Windows_Metafile
绘图表面 ( drawing surfaces )
用GDI+绘图的时候,基本上你会把图形绘制到 屏幕上的窗体、传到打印机的打印文档、内存里的图像文件等等。 这些叫做绘图表面。
二、导出的基本过程
2.1 首先创建一个新的EMF文件
System.Drawing.Imaging.Metafile mf;
Graphics g1 = control.CreateGraphics();
IntPtr hdc = g1.GetHdc();
mf = new Metafile(hdc, new Rectangle(0, 0, control.Width, control.Height), MetafileFrameUnit.Pixel, EmfType.EmfOnly);
g1.ReleaseHdc(hdc);
g1.Dispose();
2.2 将控件上的内容打印到Graphics 对象上
调用WinApi把控件打印到此Graphics 对象上面。这个Graphics对象会作为参数传递给下面一级一级的子控件的OnPaint()函数中。
const int WM_PRINT = 0x0317; const int PRF_CHECKVISIBLE = 0x00000001,
PRF_NONCLIENT = 0x00000002,
PRF_CLIENT = 0x00000004,
PRF_ERASEBKGND = 0x00000008,
PRF_CHILDREN = 0x00000010;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, int lParam); public static void DrawControl(Control control, Graphics g)
{
if (!control.Created)
control.CreateControl(); IntPtr hDc = g.GetHdc();
SendMessage(new HandleRef(control, control.Handle), WM_PRINT, (int)hDc,(int)(PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT));
g.ReleaseHdc(hDc);
}
2.3 将EMF复制到剪切板上
到这里已经得到了这个控件的矢量图了。下面附加一段代码把这个EMF复制到剪切板上面去.
[DllImport("user32.dll")]
static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll")]
static extern bool EmptyClipboard();
[DllImport("user32.dll")]
static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
[DllImport("user32.dll")]
static extern bool CloseClipboard();
[DllImport("gdi32.dll")]
static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, IntPtr hNULL);
[DllImport("gdi32.dll")]
static extern bool DeleteEnhMetaFile(IntPtr hemf);
static public bool PutEnhMetafileOnClipboard(IntPtr hWnd, Metafile mf)
{
bool bResult = false;
IntPtr hEMF, hEMF2;
hEMF = mf.GetHenhmetafile(); // invalidates mf
if (!hEMF.Equals(new IntPtr(0)))
{
hEMF2 = CopyEnhMetaFile(hEMF, new IntPtr(0));
if (!hEMF2.Equals(new IntPtr(0)))
{
if (OpenClipboard(hWnd))
{
if (EmptyClipboard())
{
IntPtr hRes = SetClipboardData(14 /*CF_ENHMETAFILE*/, hEMF2);
bResult = hRes.Equals(hEMF2);
CloseClipboard();
}
}
} DeleteEnhMetaFile(hEMF);
} return bResult;
}
参考文章
C# 导出一个控件的矢量图的更多相关文章
- UIButton 一个控件 实现 左图标右文本的效果
UIButton 一个控件 实现 左图标右文本的效果 如图,我们要实现一个 左边图标右边文本的效果,一般 可以考虑是 UIImageView + UILabel 不过,其实一个UIButton就可以搞 ...
- [C#]Winform下回车或Tab键自动切换下一个控件焦点
满足用户体验,在数据录入时,能在输入完一个信息后通过回车或Tab键自动的切换到下一个控件(字段). 在界面控件设计时,默认可以通过设置控件的TabIndex来实现.但在布局调整时或者是对输入的内容有选 ...
- ExtJs5_继承自定义一个控件
Extjs的开发都可以遵循OOP的原则,其对类的封装也很完善了.自定义一个控件最简单的办法就是继承一个已有的控件.根据上一节的需要,我做了一个Button的子类.首先根据目录结构,在app目录下建立一 ...
- android 让一个控件按钮居于底部的几种方法
android 让一个控件按钮居于底部的几种方法1.采用linearlayout布局:android:layout_height="0dp" <!-- 这里不能设置fill_ ...
- 6、手把手教你Extjs5(六)继承自定义一个控件
Extjs的开发都可以遵循OOP的原则,其对类的封装也很完善了.自定义一个控件最简单的办法就是继承一个已有的控件.根据上一节的需要,我做了一个Button的子类.首先根据目录结构,在app目录下建立一 ...
- iOS开发之通过代码自定义一个控件
关于控件的继承关系(面试重点): (1)所有的控件都继承自UIView. (2)能监听事件的都是先继承自UIControl,UIControl再继承自UIView.比如UIButton. (3)能整体 ...
- C# 给一个控件去掉焦点
给一个控件去掉焦点(如选中控件按钮button时,按钮出现方框显示):例如给form这个窗体中的button按钮去焦点1.首先在form这个窗体中拖一个label按钮,去文字,设置背景为透明: 2.然 ...
- VC++:制作一个控件注册的小工具
在平时的工作中,时常需要注册与反注册ActiveX控件,有时需要判断控件是否已经注册. 所以通过查找资料编写了一个控件注册的小工具,欢迎学习交流,不当之处请多多交流. 先直接上图: 主要代码: ...
- IOS 当一个控件被添加到父控件中会调用(didMoveToSuperview)
/** * 当一个控件被添加到父控件中就会调用 */ - (void)didMoveToSuperview { if (self.group.opened) { self.nameView.image ...
随机推荐
- intent传递参数
来建第一个Activity:MyIntent [mw_shl_code=java,true]public class MyIntent extends Activity { ...
- 学了C语言,如何利用cURL写一个程序验证某个网址的有效性?
在<C程序设计伴侣>以及这几篇关于cURL的文章中,我们介绍了如何利用cURL写一个下载程序,从网络下载文件.可是当我们在用这个程序下载文件时,又遇到了新问题:如果这个网址是无效的,那么我 ...
- JavaWeb笔记——三大组件之监听器
1 JavaWeb监听器概述 在JavaWeb被监听的事件源为:ServletContext.HttpSession.ServletRequest,即三大域对象. l 监听域对象“创建”与“销毁”的 ...
- jboss5优化
1.调整JVM在bin.bat或bin/run.cfg文件里. -Xms设置堆的最小值:-Xmx设置堆的最大值:-XX:Newsize= 设置年轻代的最小值:-XX:MaxNewsize=设置年轻代的 ...
- hive报错 Another instance of Derby may have already booted the database
刚装好hive后,启动之后showtables;等正常,退出之后再进入,就发现会报错 Caused by: ERROR XSDB6: Another instance ofDerbymay have ...
- 在ump系统的那半个多月-jqGrid
2012.04统一监控平台项目打酱油的日子 系统介绍: 目标,致力于服务于公司内部的所有系统,对所有接入监控的系统进行监控,包括系统监控,URL存活监控,端口存活监控,方法监控等. 作为打酱油的我,没 ...
- poj-3255-Roadblocks-路径可重复次短路
题目: Roadblocks Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 7075 Accepted: 2629 Descri ...
- hdu - 1728逃离迷宫 && hdu - 1175 连连看 (普通bfs)
http://acm.hdu.edu.cn/showproblem.php?pid=1728 这两道题花了一下午的时候调试,因为以前做过类似的题,但是判断方向的方法是错的,一直没发现啊,真无语. 每个 ...
- HDU 4651 Partition(整数拆分)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4651 题意:给出n.求其整数拆分的方案数. i64 f[N]; void init(){ f[0 ...
- Hibernate 的<generator class="native"></generator>的不同属性含义
1) assigned主键由外部程序负责生成,无需Hibernate参与. 2) hilo通过hi/lo 算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态. 3) seqhilo与hil ...