返回> 网站首页 

[转载]WebBrowser页面全身照相

yoours2015-06-10 13:17:29 阅读 1964

简介一边听听音乐,一边写写文章。

大家熟知的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 仍然折磨着我们. 有人提出了如下代码, 可以一定程度缓解, 让我们看看: 
 
IHTMLBodyElement * pBody = 0
IHTMLElement *pBodyElem; 
HRTEST_E(GetHTMLDocument2()->get_body(&pBodyElem)); 
HRTEST_E(pBodyElem->QueryInterface(IID_IHTMLBodyElement, (void **)&pBody)); 
 
IHTMLStyle *pStyle; 
HRTEST_E (pBodyElem->get_style(&pStyle)); 
HRTEST_E (pStyle->put_borderStyle(bsBorderStyle = ::SysAllocString(L"none"))); 
 
// hide scrollbars 
HRTEST_E(pBody->put_scroll(bsScrollStyle = ::SysAllocString(L"no"))); 
// resize the browser component to the size of the HTML content 
IHTMLElement2 *pBodyElement2; 
HRTEST_E(pBody->QueryInterface(IID_IHTMLElement2, (void **)&pBodyElement2)); 
long iScrollWidth = 0
HRTEST_E(pBodyElement2->get_scrollWidth(&iScrollWidth)); 
long iScrollHeight = 0
HRTEST_E(pBodyElement2->get_scrollHeight(&iScrollHeight)); 
RECT rc = { 00, iScrollWidth, iScrollHeight }; 
::SetWindowPos(GetHWND(), NULL, 00, iScrollWidth, iScrollHeight, SWP_NOREDRAW); 
SetWebRect(&rc); 
 
忽略其中奇怪的宏, 我们可以发现, 这个思想就是使用 Body, 来关闭border, 关闭scroll, 在有些场合下是有用的, 可是大部分情况, 如果页面过大(比如超过屏幕大小), scroll还是会出现. border也不会消失, 因为这和body元素没有关系. 
 
真的没有办法解决吗 ? 当然有, 否则我也不会写那么多东西了, 有一个很著名的好东西, 接口 : IDocHostUIHandler, 他有一个方法 : GetHostInfo(DOCHOSTUIINFO *pInfo); 
可以改变WebBrowser的显示方式.完全不需要使用body来关闭border和scroll这种吃力不讨好的办法. 所以为了去除border, scroll我们只要这么写: 
 
HRESULT CShadowWebWindow::GetHostInfo(DOCHOSTUIINFO *pInfo) 

    pInfo->cbSize = sizeof(DOCHOSTUIINFO); 
    pInfo->dwFlags = DOCHOSTUIFLAG_DIALOG | 
                     DOCHOSTUIFLAG_THEME  | 
                     DOCHOSTUIFLAG_NO3DBORDER | 
                     DOCHOSTUIFLAG_SCROLL_NO; 
    return S_OK; 

 
其中DOCHOSTUIFLAG_NO3DBORDER和DOCHOSTUIFLAG_SCROLL_NO正是我们需要的效果. 接下来我们要画出整个网页, 只需要设置WebBrowser的容器大小为html的大小, 就可以完满的画出网页缩略图. 
 
当然, 在下强烈推荐应当使用一个看不见的WebBrowser来实现化网页缩略图, 毕竟, 一个窗口忽大忽小, 不是一个好的用户体验. 
 
最后整理一下代码: 
 
我使用一个叫CShadowWebWindow类实现WebBrowser, 这是一个不可见的窗口. 
 
