返回> 网站首页
[转载]WebBrowser页面全身照相
yoours2015-06-10 13:17:29
简介一边听听音乐,一边写写文章。
大家熟知的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 = { 0, 0, iScrollWidth, iScrollHeight };
::SetWindowPos(GetHWND(), NULL, 0, 0, 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 = { 0, 0, iScrollWidth, iScrollHeight };
::SetWindowPos(GetHWND(), NULL, 0, 0, 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;
}
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 = { 0, 0, iScrollWidth, iScrollHeight };
::SetWindowPos(GetHWND(), NULL, 0, 0, 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 = { 0, 0, iScrollWidth, iScrollHeight };
::SetWindowPos(GetHWND(), NULL, 0, 0, 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条评论