C#网页截图类WebCapture(增强版)

上次使用WebBrowser控件的DrawToBitmap方法来保存页面截图,效果不是很好,百度后看了一篇非常棒的文章,效果非常好,下边示例下怎么实现。先定义三个重要的类NativeMethods、UnsafeNativeMethods和Snapshot:

NativeMethods.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;

namespace WindowsApplication1
{
    /// <summary>
    /// 从 .Net 2.0 的 System.Windows.Forms.Dll 库提取
    /// 版权所有:微软公司
    /// </summary>
    internal static class NativeMethods
    {
        [StructLayout(LayoutKind.Sequential)]
        public sealed class tagDVTARGETDEVICE
        {
            [MarshalAs(UnmanagedType.U4)]
            public int tdSize;
            [MarshalAs(UnmanagedType.U2)]
            public short tdDriverNameOffset;
            [MarshalAs(UnmanagedType.U2)]
            public short tdDeviceNameOffset;
            [MarshalAs(UnmanagedType.U2)]
            public short tdPortNameOffset;
            [MarshalAs(UnmanagedType.U2)]
            public short tdExtDevmodeOffset;
        }

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

            public COMRECT(Rectangle r)
            {
                this.left = r.X;
                this.top = r.Y;
                this.right = r.Right;
                this.bottom = r.Bottom;
            }

            public COMRECT(int left, int top, int right, int bottom)
            {
                this.left = left;
                this.top = top;
                this.right = right;
                this.bottom = bottom;
            }

            public static NativeMethods.COMRECT FromXYWH(int x, int y, int width, int height)
            {
                return new NativeMethods.COMRECT(x, y, x + width, y + height);
            }

            public override string ToString()
            {
                return string.Concat(new object[] { "Left = ", this.left, " Top ", this.top, " Right = ", this.right, " Bottom = ", this.bottom });
            }

        }

        [StructLayout(LayoutKind.Sequential)]
        public sealed class tagLOGPALETTE
        {
            [MarshalAs(UnmanagedType.U2)]
            public short palVersion;
            [MarshalAs(UnmanagedType.U2)]
            public short palNumEntries;
        }
    }
}

