`
pcajax
  • 浏览: 2200430 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

IE浏览器整页截屏程序

 
阅读更多

最近项目中涉及到浏览器整页截屏的功能,有点复杂,研究了一天,终于在IE浏览器下实现,至于其他浏览器,以后再研究。

所谓整页截屏,就是说把整个页面全部截进去,包括通过滚动才能看到的部分。

在网上搜了一下,大家用的都是同一种办法:通过滚动页面,截取每一屏的图片,然后再合并成一张整的图片。

方法是好的,悲催的是,没有一个代码是能正常运行的,相信很多人都有同感!没办法,自己动手,丰衣足食。

我需要用.NET来实现。分析一下,主要有以下几个技术点:

1、如何取得浏览器对象。首先要确定IE版本,我用的是IE8浏览器,对象结构和IE6、IE7有点区别。这个可以通过Win32API中的FindWindow函数来实现。

2、对指定控件截屏。这个可以通过Win32API中的PrintWindow函数来实现,这个函数有一个优点:即使浏览器被其它窗口挡住,也可以正常截屏。但是,如果浏览器窗口最小化了,那就漆黑一片了。。。

3、合并图片。这个用GDI+可以很方便地实现。在内存中创建一个大的画布,然后将图片从上至下依次画上去即可。

开始动手。

首先,创建一个Console应用程序(用Form程序也没关系)。

(1)添加对System.Drawing和System.Windows.Forms的引用。

(2)添加对两个COM组件的引用:SHDocVw、MSHTML,并设置属性“嵌入互操作类型”为False(这个很重要,否则无法接下来的程序无法编译通过)。

(3)将程序入口Main方法标记为[STAThread](这个也很重要,否则接下来的程序会运行失败)。

然后,加入Win32API类,该类对几个重要的API进行了封装,接下来我们会用到这些API。代码如下:

复制代码
using System;
using System.Runtime.InteropServices;

namespace IECapture
{
    /// <summary>
    /// Win32API封装类。
    /// </summary>
    internal static class Win32API
    {
        //User32
        [DllImport("User32.dll")]
        public static extern int FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);
        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowDC(IntPtr hWnd);
        [DllImport("User32.dll")]
        public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, int nFlags);

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

        public struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }
    }
}
复制代码

最后,加入主程序。代码逻辑如下:

(1)获取当前IE浏览器对象。

(2)获取浏览器核心控件的矩形区域,计算整个页面一共有多少屏。

(3)通过滚动窗口的方式,对每一屏的页面进行截屏。

(4)将所有图片合并为一张整的图片。

主程序的源代码如下:

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;

namespace IECapture
{
    class Program
    {
        //必须指定COM线程模型为单线程
        [STAThread]
        static void Main(string[] args)
        {
            //获取浏览器对象
            SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindowsClass();
            var webBrowser = shellWindows.Cast<SHDocVw.WebBrowser>().FirstOrDefault(c => c.Name == "Windows Internet Explorer");
            if (webBrowser == null)
            {
                Console.WriteLine("当前未打开任何IE浏览器");
                Console.ReadLine();
                return;
            }

            //查找浏览器核心控件
            IntPtr childHandle1 = Win32API.FindWindowEx(new IntPtr(webBrowser.HWND), IntPtr.Zero, "Frame Tab", IntPtr.Zero);
            IntPtr childHandle2 = Win32API.FindWindowEx(childHandle1, IntPtr.Zero, "TabWindowClass", IntPtr.Zero);
            IntPtr childHandle3 = Win32API.FindWindowEx(childHandle2, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
            IntPtr childHandle4 = Win32API.FindWindowEx(childHandle3, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
            if (childHandle4 == IntPtr.Zero)
            {
                Console.WriteLine("当前未打开任何IE浏览器");
                Console.ReadLine();
                return;
            }

            //获取浏览器核心控件的矩形区域
            Win32API.RECT rc = new Win32API.RECT();
            Win32API.GetWindowRect(childHandle4, ref rc);
            int pageHeight = rc.bottom - rc.top;

            //获取HTML文档对象
            mshtml.IHTMLDocument2 htmlDoc = (mshtml.IHTMLDocument2)webBrowser.Document;

            //计算总共有多少页,以及最后一页的高度
            int pageCount = htmlDoc.body.offsetHeight / pageHeight;
            int lastPageHeight = htmlDoc.body.offsetHeight % pageHeight;
            if (lastPageHeight > 0) pageCount++;
            int scrollBarWidth = pageCount > 1 ? SystemInformation.VerticalScrollBarWidth : 0;

            //图片列表,用于放置每一屏的截图
            List<Image> pageImages = new List<Image>();

            //一页一页地滚动截图
            htmlDoc.parentWindow.scrollTo(0, 0);
            for (int pageIndex = 0; pageIndex < pageCount; pageIndex++)
            {
                using (Image image = CaptureWindow(childHandle4))
                {
                    //去掉边框,以及垂直滚动条的宽度
                    Rectangle innerRect = new Rectangle(2, 2, image.Width - scrollBarWidth - 4, image.Height - 4);
                    if (pageCount > 1 && pageIndex == pageCount - 1 && lastPageHeight > 0)
                        innerRect = new Rectangle(2, pageHeight - lastPageHeight + 2, image.Width - scrollBarWidth - 4, lastPageHeight - 4);

                    pageImages.Add(GetImageByRect(image, innerRect));
                }
                htmlDoc.parentWindow.scrollBy(0, pageHeight);
            }

            //拼接所有图片
            Image fullImage = MergeImages(pageImages);
            if (fullImage == null)
            {
                Console.WriteLine("截屏失败,未获得任何图片");
                Console.ReadLine();
                return;
            }

            //将截屏图片保存到指定目录
            try
            {
                string fileName = @"c:\IE整屏截图.png";
                fullImage.Save(fileName);
                Console.WriteLine("截屏成功,图片位置:" + fileName);
            }
            finally
            {
                fullImage.Dispose();
            }

            Console.ReadLine();
        }

        /// <summary>
        /// 合并图片。
        /// </summary>
        /// <param name="imageList">图片列表。</param>
        /// <returns>合并后的图片。</returns>
        static Image MergeImages(List<Image> imageList)
        {
            if (imageList == null || imageList.Count == 0) return null;
            if (imageList.Count == 1) return imageList[0];

            int pageWidth = imageList[0].Width;
            int totalPageHeight = imageList.Sum(c => c.Height);

            Bitmap fullImage = new Bitmap(pageWidth, totalPageHeight);
            using (Graphics g = Graphics.FromImage(fullImage))
            {
                int y = 0;
                for (int i = 0; i < imageList.Count; i++)
                {
                    g.DrawImageUnscaled(imageList[i], 0, y, imageList[i].Width, imageList[i].Height);
                    y += imageList[i].Height;
                    imageList[i].Dispose();//释放图片资源
                }
            }
            return fullImage;
        }

        /// <summary>
        /// 获取图片的指定区域。
        /// </summary>
        /// <param name="image">原始图片。</param>
        /// <param name="rect">目标区域。</param>
        /// <returns></returns>
        static Image GetImageByRect(Image image, Rectangle rect)
        {
            if (image == null || rect.IsEmpty) return image;

            Bitmap bitmap = new Bitmap(rect.Width, rect.Height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.DrawImage(image, 0, 0, rect, GraphicsUnit.Pixel);
            }
            return bitmap;
        }

        /// <summary>
        /// 为指定窗口或控件截屏。
        /// </summary>
        /// <param name="hWnd">句柄。</param>
        /// <returns>截屏图片。</returns>
        static Image CaptureWindow(IntPtr hWnd)
        {
            IntPtr hscrdc = Win32API.GetWindowDC(hWnd);
            if (hscrdc == IntPtr.Zero) return null;

            Win32API.RECT windowRect = new Win32API.RECT();
            Win32API.GetWindowRect(hWnd, ref windowRect);
            int width = windowRect.right - windowRect.left;
            int height = windowRect.bottom - windowRect.top;

            IntPtr hbitmap = Win32API.CreateCompatibleBitmap(hscrdc, width, height);
            IntPtr hmemdc = Win32API.CreateCompatibleDC(hscrdc);
            Win32API.SelectObject(hmemdc, hbitmap);
            Win32API.PrintWindow(hWnd, hmemdc, 0);

            Image bmp = Image.FromHbitmap(hbitmap);
            Win32API.DeleteDC(hscrdc);
            Win32API.DeleteDC(hmemdc);

            return bmp;
        }
    }
}
复制代码


【总结】

要想写一个好的整页截屏程序,还是很困难的。就拿本文的程序来说,就存在以下几点不足之处:

(1)仅在IE8浏览器上测试通过,无法在FireFox、Chrome上运行。即使同是IE家族的IE6、IE7、IE9,我也不敢保证能正常运行,各位同学可以测试一下,并尝试修改,欢迎交流。

(2)如果有浮动DIV随着页面一起滚动,在每一屏上都会被截屏。

(3)未考虑水平滚动条的影响。

(4)未考虑在多线程环境下的应用。

最后附上一个cnblogs.com首页的截屏,看看效果:)

分类: 实用程序
分享到:
评论

相关推荐

    IE浏览器完整截图工具

    总的来说,"IE浏览器完整截图工具"是一个结合了用户友好性和开发灵活性的实用程序,不仅提供了便捷的截图服务,还为编程爱好者和开发者提供了学习和研究的机会。通过深入理解其工作原理和源代码,我们可以进一步提升...

    网页整页截屏

    总之,"网页整页截屏"技术解决了传统截图工具无法捕获长网页的痛点,"WebShot网站整页截图工具.exe"等应用程序提供了方便快捷的解决方案,让用户可以轻松处理各种网页截图需求。随着网页内容的日益丰富和多样化,整...

    微信小程序——小程序页面生成器(截图+源码).zip

    微信小程序——小程序页面生成器(截图+源码).zip、 微信小程序——小程序页面生成器(截图+源码).zip 微信小程序——小程序页面生成器(截图+源码).zip 微信小程序——小程序页面生成器(截图+源码).zip 微信小...

    新版IE浏览器源代码

    "新版IE浏览器源代码" 提供了一个深入了解浏览器内部工作原理的机会,特别是对于那些对前端开发、浏览器内核或者系统级编程感兴趣的开发者而言。这个资源可能包含了构建和修改IE浏览器功能的原始代码。 描述中提到...

    IeTester--可设置各个IE浏览器的各个版本,对于开发人员进行Ie浏览器版本兼容性测试时非常有帮助

    **IeTester:全方位的IE浏览器兼容性测试工具** 在互联网应用开发中,尤其是在企业级应用的构建过程中,浏览器兼容性是一项重要的考虑因素。IE(Internet Explorer)浏览器因其历史地位和部分用户群体的存在,尽管...

    vue 使用 html2canvas 截屏并下载图片至本地(重点兼容ie浏览器)

    本文将详细介绍如何在Vue项目中使用HTML2canvas实现截屏并下载图片,同时解决IE浏览器的兼容性问题。 首先,你需要确保已经安装了HTML2canvas。在Node.js环境中,你可以通过npm来安装: ```bash npm install ...

    IE浏览器截图插件-LightShot for

    IE浏览器截图插件-LightShot for Internet Explorer最新版使用说明帮助文件介绍,IE浏览器截图插件LightShot for Internet ExplorerIE浏览器截图工具取代了标准的Windows PrtScr命令并允许您拍摄桌面上或整个屏幕所...

    利用PowerBuilder实现对IE浏览器的调用与控制

    在 Ole_ie 对象的 NavigateComplete2 事件中,你可以处理页面加载完成后的一些逻辑,比如隐藏等待指示器或者执行其他初始化操作。 6. 错误处理与异常捕获 为了确保程序的健壮性,可以在关键操作处加入错误处理代码...

    C#截屏截图程序源程序

    标题中的"C#截屏截图程序源程序"是指一个用C#编写的程序,其主要功能是捕获用户的屏幕内容并保存为图像文件。这种程序在日常工作中非常实用,可以用于快速记录屏幕上的信息或制作教程。 描述中提到"简单的示例,可...

    截图程序c#加源码,貌似qq的截屏程序,可保存成多种图片格式

    截图程序c#加源码截图程序c#加源码,貌似qq的截屏程序,可保存成多种图片格式

    小程序源码 小程序页面生成器 (代码+截图)

    小程序源码 小程序页面生成器 (代码+截图)小程序源码 小程序页面生成器 (代码+截图)小程序源码 小程序页面生成器 (代码+截图)小程序源码 小程序页面生成器 (代码+截图)小程序源码 小程序页面生成器 (代码+截图)小...

    微信小程序源码(含截图)小程序页面生成器1111

    微信小程序源码(含截图)小程序页面生成器1111微信小程序源码(含截图)小程序页面生成器1111微信小程序源码(含截图)小程序页面生成器1111微信小程序源码(含截图)小程序页面生成器1111微信小程序源码(含截图)...

    IE浏览器测试器

    "IE浏览器测试器"就是专为解决这个问题而设计的工具,它主要用于检测和调试网页在不同版本的Internet Explorer(IE)浏览器中的表现。 IE浏览器测试器的核心功能在于模拟多个版本的IE环境,以便开发者可以直观地...

    最实用IE浏览器工具栏

    【IE浏览器工具栏详解】 IE浏览器工具栏是专为Internet Explorer设计的一款实用插件,它扩展了浏览器的功能,为用户提供了一系列便捷的操作选项,使浏览网页、管理书签、搜索信息等任务变得更加高效。这款工具栏在...

    网页保存图片并下载到本地 兼容IE浏览器

    然而,为了兼容IE浏览器,我们需要处理两个关键问题:一是IE对Blob和Data URL的支持有限,二是IE可能不支持Promise。我们可以使用FileSaver.js库来解决下载问题,同时用es6-promise来处理Promise。 首先,引入这两...

    labview截图程序_LABVIEW界面_labview截图_labview截屏_labview截图_labview截屏

    “labview截图”和“labview截屏”标签强调了该程序的特定功能,即屏幕捕获。在LabVIEW中,实现截图通常需要编写VI(Virtual Instrument),使用内置的函数库,如“屏幕快照”函数,来捕获屏幕上的任何部分或整个...

    win下实现IE网页截屏

    首先,`iesnap`是一个用于截取IE浏览器页面的实用程序。在提供的文件列表中,我们看到了`iesnap.exe`,这就是iesnap工具的可执行文件。这个工具能够捕获IE浏览器窗口的当前显示内容,并将其保存为图像文件,通常为....

    自动控制网页截屏程序C#

    综上所述,"自动控制网页截屏程序C#"涉及了C#编程、IE浏览器控制、WebBrowser控件的使用、网页截屏技术、图像处理、文件管理和异常处理等多个方面,是将软件工程与Web交互能力相结合的一个实例。

    微信小程序demo:页面框架(源代码+截图)

    微信小程序demo:页面框架(源代码+截图)微信小程序demo:页面框架(源代码+截图)微信小程序demo:页面框架(源代码+截图)微信小程序demo:页面框架(源代码+截图)微信小程序demo:页面框架(源代码+截图)微信小程序demo...

    C#编写的IE浏览器

    在本项目中,我们探讨的是使用C#编写的IE浏览器,这是一个基于`WebBrowser`控件实现的功能。`WebBrowser`控件是.NET Framework提供的一种强大工具,允许开发者在他们的应用程序中嵌入网页浏览功能,其工作原理类似于...

Global site tag (gtag.js) - Google Analytics