WebBrowser.DrawToBitmap() or other methods?

匿名 (未验证) 提交于 2019-12-03 01:23:02

问题:

I am trying to capture the content of the WebBrowser control. DrawToBitmap() would work perfectly, but it is not supported in documentation for the WebBrowser control. I have been trying to find another way to capture the contents of the WebBrowser control and save them to a local image file.

Does anyone have any workarounds or other methods to save the contents of the WebBrowser control to a local image file?

回答1:

The Control.DrawToBitmap doesn't always work so I resorted to the following native API calls that provide more consistent results:

The Utilities class. Call Utilities.CaptureWindow(Control.Handle) to capture a specific control:

public static class Utilities {     public static Image CaptureScreen()     {         return CaptureWindow(User32.GetDesktopWindow());     }      public static Image CaptureWindow(IntPtr handle)     {          IntPtr hdcSrc = User32.GetWindowDC(handle);          RECT windowRect = new RECT();         User32.GetWindowRect(handle, ref windowRect);          int width = windowRect.right - windowRect.left;         int height = windowRect.bottom - windowRect.top;          IntPtr hdcDest = Gdi32.CreateCompatibleDC(hdcSrc);         IntPtr hBitmap = Gdi32.CreateCompatibleBitmap(hdcSrc, width, height);          IntPtr hOld = Gdi32.SelectObject(hdcDest, hBitmap);         Gdi32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, ApiConstants.SRCCOPY);         Gdi32.SelectObject(hdcDest, hOld);         Gdi32.DeleteDC(hdcDest);         User32.ReleaseDC(handle, hdcSrc);          Image image = Image.FromHbitmap(hBitmap);         Gdi32.DeleteObject(hBitmap);          return image;     } } 

The Gdi32 class:

public class Gdi32 {     [DllImport("gdi32.dll")]     public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjectSource, int nXSrc, int nYSrc, int dwRop);     [DllImport("gdi32.dll")]     public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth, int nHeight);     [DllImport("gdi32.dll")]     public static extern IntPtr CreateCompatibleDC(IntPtr hDC);     [DllImport("gdi32.dll")]     public static extern bool DeleteDC(IntPtr hDC);     [DllImport("gdi32.dll")]     public static extern bool DeleteObject(IntPtr hObject);     [DllImport("gdi32.dll")]     public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); } 

The User32 class:

public static class User32 {     [DllImport("user32.dll")]     public static extern IntPtr GetDesktopWindow();     [DllImport("user32.dll")]     public static extern IntPtr GetWindowDC(IntPtr hWnd);     [DllImport("user32.dll")]     public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);     [DllImport("user32.dll")]     public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC); } 

The constants used:

    public const int SRCCOPY = 13369376; 

The structs used:

[StructLayout(LayoutKind.Sequential)] public struct RECT {     public int left;     public int top;     public int right;     public int bottom; } 

A friendly Control extension method:

public static class ControlExtensions {     public static Image DrawToImage(this Control control)     {         return Utilities.CaptureWindow(control.Handle);     } } 

This is a code snippet from my CC.Utilities project and I specifically wrote it to take screenshots from the WebBrowser control.



回答2:

The following method can capture the entire window image even if the window is larger than the size of screen. Then it can capture the image of the contents of the page if the window be resized to the webBrowser.Document.OffsetRectangle.Size

class NativeMethods {     [ComImport]     [Guid("0000010D-0000-0000-C000-000000000046")]     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]     interface IViewObject     {         void Draw([MarshalAs(UnmanagedType.U4)] uint dwAspect, int lindex, IntPtr pvAspect, [In] IntPtr ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, [MarshalAs(UnmanagedType.Struct)] ref RECT lprcBounds, [In] IntPtr lprcWBounds, IntPtr pfnContinue, [MarshalAs(UnmanagedType.U4)] uint dwContinue);     }      [StructLayout(LayoutKind.Sequential, Pack = 4)]     struct RECT     {         public int Left;         public int Top;         public int Right;         public int Bottom;     }      public static void GetImage(object obj, Image destination, Color backgroundColor)     {         using(Graphics graphics = Graphics.FromImage(destination))         {             IntPtr deviceContextHandle = IntPtr.Zero;             RECT rectangle = new RECT();              rectangle.Right = destination.Width;             rectangle.Bottom = destination.Height;              graphics.Clear(backgroundColor);              try             {                 deviceContextHandle = graphics.GetHdc();                  IViewObject viewObject = obj as IViewObject;                 viewObject.Draw(1, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, deviceContextHandle, ref rectangle, IntPtr.Zero, IntPtr.Zero, 0);             }             finally             {                 if(deviceContextHandle != IntPtr.Zero)                 {                     graphics.ReleaseHdc(deviceContextHandle);                 }             }         }     } } 

Usage :

Bitmap screenshot = new Bitmap(1024, 768); NativeMethods.GetImage(webBrowser.ActiveXInstance, screenshot, Color.White); 


回答3:

I am using DrawToBitmap (Visual Studio 2008 C#) to capture big images (user signed invoices,content out of the screen). Basically it is working well but I am getting blank images. About 100 employees are using this software, about every 2 weeks I can see one blank image.

I have done a lot of testing and one funny thing I found is: I created a button to generate the image from the webbrowser. Usually is OK but if I click the webbrowser first, then click the create-button, the blank image will appear.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!