以下是关键代码 
void CShadowWebWindow::DocumentComplete(IDispatch *pDisp, VARIANT *URL) 

    WebBrowserWindow::DocumentComplete(pDisp, URL); 
 
    PWSTR npwNewBmpFilePath = NULL; 
    IWebBrowser2 *pWB2 = GetWebBrowser2(); 
    IViewObject2 *pViewObject2 = NULL; 
    HRTEST_E(pWB2->QueryInterface(IID_IViewObject2, (void **)&pViewObject2)); 
    IHTMLElement *pBodyElem; 
    HRTEST_E(GetHTMLDocument2()->get_body(&pBodyElem)); 
 
    // resize the browser component to the size of the HTML content 
    IHTMLElement2 *pBodyElement2; 
    HRTEST_E(pBodyElem->QueryInterface(IID_IHTMLElement2, (void **)&pBodyElement2)); 
    long iScrollWidth = 0
    HRTEST_E(pBodyElement2->get_scrollWidth(&iScrollWidth)); 
    long iScrollHeight = 0
    HRTEST_E(pBodyElement2->get_scrollHeight(&iScrollHeight)); 
    //调整WebBrowser大小和网页大小一致 
    RECT rc = { 00, iScrollWidth, iScrollHeight }; 
    ::SetWindowPos(GetHWND(), NULL, 00, iScrollWidth, iScrollHeight, SWP_NOREDRAW); 
    SetWebRect(&rc); 
 
    HBITMAP hBitmap = ::CreateCompatibleBitmap(GetDC(GetHWND()), RECTWIDTH(rc), RECTHEIGHT(rc)); 
    HDC hBitmapDC = ::CreateCompatibleDC(GetDC(GetHWND())); 
    ::SelectObject(hBitmapDC, hBitmap); 
 
    RECTL rctl = { rc.left, rc.top, rc.right, rc.bottom }; 
    //绘画WebBrowser中的网页内容 
    //GetHWND()返回WebBrowser容器窗口句柄 
    HRTEST_E(pViewObject2->Draw(DVASPECT_CONTENT, 1, NULL, NULL, ::GetDC(GetHWND()), hBitmapDC, &rctl, NULL, NULL, 0)); 
    //写bmp文件 
    BITMAP stBitmap; 
    PBYTE npData; 
    DWORD dwDataSize; 
    DWORD dwBmpDataSize; 
    HANDLE hBmpFile; 
    DWORD dwWritten; 
    NULLTEST_E(::GetObjectW(hBitmap, sizeof(stBitmap), (PVOID)&stBitmap)); 
    NULLTEST_E(npData = 
                   new BYTE[ dwDataSize = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (dwBmpDataSize = ((stBitmap.bmWidth*8+31)/32)*4*stBitmap.bmHeight*3)) ]); 
 
    BITMAPFILEHEADER *pBmpFileHeader = (BITMAPFILEHEADER *)(npData); 
    pBmpFileHeader->bfType   =   0x4D42;     //   "BM" 
    pBmpFileHeader->bfSize   =   dwDataSize;//sizeof(BITMAPFILEHEADER)  + sizeof(BITMAPINFOHEADER)  +  0  +  dwBmpDataSize ; 
    pBmpFileHeader->bfReserved1   =   0
    pBmpFileHeader->bfReserved2   =   0
    pBmpFileHeader->bfOffBits   =   sizeof(BITMAPFILEHEADER)  +  sizeof(BITMAPINFOHEADER)  +  0
    BITMAPINFOHEADER *pBmpInfoHeader = (BITMAPINFOHEADER *)(npData + sizeof(BITMAPFILEHEADER)); 
    pBmpInfoHeader->biSize  = sizeof(BITMAPINFOHEADER); 
    pBmpInfoHeader->biWidth = stBitmap.bmWidth; 
    pBmpInfoHeader->biHeight = stBitmap.bmHeight; 
    pBmpInfoHeader->biPlanes = 1
    pBmpInfoHeader->biBitCount = 24
    pBmpInfoHeader->biCompression = BI_RGB; 
    pBmpInfoHeader->biSizeImage = 0
    pBmpInfoHeader->biXPelsPerMeter = 0
    pBmpInfoHeader->biYPelsPerMeter = 0
    pBmpInfoHeader->biClrUsed = 0
    pBmpInfoHeader->biClrImportant = 0
    NULLTEST_E(::GetDIBits(hBitmapDC, hBitmap, 0, stBitmap.bmHeight, npData   + sizeof(BITMAPFILEHEADER) +  sizeof(BITMAPINFOHEADER), (BITMAPINFO *)(npData + sizeof(BITMAPFILEHEADER)), DIB_RGB_COLORS)); 
 
    //创建文件,写文件 
    VALUETEST_E(hBmpFile = ::CreateFileW(L"e://test.bmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL), INVALID_HANDLE_VALUE); 
    FALSETEST_E(::WriteFile(hBmpFile, npData, dwDataSize, &dwWritten, NULL)); 
    ::CloseHandle(hBmpFile); 
 
RETURN: 
    DeleteArray(npwNewBmpFilePath); 
    return

 
HRESULT CShadowWebWindow::GetHostInfo(DOCHOSTUIINFO *pInfo) 

    pInfo->cbSize = sizeof(DOCHOSTUIINFO); 
    pInfo->dwFlags = DOCHOSTUIFLAG_DIALOG | 
                     DOCHOSTUIFLAG_THEME  | 
                     DOCHOSTUIFLAG_NO3DBORDER | 
                     DOCHOSTUIFLAG_SCROLL_NO; 
    return S_OK; 

微信小程序扫码登陆

文章评论

1964人参与,0条评论