关于WebBrowser.DrawToBitmap

概述

最近在Winform的开发中用到了Flash动态图表FusionCharts Free,这是个开源的flash组件。商业版可以使用FusionCharts V3,免费版本的是FusionCharts Free v2.2。下载地址:http://www.fusioncharts.com/free/download/。大家可以去看看,效果还是非常炫的。商业版比免费版能够提供更多的图表,导出pdf,image,csv等功能,当然免费版这些功能大家就别指望了。

一般flash组件都是以flash的形式在网页中呈现的。因此如果要在WinformFlash图表个人认为有两种方案。1. 利用WebBrowser控件,将url执行包含这个flash的网页。2.利用Flash的com组件shockwave Flash。第一种方式实现方式比较简单,第二种个人认为最好的是有Flex的组件作为容器,这样可以根据传递进来的参数显示不同的图表。

因为免费版没有导出pdf,image,csv等功能,所以只好自己去写了。而且是加载到WebBrowser控件,因此我对WebBrowser进行了扩展。目前常用的Flash图表都可以展示,导出pdf,image,excel,等格式。

相关图片预览

    先上几张图片给大家一个直观点的认识

  

1.导出的图片


                图2.导出的pdf

遇到的问题

1.          如标题所说的关于WebBrowser.DrawToBitmap问题,因为此控件是没有这个方法的,但是你用了也不会出错,但是问题就来了,有时候可以导出图片有时候又不能,加载的网页里面不存在Ajax内容之类的。网上有不少对此问题的解决办法,但是所见之处基本都是错误的。一种普遍的做法如下:

代码
public void WriteBmp(string bmpPath)
        {
            
while (webbrowser.ReadyState != WebBrowserReadyState.Complete)
            {
                Application.DoEvents();
            }
            System.Drawing.Rectangle r 
= new System.Drawing.Rectangle(Point.Empty,
                
new Size(int.Parse(webbrowser.Document.Body.GetAttribute("scrollWidth")), int.Parse(webbrowser.Document.Body.GetAttribute("scrollHeight"))));
            Bitmap bmp 
= new Bitmap(r.Width, r.Height);
            webbrowser.DrawToBitmap(bmp, r);
            bmp.Save(bmpPath);
            bmp.Dispose();
        }

   结果就导致了时而可以时而不可以的问题。对这个问题,国外的站点有不错的解决方法:
  1.http://bytes.com/topic/c-sharp/answers/605264-taking-screenshot-webbrowser-tab
  
2. http://efreedom.com/Question/1-2434156/WebBrowser-DrawToBitmap-Methods

    根据上面的方法,我将代码列出来给大家供参考,以上两种方法我用过了效果都很棒(上面的截图就是这样生成的):

代码
[DllImport("user32.dll")]
        
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);

        
public void WriteBmp(string bmpPath)
        {

            
int screenWidth = webbrowser.Document.Body.ScrollRectangle.Width;
            
int screenHeight = webbrowser.Document.Body.ScrollRectangle.Height;

            IntPtr myIntptr 
= webbrowser.Handle;
            
int hwndInt = myIntptr.ToInt32();
            IntPtr hwnd 
= myIntptr;

            
// Set hdc to the bitmap

            Bitmap bm 
= new Bitmap(screenWidth, screenHeight);
            Graphics g 
= Graphics.FromImage(bm);
            IntPtr hdc 
= g.GetHdc();

            
// Snapshot the WebBrowser

            
bool result = PrintWindow(hwnd, hdc, 0);
            g.ReleaseHdc(hdc);
            g.Flush();

            
// Save the bitmap, if successful

            
if (result == true)
                bm.Save(bmpPath);
        }

 第2种方式:

代码
public static class ApiConstants
    {
        
public const int SRCCOPY = 13369376;
    }

    
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, 
00, width, height, hdcSrc, 00, ApiConstants.SRCCOPY);
            Gdi32.SelectObject(hdcDest, hOld);
            Gdi32.DeleteDC(hdcDest);
            User32.ReleaseDC(handle, hdcSrc);

            Image image 
= Image.FromHbitmap(hBitmap);
            Gdi32.DeleteObject(hBitmap);

            
return image;
        }
    }

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

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

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

    
//如果是.net的扩展方法,如果你.net库版本比较高就去掉注释
    
//public static class ControlExtensions
    
//{
    
//    public static Image DrawToImage(this Control control)
    
//    {
    
//        return Utilities.CaptureWindow(control.Handle);
    
//    }
    
//}

 2.关于导出pdf的问题,大家可以去下载itextsharp开源的组件,学习文档可以参考

  1. http://itextpdf.com/book/examples.phpjava版的

  2. http://www.cnblogs.com/islands/archive/2008/06/27/1231288.html

小结

         以上是自己在Flash动态图表开发中一点小小的心得,写出来和大家一起分享,本文的目的给遇到类似问题的朋友一种解决方案,在你搜索完google,再搜索baidu发现都不能解决你问题的时候,或许此文能给你点帮助。

作者:Jackhuclan
出处:http://jackhuclan.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/jackhuclan/p/1909301.html