轉(zhuǎn)載請(qǐng)注明出處:
http://www.shnenglu.com/greatws/archive/2009/05/05/81996.html這段時(shí)間GF一直在玩QQ找茬,看了一下,原理很簡單,就是找到2附圖片的不同之處,那么程序的思路也就很明了了,就是抓圖,存入buffer,比較,顯示,這么一個(gè)過程。閑話不多說了,下面我用MFC來實(shí)現(xiàn)它。
首先先要拿到QQ找茬從窗口的句柄,拿到句柄想咋搞就咋搞,哈哈。當(dāng)然也可以不要句柄,直接屏幕截圖,不過那樣就要保證窗口在某個(gè)特定的位置,不如句柄來的方便。嗯,還是拿句柄吧,就FindWindow這個(gè)函數(shù)吧,至于窗口名和類名,用spy++就好啦。
得到句柄之后,接下來要做的是獲得窗口大小及設(shè)備DC,然后利用CreateCompatibleBitmap函數(shù),創(chuàng)建與QQ找茬窗口DC兼容的BITMAP對(duì)象,針對(duì)左右2副圖,創(chuàng)建2個(gè),便于以后的比較,然后根據(jù)坐標(biāo)偏移,這個(gè)用photoshop可以數(shù)出來,利用BitBlt函數(shù)復(fù)制QQ找茬窗口DC里的位圖數(shù)據(jù)進(jìn)入創(chuàng)建好的BITMAP對(duì)象,然后再把BITMAP中的位圖數(shù)據(jù)復(fù)制到內(nèi)存Buffer中,CopyBMPToBuffer是我對(duì)GetDIBits函數(shù)做了一下簡單的封裝,少了幾個(gè)參數(shù)而已。代碼如下:
BOOL CFindDlg::CopyWindowBlt(CWnd *pWndSrc)


{
if(pWndSrc == NULL)

{
return FALSE;
}

CRect cRect, cRectClient;
pWndSrc->GetWindowRect(&cRect);
pWndSrc->GetClientRect(&cRectClient);
pWndSrc->ClientToScreen(&cRectClient);

CDC *pSrcDC = NULL;
CDC cNewDC;
CBitmap cBitmapLeft, cBitmapRight;
BITMAPINFO bi;

pSrcDC = pWndSrc->GetDC();
//create Compatible Bitmap with the game window
cBitmapLeft.CreateCompatibleBitmap(pSrcDC, m_nPicWidth, m_nPicHeight);
cBitmapRight.CreateCompatibleBitmap(pSrcDC, m_nPicWidth, m_nPicHeight);
cNewDC.CreateCompatibleDC(pSrcDC);
CBitmap* pcOldBitmap = cNewDC.SelectObject(&cBitmapLeft);
//copy bitmap to dc
cNewDC.BitBlt(0, 0, m_nPicWidth, m_nPicHeight, pSrcDC,
m_nLeftPicLeftTopX - (cRectClient.left - cRect.left),
m_nLeftPicLeftTopY - (cRectClient.top - cRect.top), SRCCOPY);

CopyBMPToBuffer(cNewDC.GetSafeHdc(), (HBITMAP)cBitmapLeft.GetSafeHandle(), m_pBufLeft, &bi);

cNewDC.SelectObject(&cBitmapRight);
cBitmapLeft.DeleteObject();

cNewDC.BitBlt(0, 0, m_nPicWidth, m_nPicHeight, pSrcDC,
m_nRightPicLeftTopX - (cRectClient.left - cRect.left),
m_nRightPicLeftTopY - (cRectClient.top - cRect.top), SRCCOPY);

CopyBMPToBuffer(cNewDC.GetSafeHdc(), (HBITMAP)cBitmapRight.GetSafeHandle(), m_pBufRight, &bi);

cNewDC.SelectObject(pcOldBitmap);
cBitmapRight.DeleteObject();
cNewDC.DeleteDC();
pWndSrc->ReleaseDC(pSrcDC);

return TRUE;
}
完成上述工作以后,要比較的位圖已經(jīng)在2塊buffer中了,數(shù)學(xué)建模完成了,已經(jīng)轉(zhuǎn)化成數(shù)學(xué)問題了,下面要做的就是比較數(shù)組中的數(shù)據(jù)和顯示了。這里我沒有用2維數(shù)組來做比較,簡單的用一下一維就好啦。建立一塊新的buffer,全部置為藍(lán)色,這樣可以設(shè)置alpha透過,以便直接在QQ找茬窗口上面直接顯示差異,稍后就會(huì)看到效果。比較算法如下,很簡單,找到不同處涂為黃色,臨近的左右2點(diǎn)圖為紅色,iDifFlag是為了只涂邊緣的點(diǎn),實(shí)際用下來效果不是很好,如果有更好的算法,請(qǐng)告訴我,其中MAKECOLOR是類似COLORREF的一個(gè)宏#define MAKECOLOR(r, g, b) (0xff000000 | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff))
for (int i = iLen - 1; i >= 0; i--)

