先说一点题外话,将WEB页面渲染成图片有比较好的开源工具,如CutyCapt ,它使用WebKit渲染,兼容多种操作系统,适合于在服务器上作为后台服务运行。
不过,这里说到的是对WebBrowser内的页面进行截图并保存. WebBrowser本质上就是IE内核的浏览器。使用mshtml来渲染页面的话,依赖GDI,所以不可能作为后台服务运行。
获取WebBrowser截屏的方法很多, PrintWindow / IHTMLElementRender / IViewObject。不管使用哪种方法,都需考虑长页面的问题。因为这些方法都只能截屏clientArea区域,也就是说没显示的部分无法截图,必须通过多次截图完成整个页面截图的拼合。
本文使用的是PrintWindow方式,这种方式原理上能够兼容其它所有的浏览器。
首先通过设置ControlSite将浏览器的边框和滚动条隐藏,这样客户区只有WEB页面。
HRESULT FAR EXPORT CCustomControlSite::XDocHostUIHandler::GetHostInfo( DOCHOSTUIINFO* pInfo )
{
METHOD_PROLOGUE(CCustomControlSite, DocHostUIHandler)
pInfo->cbSize = sizeof(DOCHOSTUIINFO);
pInfo->dwFlags = DOCHOSTUIFLAG_DIALOG |
DOCHOSTUIFLAG_DISABLE_HELP_MENU |
DOCHOSTUIFLAG_ACTIVATE_CLIENTHIT_ONLY |
DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8 |
DOCHOSTUIFLAG_NO3DOUTERBORDER |
DOCHOSTUIFLAG_NO3DBORDER |
DOCHOSTUIFLAG_SCROLL_NO |
DOCHOSTUIFLAG_USE_WINDOWLESS_SELECTCONTROL;
pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
return S_OK;
}
然后挂接
document.body.onload事件,保证页面上的图片都加载完成。
void CWebBrowser::OnDocumentComplete( IDispatch *pDisp, VARIANT *URL)
{
CComQIPtr<IWebBrowser2> pWebBrowser2(pDisp);
if( pWebBrowser2 )
{
CComPtr<IDispatch> pDispatch;
if( S_OK == pWebBrowser2->get_Document(&pDispatch) )
{
CComQIPtr<IHTMLDocument2> pDoc2(pDispatch);
if( pDoc2 )
{
BSTR bstrReadyState;
if( S_OK == pDoc2->get_readyState(&bstrReadyState) )
{
if( 0 == _wcsicmp( bstrReadyState, L"complete") )
{
CComPtr<IHTMLWindow2> pWnd2;
if( S_OK == pDoc2->get_parentWindow(&pWnd2) )
{
CComPtr<IHTMLWindow2> pTopWnd2;
if( S_OK == pWnd2->get_top(&pTopWnd2) )
{
CComQIPtr<IHTMLWindow3> pTopWnd3(pTopWnd2);
if( pTopWnd3 )
{
VARIANT_BOOL vbSuccess = VARIANT_FALSE;
if( m_pOnPageLoadEvent )
{
pTopWnd3->detachEvent( _bstr_t(L"onload"), m_pOnPageLoadEvent);
}
m_pOnPageLoadEvent = (CDOMEventHandler*)CDOMEventHandler::CreateEventHandler( &CWebBrowser::OnPageLoad, (LONG_PTR)this);
pTopWnd3->attachEvent( _bstr_t(L"onload")
, m_pOnPageLoadEvent
, &vbSuccess
);
}
}
}
}
SysFreeString(bstrReadyState);
}
}// pDoc2
}// get_Document
}// pWebBrowser2
}
当页面onload后,就可以进行截屏了。下面是关键代码,其实原理很简单:
首先创建一个大小等于 document.body.clientWidth 宽, document.documentElement.scrollHeight 高的 画布。 然后依次滚动页面,每次滚动的距离等于客户区的高度,滚动后截图,依此结束。
void CWebBrowser::CaptureToImage()
{
CComQIPtr<IHTMLDocument2> pDoc2 = this->get_Document();
CComQIPtr<IHTMLDocument3> pDoc3(pDoc2);
if( pDoc2 )
{
CComPtr<IHTMLElement> pBodyElem;
CComPtr<IHTMLWindow2> pWnd2, pTopWnd2;
if( S_OK == pDoc2->get_body(&pBodyElem) &&
S_OK == pDoc2->get_parentWindow(&pWnd2) &&
S_OK == pWnd2->get_top(&pTopWnd2))
{
long nScrollHeight = 0L, nClientWidth = 0L, nClientHeight = 0L;
CComPtr<IHTMLElement> pDocElem;
pDoc3->get_documentElement(&pDocElem);
CComQIPtr<IHTMLElement2> pDocElem2(pDocElem);
CComQIPtr<IHTMLElement2> pBodyElem2(pBodyElem);
pBodyElem2->get_scrollHeight(&nScrollHeight);
RECT rect;
GetClientRect(&rect);
nClientWidth = rect.right - rect.left;
nClientHeight = rect.bottom - rect.top;
if( nScrollHeight > 0 && nClientWidth > 0 && nClientHeight > 0 )
{
Bitmap bitmap(nClientWidth, nScrollHeight);
Graphics g(&bitmap);
HDC hDC = g.GetHDC();
if (hDC != NULL)
{
long nYPos = nScrollHeight - nClientHeight;
do
{
pTopWnd2->scrollTo( 0, nYPos);
{
long y1 = 0, y2 = 0;
pDocElem2->get_scrollTop(&y1);
pBodyElem2->get_scrollTop(&y2);
nYPos = max(y1, y2);
}
HDC hMemDC = ::CreateCompatibleDC(hDC);
HBITMAP hBitmap = ::CreateCompatibleBitmap( hDC, nClientWidth, nClientHeight);
::SelectObject( hMemDC, hBitmap);
VERIFY(::PrintWindow( GetSafeHwnd(), hMemDC, PW_CLIENTONLY));
::SelectObject( hMemDC, NULL);
::BitBlt( hDC, 0, nYPos, nClientWidth, nClientHeight, hMemDC, 0, 0, SRCCOPY);
::DeleteDC(hMemDC);
::DeleteObject(hBitmap);
if( nYPos <= 0)
break;
nYPos -= nClientHeight;
if( nYPos < 0 )
nYPos = 0;
} while (true);
g.ReleaseHDC(hDC);
CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
bitmap.Save(L"L:\\WebSitesMonitoring\\1.png", &pngClsid);
}
}
}
}
}
最终通过GDI+保存成PNG格式。下面是
GetEncoderClsid方法
int CWebBrowser::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0; // number of image encoders
UINT size = 0; // size of the image encoder array in bytes
ImageCodecInfo* pImageCodecInfo = NULL;
GetImageEncodersSize(&num, &size);
if(size == 0)
return -1; // Failure
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo == NULL)
return -1; // Failure
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j = 0; j < num; ++j)
{
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
{
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j; // Success
}
}
free(pImageCodecInfo);
return -1; // Failure
}
下面是效果,图片已经被CSDN压缩的不成样子了。。
分享到:
相关推荐
C# WebBrowser获取网页截图 调用WebBrowser.DrawImage
C# 从内存中获取webbrowser控件截图,可以后台或者隐藏窗体截图 C# 从内存中获取webbrowser控件截图,可以后台或者隐藏窗体截图
将webbrowser(其实不用webbrowser只给一个网址也行)中的内容保存为mht(和浏览器的网页另存为功能一样)文件,同时支持页面全屏截图(就是不管页面多长多宽自动截整个页面)。 默认保存为tif格式(应CSDN一名网友...
本人写了个用C# 导出网页上的图片小项目 只要输入网址就可以导出网页上的图片了 有兴趣的可以看看。
C#判断webbrowser页面最终加载完成
C#中使用Webbrowser打开网页之后 可以通过这个方法来获取打开网页中的图片
vb6保存窗口界面为图片
当要打开新窗口时,不是弹出IE或其他浏览器,在本身的新tab页中是实现。 可以在此基础上进行多次开发,如进行DOM操作,当然做个什么自动化提交之类的也不在话下了。 --包含源码
在WinForm程序中,webBrowser显示页面使用谷歌内核。避免了网页在WinForm中显示兼容性问题。
通过C#网络编程的webBrowser获取网页中的url并简单的尝试下载网页中的图片,主要是为以后网络开发的基础学习.其中主要的通过应用程序结合网页知识、正则表达式实现浏览、获取url、下载图片三个功能.而且很清晰的解析...
1,在项目中引用程序集拓展中的Microsoft.mshtml后,可以在公共控件中找到WebBrowser控件。 2,在窗体中加入三个按钮,然后添加WebBrowser控件,右键控件选属性,设置相应的属性。 3,设置WebBrowser控件的属性 ...
C#将网页内容转换成图片保存到本地( webbrowser 可应用于B/S结构中). 功能点: 1、里面集成了webbrowser 代理服务器的设定。 2、解决了不能在b/s结构中生成图片的问题。
C#使用webBrowser读取网页并将网页保存成图片,可保存图片为PNG 格式、JPG 格式图片、BMP 格式图片文件
C# webbrowser捕获错误页面实例类,捕获404 402 403 500 505 502 和断网-2146697211
继承WebBrowoser控件,新增页面内容缩放功能。。。
使用WebBrowser控件打印页面demo,通过修改demo中的几行代码就可以使用
Delphi将网页保存为图片! 值得下载看看!资源免费,大家分享!! 更多免费资源 http://ynsky.download.csdn.net/
采用WebBrowser伪装成浏览器访问,绕过了反爬虫程序,获取一个目标网页的数据
vb6_Webbrowser控件使用技巧 1、获得浏览器信息: Private Sub Command1_Click() WebBrowser1.Navigate "http://www.applevb.com" End Sub Private Sub Command2_Click() Dim oWindow Dim oNav Set oWindow ...
C#WebBrowser页面与Winform交互技巧