调用Control.DrawToBitmap(Bitmap) 方法是很容易得到控件的图形的。 但是bitmap是栅格化图形。栅格化图形有很多缺点,比如文件体积比较大、 放大后失真、 不易编辑等等。 这里将给出导出一个控件的矢量图的过程。
一、两个概念
Windows MetaFile
windows MetaFile 是windows 下面的一种矢量图形格式。 事实上WMF 只是记录下来的一串GDI 命令,重新调用一次这一串GDI命令就可以重建之前记录下来的图像。而大部分windows应用程序的界面都是用GDI绘制的,所以理论上都可以导出他们 界面的矢量图。 详细去看:绘图表面 ( drawing surfaces )
用GDI+绘图的时候,基本上你会把图形绘制到 屏幕上的窗体、传到打印机的打印文档、内存里的图像文件等等。 这些叫做绘图表面。
二、导出的基本过程
2.1 首先创建一个新的EMF文件
1 2 3 4 5 6 | 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()函数中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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复制到剪切板上面去.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | [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; } |
参考文章
1. 。