2010-03-12 27 views
22

Estoy tratando de capturar el contenido del control WebBrowser. DrawToBitmap() funcionaría perfectamente, pero no es compatible con la documentación del control WebBrowser. He estado tratando de encontrar otra forma de capturar los contenidos del control WebBrowser y guardarlos en un archivo de imagen local.WebBrowser.DrawToBitmap() u otros métodos?

¿Alguien tiene alguna solución alternativa u otros métodos para guardar el contenido del control WebBrowser en un archivo de imagen local?

+0

Un q relacionado/a: [Cómo corregir un error de opacidad con DrawToBitmap en WebBrowser Control?] (http://stackoverflow.com/q/21697048/1768303) – Noseratio

+0

[tardía, pero tal vez de interés] (http://stackoverflow.com/questions/24343393/webbrowser-madness?noredirect=1#comment37647172_24343393) - La solución al final es simple y parece ser confiable. – TaW

Respuesta

36

El Control.DrawToBitmap no siempre funciona así que recurrieron a las siguientes llamadas a la API nativas que proporcionan resultados más consistentes:

clase de las utilidades. Llamar Utilities.CaptureWindow (Control.Handle) para capturar un control específico:

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; 
    } 
} 

La clase gdi32:

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); 
} 

La clase User32:

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); 
} 

Las constantes utilizadas:

public const int SRCCOPY = 13369376; 

T Las estructuras que utiliza:

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

Un agradable método de extensión de control:

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

Este es un fragmento de código de mi proyecto CC.Utilities y me escribió específicamente para tomar capturas de pantalla desde el control WebBrowser.

+0

Gracias voy a dar una oportunidad. – Matt

+1

@Matt: Espero que ayude. Había omitido la clase Gdi32 de mi publicación original, pero lo solucioné ahora. –

+1

@Cory Charlton: ¡Funciona genial! Mi única pregunta es decir que tengo una página en el control WebBrowser que se extiende a más de una página. No hay forma de usar esto para agarrar eso? – Matt

0

Estoy usando DrawToBitmap (Visual Studio 2008 C#) para capturar imágenes grandes (facturas firmadas por el usuario, contenido fuera de la pantalla). Básicamente está funcionando bien, pero obtengo imágenes en blanco. Cerca de 100 empleados están usando este software, aproximadamente cada 2 semanas puedo ver una imagen en blanco.

He hecho muchas pruebas y una cosa graciosa que encontré es: Creé un botón para generar la imagen desde el navegador web. Por lo general, está bien, pero si hago clic primero en el navegador web y hago clic en el botón Crear, aparecerá la imagen en blanco.

+3

La imagen en blanco es una queja que se ve mucho. La propia documentación de Microsoft sobre el método le dice a la gente que no la use, pero todos siguen haciéndolo porque este es un método muy necesario. He estado buscando una solución sobre esto por alrededor de una semana. Debo confiar en que IE está haciendo el renderizado, así que no puedo usar otras soluciones. Sería interesante ver si hay un mejor método para obtener resultados consistentes del método DrawToBitmap. –

+0

Solo una sugerencia, algo que tendré que hacer yo mismo si no puedo resolverlo de otra manera, deberías poder determinar que la imagen está en blanco, no solo cada píxel será blanco, sino que si todos son blancos, entonces un poco de matemáticas debería mostrar que solo hay un píxel de color en la imagen. –

3

El siguiente método puede capturar toda la imagen de la ventana, incluso si la ventana es más grande que el tamaño de la pantalla. A continuación, puede capturar la imagen de los contenidos de la página, si la ventana se cambia de tamaño para el 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); 
       } 
      } 
     } 
    } 
} 

Uso:

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

Está por encima de la capacidad de tomar capturas de pantalla si la página html tiene pergaminos. Intenté usar @Cory Charlton pero funciona, pero solo la pantalla visible no toda la página – Sandeep

Cuestiones relacionadas