通过WebBrowser+PrintWindow实现了网页截图,内部使用了拼接的方式可以实现保存完整网页,也可保存第一屏,不过这种方式的潜在 bug是窗体不可最小化,否则为黑屏,而且也没有找到webbrowser以内存方式构建截屏和合理方式,无法正确render后通过PrintWindow 方式截获图片,这可能也是通过PrintWindow截取的不完美的地方吧(请大家指点更完美的方式吧),下面看代码吧:
简易的界面:
截取163.com的图片如下:
首屏
全页面(注:页面被上传控制缩小了,保存的图片是完全比例大小的)
整个项目Demo:http://cid-9601b7b7f2063d42.skydrive.live.com/self.aspx/Code/WebBrowserCapture.rar
作者:FreezeSoul
出处:http://hi.baidu.com/freezesoul
欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。
Link:http://hi.baidu.com/freezesoul/blog/item/124db9a18cb3ba824710649d.html
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using System.Drawing.Imaging;
using SHDocVw;
using mshtml;
using System.Net;
namespace WebBrowserCapture
{
public class WebBrowserCapture
{
#region DLLImport
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/, IntPtr next /*HWND*/, string sClassName, IntPtr sWindowTitle);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
private static extern IntPtr GetWindow(IntPtr hWnd, int uCmd);
[DllImport("user32.dll")]
private static extern void GetClassName(int h, StringBuilder s, int nMaxCount);
[DllImport("user32.dll")]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
public const int GW_CHILD = 5;
public const int GW_HWNDNEXT = 2;
#endregion
public System.Windows.Forms.WebBrowser m_browser;
//我还抓你第一屏幕
public bool firstScreen = true;
//测试网络连通状况
private bool TestInternet(string url)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(new Uri(url));
req.AllowAutoRedirect = true;
req.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 1.1.4322)";
req.Referer = "http://www.google.com";
req.ContentType = "text/html";
req.AllowWriteStreamBuffering = true;
req.AutomaticDecompression = DecompressionMethods.GZip;
req.Method = "GET";
req.Proxy = null;
req.ReadWriteTimeout = 20;
HttpStatusCode status;
using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
{
status = resp.StatusCode;
}
if (status == HttpStatusCode.OK || status == HttpStatusCode.Moved)
{
return true;
}
return false;
}
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
public void GetPageImage(string url, string path)
{
//Test Is OK
if (TestInternet(url))
{
bool flag = firstScreen;
m_browser.Navigate(url);
//浏览器Dom载入完毕
while (m_browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
mshtml.IHTMLDocument2 myDoc = (mshtml.IHTMLDocument2)m_browser.Document.DomDocument;
//处理由于webbrowser上、左边框阴影带来的拼接bug
int URLExtraHeight = 3;
int URLExtraLeft = 3;
(myDoc as HTMLDocumentClass).documentElement.setAttribute("scroll", "yes", 0);
//document完整高度
int heightsize = (int)(myDoc as HTMLDocumentClass).documentElement.getAttribute("scrollHeight", 0);
int widthsize = (int)(myDoc as HTMLDocumentClass).documentElement.getAttribute("scrollWidth", 0);
////Get Screen Height
int screenHeight = (int)(myDoc as HTMLDocumentClass).documentElement.getAttribute("clientHeight", 0);
int screenWidth = (int)(myDoc as HTMLDocumentClass).documentElement.getAttribute("clientWidth", 0);
IntPtr myIntptr = (IntPtr)m_browser.Handle;
//寻找IE对象句柄
IntPtr wbHandle = FindWindowEx(myIntptr, IntPtr.Zero, "Shell Embedding", null);
wbHandle = FindWindowEx(wbHandle, IntPtr.Zero, "Shell DocObject View", null);
wbHandle = FindWindowEx(wbHandle, IntPtr.Zero, "Internet Explorer_Server", null);
IntPtr hwnd = wbHandle;
Bitmap bm = new Bitmap(screenWidth, screenHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
Bitmap bm2 = new Bitmap(widthsize, heightsize, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
Graphics g = null;
Graphics g2 = Graphics.FromImage(bm2);
//切割用的临时对象
Bitmap tempbm = null;
Graphics tempg = null;
IntPtr hdc;
Image screenfrag = null;
Image firstScreenfrag = null;
#region 拼接
int brwTop = 0;
int brwLeft = 0;
int myPage = 0;
//Get Screen Height (for bottom up screen drawing)
while ((myPage * screenHeight) < heightsize)
{
(myDoc as HTMLDocumentClass).documentElement.setAttribute("scrollTop", (screenHeight - 5) * myPage, 0);
++myPage;
}
//Rollback the page count by one
--myPage;
int myPageWidth = 0;
//screenWidth+ URLExtraLeft
while ((myPageWidth * screenWidth) < widthsize)
{
(myDoc as HTMLDocumentClass).documentElement.setAttribute("scrollLeft", (screenWidth - 5) * myPageWidth, 0);
brwLeft = (int)(myDoc as HTMLDocumentClass).documentElement.getAttribute("scrollLeft", 0);
for (int i = myPage; i >= 0; --i)
{
//Shoot visible window
g = Graphics.FromImage(bm);
hdc = g.GetHdc();
(myDoc as HTMLDocumentClass).documentElement.setAttribute("scrollTop", (screenHeight - 5) * i, 0);
brwTop = (int)(myDoc as HTMLDocumentClass).documentElement.getAttribute("scrollTop", 0);
PrintWindow(hwnd, hdc, 0);
g.ReleaseHdc(hdc);
g.Flush();
screenfrag = Image.FromHbitmap(bm.GetHbitmap());
//切除URLExtraLeft、URLExtraHeight长度的webbrowser带来的bug
tempbm = new Bitmap(screenWidth - URLExtraLeft, screenHeight - URLExtraHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
tempg = Graphics.FromImage(tempbm);
tempg.DrawImage(screenfrag, -URLExtraLeft, -URLExtraHeight);
//拼接到g2
g2.DrawImage(tempbm, brwLeft + URLExtraLeft, brwTop + URLExtraLeft);
}
//是否得到第一屏
if (flag)
{
firstScreenfrag = (Image)tempbm.Clone();
flag = false;
}
++myPageWidth;
}
int finalWidth = (int)widthsize;
int finalHeight = (int)heightsize;
Bitmap finalImage = new Bitmap(finalWidth, finalHeight, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
Graphics gFinal = Graphics.FromImage((Image)finalImage);
gFinal.DrawImage(bm2, 0, 0, finalWidth, finalHeight);
#endregion
//Get Time Stamp
DateTime myTime = DateTime.Now;
String format = "yyyy_MM_dd_hh_mm_ss";
//Create Directory to save image to.
Directory.CreateDirectory(path);
//Write Image.
EncoderParameters eps = new EncoderParameters(1);
long myQuality = Convert.ToInt64(100);
eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, myQuality);
ImageCodecInfo ici = GetEncoderInfo("image/jpeg");
//保存
finalImage.Save(path + @"\Img_" + myTime.ToString(format) + ".jpg", ici, eps);
//保存第一屏
if (firstScreen)
{
firstScreenfrag.Save(path + @"\Img_FirstScreen_" + myTime.ToString(format) + ".jpg", ici, eps);
firstScreenfrag.Dispose();
}
//Process.Start("explorer.exe", path);
#region Clean
//Clean Up.
myDoc.close();
myDoc = null;
g.Dispose();
g2.Dispose();
gFinal.Dispose();
bm.Dispose();
bm2.Dispose();
finalImage.Dispose();
tempbm.Dispose();
tempg.Dispose();
#endregion
}
}
}
}
简易的界面:
截取163.com的图片如下:
首屏
全页面(注:页面被上传控制缩小了,保存的图片是完全比例大小的)
整个项目Demo:http://cid-9601b7b7f2063d42.skydrive.live.com/self.aspx/Code/WebBrowserCapture.rar
作者:FreezeSoul
出处:http://hi.baidu.com/freezesoul
欢迎转载,但请保留此段声明,且在文章页面明显位置给出原文连接。
Link:http://hi.baidu.com/freezesoul/blog/item/124db9a18cb3ba824710649d.html