`
helpbs
  • 浏览: 1162002 次
文章分类
社区版块
存档分类
最新评论

如何给WebBrowser中的网页全身照相

 
阅读更多

最近在写程序的时候,突然觉得google chrome的网页缩略照片挺好玩 , 可是 chrome 是自己的内核, 自家的东西当然方便.WebBrowser 又怎么办?

首先想到的是最普通的屏幕复制, 也就是大家熟知的bitblt, 从WebBrowser的dc复制到bitmap的dc. 这种方法有很大的局限性: 1.要正确复制,必须保证WebBrowser在屏幕复制的时候必须处于窗口最前端( 就是没有遮蔽物 ), 否则复制出来的图像是有遮盖物. 2.即使没有遮盖物,复制出来的图像往往包含3D Border , Scroll , 这在标准的WebBrowser是必要的.但是对于网页缩略照片,这可就是恶心的东西了.

于是有人想到了ActiveX里面的一个接口 IViewObject2 , WebBrowser也实现了这个接口, 你只需要从WebBrowser对象中QueryInterface(...)就可以枚举出这个接口. IWebBrowser2* pWB2 = ...//获取WebBrowser接口, pWB2->QueryInterface( IID_IViewObject2 , (void**)&pViewObj2 ); 然后使用 IViewObject2 中的 Draw 这个方法,就可以绘画WebBrowser中网页的内容, 很好,即使窗口是隐藏的也可以画出, 可是,等等, 只要您尝试这个方法, 您就会发现,这个仍然不尽如人意. 因为你只能获取WebBrowser这个窗口大小的网页缩略图 , 而无法获取整个网页的缩略图. 同时, 3D Border, Scroll 仍然折磨着我们. 有人提出了如下代码 , 可以一定程度缓解, 让我们看看:

  1. IHTMLBodyElement*pBody=0;
  2. IHTMLElement*pBodyElem;
  3. HRTEST_E(GetHTMLDocument2()->get_body(&pBodyElem));
  4. HRTEST_E(pBodyElem->QueryInterface(IID_IHTMLBodyElement,(void**)&pBody));
  5. IHTMLStyle*pStyle;
  6. HRTEST_E(pBodyElem->get_style(&pStyle));
  7. HRTEST_E(pStyle->put_borderStyle(bsBorderStyle=::SysAllocString(L"none")));
  8. //hidescrollbars
  9. HRTEST_E(pBody->put_scroll(bsScrollStyle=::SysAllocString(L"no")));
  10. //resizethebrowsercomponenttothesizeoftheHTMLcontent
  11. IHTMLElement2*pBodyElement2;
  12. HRTEST_E(pBody->QueryInterface(IID_IHTMLElement2,(void**)&pBodyElement2));
  13. longiScrollWidth=0;
  14. HRTEST_E(pBodyElement2->get_scrollWidth(&iScrollWidth));
  15. longiScrollHeight=0;
  16. HRTEST_E(pBodyElement2->get_scrollHeight(&iScrollHeight));
  17. RECTrc={0,0,iScrollWidth,iScrollHeight};
  18. ::SetWindowPos(GetHWND(),NULL,0,0,iScrollWidth,iScrollHeight,SWP_NOREDRAW);
  19. SetWebRect(&rc);

忽略其中奇怪的宏,我们可以发现,这个思想就是使用 Body, 来关闭border, 关闭scroll, 在有些场合下是有用的,可是大部分情况,如果页面过大(比如超过屏幕大小), scroll还是会出现. border也不会消失,因为这和body元素没有关系.

真的没有办法解决吗? 当然有,否则我也不会写那么多东西了, 有一个很著名的好东西, 接口:IDocHostUIHandler , 他有一个方法:GetHostInfo(DOCHOSTUIINFO *pInfo); 可以改变WebBrowser的显示方式.完全不需要使用body来关闭border和scroll这种吃力不讨好的办法. 所以为了去除border, scroll我们只要这么写:

  1. HRESULT
  2. CShadowWebWindow::GetHostInfo(DOCHOSTUIINFO*pInfo)
  3. {
  4. pInfo->cbSize=sizeof(DOCHOSTUIINFO);
  5. pInfo->dwFlags=DOCHOSTUIFLAG_DIALOG|
  6. DOCHOSTUIFLAG_THEME|
  7. DOCHOSTUIFLAG_NO3DBORDER|
  8. DOCHOSTUIFLAG_SCROLL_NO;
  9. returnS_OK;
  10. }

其中DOCHOSTUIFLAG_NO3DBORDER和DOCHOSTUIFLAG_SCROLL_NO正是我们需要的效果. 接下来我们要画出整个网页,只需要设置WebBrowser的容器大小为html的大小, 就可以完满的画出网页缩略图.

当然, 在下强烈推荐应当使用一个看不见的WebBrowser来实现化网页缩略图, 毕竟, 一个窗口忽大忽小,不是一个好的用户体验.

最后整理一下代码:

我使用一个叫CShadowWebWindow类实现WebBrowser, 这是一个不可见的窗口.

以下是关键代码, (请忽略奇怪的宏 )

  1. void
  2. CShadowWebWindow::DocumentComplete(IDispatch*pDisp,VARIANT*URL)
  3. {
  4. WebBrowserWindow::DocumentComplete(pDisp,URL);
  5. PWSTRnpwNewBmpFilePath=NULL;
  6. IWebBrowser2*pWB2=GetWebBrowser2();
  7. IViewObject2*pViewObject2=NULL;
  8. HRTEST_E(pWB2->QueryInterface(IID_IViewObject2,(void**)&pViewObject2));
  9. IHTMLElement*pBodyElem;
  10. HRTEST_E(GetHTMLDocument2()->get_body(&pBodyElem));
  11. //resizethebrowsercomponenttothesizeoftheHTMLcontent
  12. IHTMLElement2*pBodyElement2;
  13. HRTEST_E(pBodyElem->QueryInterface(IID_IHTMLElement2,(void**)&pBodyElement2));
  14. longiScrollWidth=0;
  15. HRTEST_E(pBodyElement2->get_scrollWidth(&iScrollWidth));
  16. longiScrollHeight=0;
  17. HRTEST_E(pBodyElement2->get_scrollHeight(&iScrollHeight));
  18. //调整WebBrowser大小和网页大小一致
  19. RECTrc={0,0,iScrollWidth,iScrollHeight};
  20. ::SetWindowPos(GetHWND(),NULL,0,0,iScrollWidth,iScrollHeight,SWP_NOREDRAW);
  21. SetWebRect(&rc);
  22. HBITMAPhBitmap=::CreateCompatibleBitmap(GetDC(GetHWND()),RECTWIDTH(rc),RECTHEIGHT(rc));
  23. HDChBitmapDC=::CreateCompatibleDC(GetDC(GetHWND()));
  24. ::SelectObject(hBitmapDC,hBitmap);
  25. RECTLrctl={rc.left,rc.top,rc.right,rc.bottom};
  26. //绘画WebBrowser中的网页内容
  27. //GetHWND()返回WebBrowser容器窗口句柄
  28. HRTEST_E(pViewObject2->Draw(DVASPECT_CONTENT,1,NULL,NULL,::GetDC(GetHWND()),hBitmapDC,&rctl,NULL,NULL,0));
  29. //写bmp文件
  30. BITMAPstBitmap;
  31. PBYTEnpData;
  32. DWORDdwDataSize;
  33. DWORDdwBmpDataSize;
  34. HANDLEhBmpFile;
  35. DWORDdwWritten;
  36. NULLTEST_E(::GetObjectW(hBitmap,sizeof(stBitmap),(PVOID)&stBitmap));
  37. NULLTEST_E(npData=
  38. newBYTE[dwDataSize=(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+(dwBmpDataSize=((stBitmap.bmWidth*8+31)/32)*4*stBitmap.bmHeight*3))]);
  39. BITMAPFILEHEADER*pBmpFileHeader=(BITMAPFILEHEADER*)(npData);
  40. pBmpFileHeader->bfType=0x4D42;//"BM"
  41. pBmpFileHeader->bfSize=dwDataSize;//sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+0+dwBmpDataSize;
  42. pBmpFileHeader->bfReserved1=0;
  43. pBmpFileHeader->bfReserved2=0;
  44. pBmpFileHeader->bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+0;
  45. BITMAPINFOHEADER*pBmpInfoHeader=(BITMAPINFOHEADER*)(npData+sizeof(BITMAPFILEHEADER));
  46. pBmpInfoHeader->biSize=sizeof(BITMAPINFOHEADER);
  47. pBmpInfoHeader->biWidth=stBitmap.bmWidth;
  48. pBmpInfoHeader->biHeight=stBitmap.bmHeight;
  49. pBmpInfoHeader->biPlanes=1;
  50. pBmpInfoHeader->biBitCount=24;
  51. pBmpInfoHeader->biCompression=BI_RGB;
  52. pBmpInfoHeader->biSizeImage=0;
  53. pBmpInfoHeader->biXPelsPerMeter=0;
  54. pBmpInfoHeader->biYPelsPerMeter=0;
  55. pBmpInfoHeader->biClrUsed=0;
  56. pBmpInfoHeader->biClrImportant=0;
  57. NULLTEST_E(::GetDIBits(hBitmapDC,hBitmap,0,stBitmap.bmHeight,npData+sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER),(BITMAPINFO*)(npData+sizeof(BITMAPFILEHEADER)),DIB_RGB_COLORS));
  58. //创建文件,写文件
  59. VALUETEST_E(hBmpFile=::CreateFileW(L"e://test.bmp",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL),INVALID_HANDLE_VALUE);
  60. FALSETEST_E(::WriteFile(hBmpFile,npData,dwDataSize,&dwWritten,NULL));
  61. ::CloseHandle(hBmpFile);
  62. RETURN:
  63. DeleteArray(npwNewBmpFilePath);
  64. return;
  65. }
  66. HRESULT
  67. CShadowWebWindow::GetHostInfo(DOCHOSTUIINFO*pInfo)
  68. {
  69. pInfo->cbSize=sizeof(DOCHOSTUIINFO);
  70. pInfo->dwFlags=DOCHOSTUIFLAG_DIALOG|
  71. DOCHOSTUIFLAG_THEME|
  72. DOCHOSTUIFLAG_NO3DBORDER|
  73. DOCHOSTUIFLAG_SCROLL_NO;
  74. returnS_OK;
  75. }

至此,我们已经实现了网页的快照(或者缩略图). 完全可以媲美Chrome的实现. 希望给大家有帮助,我在网上看到的都有这样那样的瑕疵, 在下的实现应该稍微完美一点, 希望对大家有帮助.

如果我的文章对您有帮助,请您留言说说您的感想,这是对我莫大的鼓励,谢谢!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics