作業日志:實作瀏覽器滾動截屏,并且是指定的iframe在跨域的情況下,
首先拿到這個需求的時候,想了一下,實作滾動截屏并不難,難的具體的情況如下,
在IE瀏覽器的情況下,在前端實作,并且iframe是跨域的,還要自動上傳服務器,萬事開頭難,嘗試了HTML2canvas之后發現,它并不能解決跨域問題,而且不同瀏覽器其圖片會有差異,并且最重要的一點,svg圖在IE瀏覽器中截圖是空白,
當然,遇到需求,一定要解決,研究了IE設計介面,終于實作了,整體的思路是,拿到瀏覽器的介面物件,使用遞回遍歷,找到指定的iframe,拿到iframe物件,滾動每一屏,拼接起來,最后產生的是一個長圖,并且是高清位圖,高清的位圖占的控制元件大小非常大,所以使用壓縮演算法將其大小進行了30倍的壓縮,
壓縮后的圖片大概在100k-500k之間,那么怎么上傳呢,這個比較簡單了,在記憶體里直接使用base64編碼圖片,將字串傳至服務器當中,服務器拿到字串可以進行轉碼存盤,至于前端顯示,可以把圖片直接io傳輸顯示,也可以轉base64直接由img標簽進行決議,
既然思路有了,那就說說具體的實作,首先,采用任意編程語言,創建一個瀏覽器插件工程,這里,我采用studio,首先,捕獲IE瀏覽器視窗句柄,這個十分簡單,呼叫原生api就可以,代碼如下:
BSTR CshotScreenCtrl::shotScreen(void)
{
POINT pNow = { 0,0 };
BSTR base64Data = L"";
if (GetCursorPos(&pNow)) // 獲取滑鼠當前位置
{
pNow.x = pNow.x+200 ;
pNow.y = pNow.y+200;
HWND hwndPointNow = NULL;
hwndPointNow = WindowFromPoint(pNow)->m_hWnd; // 獲取滑鼠所在視窗的句柄
if (hwndPointNow)
{
string data = GetIHTMLDocument2Interface(hwndPointNow);
CString str = (CA2W)(data.c_str());
base64Data = str.AllocSysString();
}
}
return base64Data;
}
GetIHTMLDocument2Interface是獲取對應的父表單的介面物件方法,
string GetIHTMLDocument2Interface(HWND BrowserWnd)
{
string data;
CoInitialize(NULL);
HRESULT hr;
// Explicitly load MSAA so we know if it's installed
HINSTANCE hInst = ::LoadLibrary(_T("OLEACC.DLL"));
if (hInst)
{
LRESULT lRes; //SendMessageTimeout后的回傳值,用于函式pfObjectFromLresult的第1個引數
UINT nMsg = ::RegisterWindowMessage(_T("WM_HTML_GETOBJECT"));
::SendMessageTimeout(BrowserWnd, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes);
//獲取函式pfObjectFromLresult
LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress(hInst, "ObjectFromLresult");
if (pfObjectFromLresult)
{
CComQIPtr<IHTMLDocument2> spDoc;
hr = (*pfObjectFromLresult)(lRes, IID_IHTMLDocument, 0, (void**)&spDoc);
if (SUCCEEDED(hr))
{
//獲取檔案介面
CComPtr<IDispatch> spDisp;
spDoc->get_Script(&spDisp);
CComQIPtr<IHTMLWindow2> spWin = spDisp;
spWin->get_document(&spDoc.p);
// Change background color to red
//spDoc->put_bgColor(CComVariant("red"));
CComQIPtr<IHTMLWindow2> window;
spDoc->get_parentWindow(&window);
RECT rect;
::GetWindowRect(BrowserWnd, &rect);
int nWidth = rect.right - rect.left;
int nHeigth = rect.bottom - rect.top;
//嘗試獲取iframe的表單
CComQIPtr<IHTMLElement> fBody;
spDoc->get_body(&fBody);
CComQIPtr<IHTMLFrameBase2> fBase;
EnumFrame(spDoc, rect);
//CaptureToImage(spDoc,rect, BrowserWnd,"C://tempImg//tmp.png");
CompressImageQuality(L"C://tempImg//tmp.png", L"C://tempImg//tmpcompress.jpg", 50);
ReadPhotoFile(L"C://tempImg//tmpcompress.jpg",data);
} // else document not ready
} // else Internet Explorer is not running
::FreeLibrary(hInst);
} // else Active Accessibility is not installed
CoUninitialize();
return data;
}
雖然找到了父表單的介面,但是這里不能直接拿iframe的,因為我們現在是跨域,瀏覽器可不會讓你這么簡單的跨域,畢竟如果強行跨域,那你就可以強行跨站腳本攻擊了,但是道理是死的,人是活的,我們換種方法,既然我們呼叫拿的方法拿不到,那我們就自己取找,把父視窗轉成容器介面,列舉遞回遍歷每一個實作的iwebborwser介面的物件,直到找到名字為我們要的那個iframe為止,代碼如下:
void EnumFrame(IHTMLDocument2* pHTML,RECT rect)
{
CComQIPtr spContainer(pHTML);
if (spContainer)
{
CComPtr spEnumerator; // 注:引數OLECONTF_EMBEDDINGS // 表示列舉容器內的所有嵌入物件
HRESULT hr = spContainer->EnumObjects(OLECONTF_EMBEDDINGS, &spEnumerator);
if (spEnumerator)
{
CComPtr<IUnknown> spUnk;
while (spEnumerator->Next(1, &spUnk, NULL) == S_OK)
{
CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> spWB(spUnk);
spUnk = NULL;
if (spWB)
{
CComPtr<IDispatch> spDocDisp;
hr = spWB->get_Document(&spDocDisp);
CComQIPtr<IHTMLDocument2> spHTML(spDocDisp);
CComQIPtr<IHTMLElement> sBody;
spHTML->get_body(&sBody);
long sScrollHeight = 0L;
CComQIPtr<IHTMLElement2> pBodyElem2(sBody);
pBodyElem2->get_scrollHeight(&sScrollHeight);
CComPtr<IHTMLWindow2> pWnd2;
S_OK == spHTML->get_parentWindow(&pWnd2);
BSTR frameName;
pWnd2->get_name(&frameName);
string str1 = (_bstr_t)frameName;
if ("childIframe" == str1) {
long width = 0L;
long height = 0L;
spWB->get_Width(&width);
spWB->get_Height(&height);
CaptureToImage(spHTML, rect, NULL, "C://tempImg//tmp.png");
break;
}else {
EnumFrame(spHTML, rect);
}
}
}
}
}
}
到了這里,我們已經拿到iframe,也就是我們要截圖的表單,那么接下來只要呼叫scrollto,并且計算坐標偏移就可以了,原理十分的簡單,至于后面的代碼,十分簡單,就不貼出來了,到了這一步,我們已經可以跨域拿到iframe里的任何東西啦,想怎么操作就怎么操作,至于壓縮演算法還有轉base64上傳的代碼百度滿天飛,如果你有什么不懂,可以私信,附一張效果圖吧,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/229880.html
標籤:其他
上一篇:JS特效二:圖片彈窗
