将WebBrowser中的页面截屏保存为图片
先说一点题外话,将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压缩的不成样子了。。
将WebBrowser中的页面截屏保存为图片相关推荐
- 对相机所看的视角截屏保存为图片
对相机所看的视角截屏保存为图片: 1 using UnityEngine; 2 using System.Collections; 3 using UnityEngine.UI; 4 /// < ...
- 使用html2canvas完成页面截屏并保存为图片
实现网页页面截屏,并且将其转换为指定图片格式保存下来,需要使用到html2canvas.js. 前面是实现原理和步骤分析,具体实现代码在文章尾部. 一.实现HTML页面截屏并保存为图片 原理是遍历需要 ...
- 如何使用ChromeHeadLess 技术实现后台对前台页面截屏
如何使用ChromeHeadLess 技术实现后台对前台页面截屏 1 chrome headless 1.1 什么是chrome headless 1.2 chrome headless的作用 1.3 ...
- iOS 生成带 logo 的二维码,区域截屏保存至相册(小功能二连发 (一))
原文链接:http://www.jianshu.com/p/36e9f012ef39 生成带 logo 的二维码 区域截屏相关 -- 由3033分享 开篇 最近项目需要搞了几个相对独立的小功能,今天有 ...
- 在ubuntu中进行简单截屏、专业截屏、自定义截屏操作
我的工作离不开处理文档,文档记录中时常要求截图操作和录屏操作.个人的精力有限,只能先在这一个文档中记录截图操作. 在windows中,我们可以通过快捷键来截图(Alt+PS).截屏(PS),然后打开画 ...
- JAVA服务端实现页面截屏(附代码)
JAVA服务端实现页面截屏 适配需求 方案一.使用JxBrowser 使用步骤: 方案二.JavaFX WebView 使用步骤: 方案三.Headless Chrome 使用步骤: 综上方案对比 记 ...
- 上传文件、视频、图片、全选、全不选、截屏直接粘贴图片
上传文件.视频.图片.全选.全不选.截屏直接粘贴图片 控制器代码:ObUnitsController.php <?phpnamespace App\Admin\Controllers;use A ...
- Python自动控制鼠标中键滚动并截屏保存图像
推荐图书: <Python可以这样学>,ISBN:9787302456469,董付国,清华大学出版社,第9次印刷 图书详情(京东): 董付国老师所有图书均提供配套教学资源. ======= ...
- html手机截屏保存,手机屏幕截图无法保存该怎么解决?
安卓4.0及以上系统有快捷截图功能,大多数安卓机是同时按住[电源键]和[音量下键]完成整个功能.笔者以前用这个功能非常便利,可最近快速截屏时一直提示:"无法保存屏幕截图存储设备可能正在使用& ...
最新文章
- Android深度探索(卷1)HAL与驱动开发 读书笔记(第四章)
- 【APICloud系列|22】 videoPlayer模块(视频播放)的实现
- python基础入门(4)之布尔值
- 折纸 瓦力机器人_折纸图解金鱼筷子架
- 一用户使用LTC以168万美元的价格购入收藏界“圣杯“卡片
- iframe父页面和子页面高度自适应
- 小学计算机教案 插入艺术字,小学信息技术《在幻灯片中插入艺术字》说课及反思...
- android多个单选框超格,福昕PDF阅读器打印时提示“打印机被意外删除了”怎么处理?...
- FastReport.NET v2022.2.7
- b和kb的换算_G,M,KB,B,b,MB/s,Mb/s,bps等等之间的换算
- C语言编写时钟 循环,單片机基于c语言编写时钟.doc
- 香坊区开启“三位一体”智慧城管新模式
- linux pam 使用例子,PAM认证模块使用实例
- 台式计算机联网,台式电脑怎么联网宽带
- Out of range value for column
- 如何把Dom对象转换成jQuery对象,如何把jQuery对象转换成Dom对象
- 实现人脸磨皮算法---OpenCV-Python开发指南(58)
- 免费的阿里云短信(5000条)
- STM32 12864串行驱动
- 《深入理解Android 卷Ⅰ》深入理解init
热门文章
- dla模型 matlab代码,在MATLAB平台下实现DLA分形聚集生长的模拟
- 基于51单片机的酒精浓度检测量仪proteus仿真程序原理图设计数码管液晶LCD1602显示
- 斯特芬森迭代法求解方程根 c++
- 订单和订单明细继承等级结构简单介绍
- 财务系统软件数据库服务器配置,用友财务数据库配置服务器地址
- python识别花草_吴裕雄 python神经网络 花朵图片识别(9)
- mysql字符串转拼音_MySQL中文字段转拼音
- 为什么出现新零售 如何做好新零售?
- 大学外语电台自动播控系统方案
- iOS 烟花撒花效果,图层渐变,图层倒影特效。CAEmitterLayer粒子发射器