{
pdwDstBuf[i] = MAKECOLOR(0, 0, 255); //all colors fill blue, in order to set alpha blend
if ((pdwLeft[i] != pdwRight[i] && iDifFlag == 0) ||
(pdwLeft[i] == pdwRight[i] && iDifFlag == 1))

{

pdwDstBuf[i] = MAKECOLOR(255, 255, 0);
if (iDifFlag == 0)

{
//first different in one time
iDifFlag = 1;
}
else

{
iDifFlag = 0;
}

//nearby points
if (i + 1 < iLen)

{
pdwDstBuf[i + 1] = MAKECOLOR(255, 0, 0);
}
if (i - 1 >= 0)

{
pdwDstBuf[i - 1] = MAKECOLOR(255, 0, 0);
}
if (i + 2 < iLen)

{
pdwDstBuf[i + 2] = MAKECOLOR(255, 0, 0);
}
if (i - 2 >= 0)

{
pdwDstBuf[i - 2] = MAKECOLOR(255, 0, 0);
}
i -= 2;
}
}
然后呢?最后一步了,就是將比較好的位圖顯示出來,我這里用到CreateBitmap和CreatePatternBrush這2個(gè)函數(shù),然后再利用FillRect刷到窗口中,再把窗口用SetLayeredWindowAttributes設(shè)置為藍(lán)色透過,然后移動(dòng)到QQ找茬窗口上方,這樣就OK了。不過CreateBitmap要把圖片行序顛倒一下,我懶得轉(zhuǎn)2維數(shù)組,直接用偏移搞了一下,OK哈哈。
for (DWORD i = 0; i < PIC_HEIGHT / 2; i++)

{
for (DWORD j = 0; j < PIC_WIDTH; j++)

{
temp = *((DWORD*)pBuf + i * PIC_WIDTH + j);
*((DWORD*)pBuf + i * PIC_WIDTH + j) = *((DWORD*)pBuf + PIC_WIDTH * (PIC_HEIGHT - 1 - i) + j);
*((DWORD*)pBuf + PIC_WIDTH * (PIC_HEIGHT - 1 - i) + j) = temp;
}
}


cBM.CreateBitmap(PIC_WIDTH, PIC_HEIGHT, 1, 32, pBuf);
m_cBr.CreatePatternBrush(&cBM);
cBM.DeleteObject();
最后用SetWindowPos將顯示差異的窗口置為頂層窗口。效果圖如下:

目前已知的問題:區(qū)域標(biāo)示很奇怪,是算法的問題,上面我也說過了,有個(gè)flag,因?yàn)椴荒鼙WC2附圖片的點(diǎn)與點(diǎn)完全不同,所以這樣的效果也是顯而易見的。
下載:
可執(zhí)行程序 (適用于2種找茬游戲,其實(shí)就是窗口大小不同)
By greatws
posted on 2009-05-06 00:13
greatws 閱讀(4270)
評(píng)論(15) 編輯 收藏 引用