調用Control.DrawToBitmap(Bitmap) 方法是很容易得到控件的圖形的。 但是bitmap是柵格化圖形。 柵格化圖形有很多缺點,比如文件體積比較大、 放大後失真、 不易編輯等等。 這裡教你如何導出一個 控件的矢量圖。
I. Windows MetaFile.
windows MetaFile 是windows 下面的一種矢量圖形格式。 事實上WMF 只是記錄下來的一串GDI 命令 ,重新調用一次這一串GDI命令就可以重建之前記錄下來的圖像。而大部分windows應用程序的界面都是用 GDI繪制的,所以理論上都可以導出他們界面的矢量圖。 詳細去看: http://en.wikipedia.org/wiki/Windows_Metafile
II. 繪圖表面 ( drawing surfaces )
用GDI+繪圖的時候,基本上你會把圖形繪制到 屏幕上的窗體、傳到打印機的打印文檔、內存裡的圖像 文件等等。 這些叫做繪圖表面。
首先我們來創建一個新的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();
Graphics g2 = Graphics.FromImage(mf);
調用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); }
到這裡已經得到了這個控件的矢量圖了。下面附加一段代碼把這個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; }
運行這段代碼以後, 就可以吧控件的矢量圖粘貼到圖像編輯軟件上面了(CorelDraw, Word, Excel等) 。 可以無限放大不失真, 還能夠編輯裡面的文本哦!