先说一点题外话,将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. 对相机所看的视角截屏保存为图片

    对相机所看的视角截屏保存为图片: 1 using UnityEngine; 2 using System.Collections; 3 using UnityEngine.UI; 4 /// < ...

  2. 使用html2canvas完成页面截屏并保存为图片

    实现网页页面截屏,并且将其转换为指定图片格式保存下来,需要使用到html2canvas.js. 前面是实现原理和步骤分析,具体实现代码在文章尾部. 一.实现HTML页面截屏并保存为图片 原理是遍历需要 ...

  3. 如何使用ChromeHeadLess 技术实现后台对前台页面截屏

    如何使用ChromeHeadLess 技术实现后台对前台页面截屏 1 chrome headless 1.1 什么是chrome headless 1.2 chrome headless的作用 1.3 ...

  4. iOS 生成带 logo 的二维码,区域截屏保存至相册(小功能二连发 (一))

    原文链接:http://www.jianshu.com/p/36e9f012ef39 生成带 logo 的二维码 区域截屏相关 -- 由3033分享 开篇 最近项目需要搞了几个相对独立的小功能,今天有 ...

  5. 在ubuntu中进行简单截屏、专业截屏、自定义截屏操作

    我的工作离不开处理文档,文档记录中时常要求截图操作和录屏操作.个人的精力有限,只能先在这一个文档中记录截图操作. 在windows中,我们可以通过快捷键来截图(Alt+PS).截屏(PS),然后打开画 ...

  6. JAVA服务端实现页面截屏(附代码)

    JAVA服务端实现页面截屏 适配需求 方案一.使用JxBrowser 使用步骤: 方案二.JavaFX WebView 使用步骤: 方案三.Headless Chrome 使用步骤: 综上方案对比 记 ...

  7. 上传文件、视频、图片、全选、全不选、截屏直接粘贴图片

    上传文件.视频.图片.全选.全不选.截屏直接粘贴图片 控制器代码:ObUnitsController.php <?phpnamespace App\Admin\Controllers;use A ...

  8. Python自动控制鼠标中键滚动并截屏保存图像

    推荐图书: <Python可以这样学>,ISBN:9787302456469,董付国,清华大学出版社,第9次印刷 图书详情(京东): 董付国老师所有图书均提供配套教学资源. ======= ...

  9. html手机截屏保存,手机屏幕截图无法保存该怎么解决?

    安卓4.0及以上系统有快捷截图功能,大多数安卓机是同时按住[电源键]和[音量下键]完成整个功能.笔者以前用这个功能非常便利,可最近快速截屏时一直提示:"无法保存屏幕截图存储设备可能正在使用& ...

最新文章

  1. Android深度探索(卷1)HAL与驱动开发 读书笔记(第四章)
  2. 【APICloud系列|22】 videoPlayer模块(视频播放)的实现
  3. python基础入门(4)之布尔值
  4. 折纸 瓦力机器人_折纸图解金鱼筷子架
  5. 一用户使用LTC以168万美元的价格购入收藏界“圣杯“卡片
  6. iframe父页面和子页面高度自适应
  7. 小学计算机教案 插入艺术字,小学信息技术《在幻灯片中插入艺术字》说课及反思...
  8. android多个单选框超格,福昕PDF阅读器打印时提示“打印机被意外删除了”怎么处理?...
  9. FastReport.NET v2022.2.7
  10. b和kb的换算_G,M,KB,B,b,MB/s,Mb/s,bps等等之间的换算
  11. C语言编写时钟 循环,單片机基于c语言编写时钟.doc
  12. 香坊区开启“三位一体”智慧城管新模式
  13. linux pam 使用例子,PAM认证模块使用实例
  14. 台式计算机联网,台式电脑怎么联网宽带
  15. Out of range value for column
  16. 如何把Dom对象转换成jQuery对象,如何把jQuery对象转换成Dom对象
  17. 实现人脸磨皮算法---OpenCV-Python开发指南(58)
  18. 免费的阿里云短信(5000条)
  19. STM32 12864串行驱动
  20. 《深入理解Android 卷Ⅰ》深入理解init

热门文章

  1. dla模型 matlab代码,在MATLAB平台下实现DLA分形聚集生长的模拟
  2. 基于51单片机的酒精浓度检测量仪proteus仿真程序原理图设计数码管液晶LCD1602显示
  3. 斯特芬森迭代法求解方程根 c++
  4. 订单和订单明细继承等级结构简单介绍
  5. 财务系统软件数据库服务器配置,用友财务数据库配置服务器地址
  6. python识别花草_吴裕雄 python神经网络 花朵图片识别(9)
  7. mysql字符串转拼音_MySQL中文字段转拼音
  8. 为什么出现新零售 如何做好新零售?
  9. 大学外语电台自动播控系统方案
  10. iOS 烟花撒花效果,图层渐变,图层倒影特效。CAEmitterLayer粒子发射器