UnsafeNativeMethods.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace WindowsApplication1
{
    /// <summary>
    /// 从 .Net 2.0 的 System.Windows.Forms.Dll 库提取
    /// 版权所有:微软公司
    /// </summary>
    [SuppressUnmanagedCodeSecurity]
    internal static class UnsafeNativeMethods
    {
        public static Guid IID_IViewObject = new Guid("{0000010d-0000-0000-C000-000000000046}");

        [ComImport, Guid("0000010d-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IViewObject
        {
            [PreserveSig]
            int Draw([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [In] NativeMethods.tagDVTARGETDEVICE ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, [In] NativeMethods.COMRECT lprcBounds, [In] NativeMethods.COMRECT lprcWBounds, IntPtr pfnContinue, [In] int dwContinue);
            [PreserveSig]
            int GetColorSet([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [In] NativeMethods.tagDVTARGETDEVICE ptd, IntPtr hicTargetDev, [Out] NativeMethods.tagLOGPALETTE ppColorSet);
            [PreserveSig]
            int Freeze([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [Out] IntPtr pdwFreeze);
            [PreserveSig]
            int Unfreeze([In, MarshalAs(UnmanagedType.U4)] int dwFreeze);
            void SetAdvise([In, MarshalAs(UnmanagedType.U4)] int aspects, [In, MarshalAs(UnmanagedType.U4)] int advf, [In, MarshalAs(UnmanagedType.Interface)] IAdviseSink pAdvSink);
            void GetAdvise([In, Out, MarshalAs(UnmanagedType.LPArray)] int[] paspects, [In, Out, MarshalAs(UnmanagedType.LPArray)] int[] advf, [In, Out, MarshalAs(UnmanagedType.LPArray)] IAdviseSink[] pAdvSink);
        }
    }
}

Snapshot.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsApplication1
{
    /// <summary>
    /// ActiveX 组件快照类
    /// AcitveX 必须实现 IViewObject 接口
    ///
    /// 作者:随飞
    /// http://chinasf.cnblogs.com
    /// chinasf@hotmail.com
    /// </summary>
    public class Snapshot
    {
        /// <summary>
        /// 取快照
        /// </summary>
        /// <param name="pUnknown">Com 对象</param>
        /// <param name="bmpRect">图象大小</param>
        /// <returns></returns>
        public Bitmap TakeSnapshot(object pUnknown, Rectangle bmpRect)
        {
            if (pUnknown == null)
                return null;
            //必须为com对象
            if (!Marshal.IsComObject(pUnknown))
                return null;
            //IViewObject 接口
            UnsafeNativeMethods.IViewObject ViewObject = null;
            IntPtr pViewObject = IntPtr.Zero;
            //内存图
            Bitmap pPicture = new Bitmap(bmpRect.Width, bmpRect.Height);
            Graphics hDrawDC = Graphics.FromImage(pPicture);
            //获取接口
            object hret = Marshal.QueryInterface(Marshal.GetIUnknownForObject(pUnknown),
                ref UnsafeNativeMethods.IID_IViewObject, out pViewObject);
            try
            {
                ViewObject = Marshal.GetTypedObjectForIUnknown(pViewObject, typeof(UnsafeNativeMethods.IViewObject)) as UnsafeNativeMethods.IViewObject;
                //调用Draw方法
                ViewObject.Draw((int)DVASPECT.DVASPECT_CONTENT,
                    -1,
                    IntPtr.Zero,
                    null,
                    IntPtr.Zero,
                    hDrawDC.GetHdc(),
                    new NativeMethods.COMRECT(bmpRect),
                    null,
                    IntPtr.Zero,
                    0);
                Marshal.Release(pViewObject);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw ex;
            }
            //释放
            hDrawDC.Dispose();
            return pPicture;
        }
    }
}

使用语法如下:

Snapshot snap = new Snapshot();
using (Bitmap bitmap = snap.TakeSnapshot(webBrowser.ActiveXInstance, new Rectangle(0, 0, picWidth, picHeight)))
{
    bitmap.Save(savepath, picType);
}

好了,修改下上次的WebCapture类:

WebCapture.cs:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.IO;

namespace WindowsApplication1
{
    public class WebCapture
    {
        #region 字段、属性
        private int width = 0;
        private int height = 0;
        private string url;
        private WebBrowser browser = new WebBrowser();

        /// <summary>
        /// 属性:图片宽
        /// </summary>
        public int Width { get { return width; } }
        /// <summary>
        /// 属性:图片高
        /// </summary>
        public int Height { get { return height; } }
        /// <summary>
        /// 属性:Url
        /// </summary>
        public string Url { get { return url; } }
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        public WebCapture()
        {
            this.url = "http://www.mzwu.com/";
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="url">Url</param>
        public WebCapture(string url)
        {
            this.url = url;
        }
        #endregion

        /// <summary>
        /// 保存图片
        /// </summary>
        /// <param name="destpath">保存路径</param>
        /// <returns></returns>
        public void Save(string destpath)
        {
            Save(this.url, destpath, this.width, this.height);
        }

        /// <summary>
        /// 保存图片
        /// </summary>
        /// <param name="url">Url</param>
        /// <param name="destpath">保存路径</param>
        /// <returns></returns>
        public void Save(string url, string destpath)
        {
            Save(url, destpath, this.width, this.height);
        }

        /// <summary>
        /// 保存图片
        /// </summary>
        /// <param name="url">Url</param>
        /// <param name="destpath">保存路径</param>
        /// <param name="width">图片宽</param>
        /// <param name="height">图片高</param>
        /// <returns></returns>
        /// <remarks>width,height为0时获取完整大小</remarks>
        public void Save(string url, string destpath, int width, int height)
        {
            ImageFormat picType;

            //图片格式
            switch (Path.GetExtension(destpath).ToLower())
            {
                case ".gif":
                    picType = System.Drawing.Imaging.ImageFormat.Gif;
                    break;
                case ".jpg":
                case ".jpeg":
                    picType = System.Drawing.Imaging.ImageFormat.Jpeg;
                    break;
                case ".png":
                    picType = System.Drawing.Imaging.ImageFormat.Png;
                    break;
                case ".bmp":
                    picType = System.Drawing.Imaging.ImageFormat.Bmp;
                    break;
                default:
                    picType = System.Drawing.Imaging.ImageFormat.Jpeg;
                    break;
            }

            //抓取图片
            InitComobject(url);//初始化窗体
            int scrollWidth = this.browser.Document.Body.ScrollRectangle.Width;
            int scrollHeight = this.browser.Document.Body.ScrollRectangle.Height;
            this.browser.Width = scrollWidth;
            this.browser.Height = scrollHeight;
            if (width == 0) width = scrollWidth;
            if (height == 0) height = scrollHeight;

            //核心语句
            Snapshot snap = new Snapshot();
            using (Bitmap bitmap = snap.TakeSnapshot(this.browser.ActiveXInstance, new Rectangle(0, 0, width, height)))
            {
                bitmap.Save(destpath, picType);
            }

            browser.Dispose();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="url"></param>
        protected void InitComobject(string url)
        {
            this.browser.ScriptErrorsSuppressed = false;
            this.browser.ScrollBarsEnabled = false;
            this.browser.Navigate(url);

            //因为没有窗体,所以必须如此
            while (this.browser.ReadyState != WebBrowserReadyState.Complete)
                System.Windows.Forms.Application.DoEvents();
            this.browser.Stop();
            if (this.browser.ActiveXInstance == null)
                throw new Exception("实例不能为空");
        }

    }
}

使用示例:

new WebCapture().Save("http://www.163.com/", @"C:\163.jpg");

参考文章:

[1].http://www.cnblogs.com/Chinasf/archive/2006/12/25/603294.html

评论: 0 | 引用: 0 | 查看次数: 6576
发表评论
登录后再发表评论!