前言算法
最近有好幾個朋友都在問我找圖找色的問題,奇怪?因而乎寫了一個專門用於找圖找色的單元文件「BitmapData.pas」。在這個單元文件中我實現了從文件中導入位圖、屏幕截圖、鼠標指針截圖、在圖片上查找子圖、在圖片上查找顏色等功能。在查找過程當中能夠設定顏色變化範圍、能夠從左到右從上到下查找、也能夠從指定點向四周查找。關於這個文件的下載和使用,能夠參考本文的第四節。下面詳細說說這些功能的實現。編程
1、數據提取數組
位圖其實能夠當作是一個由象素組成的矩陣,找圖找色能夠當作是象素值的比對。不少新手在設計這類的程序時喜歡使用TBitmap.Canvas.Pixels屬性,這個屬性實際上是對API函數GetPixel的封裝,這個函數執行速度是很慢的,主要用來對位圖象素進行偶爾的訪問。而比對過程當中須要對象素進行頻繁的訪問,形成程序運行緩慢。另一種方法是使用TBitmap.ScanLine屬性,利用它能夠直接訪問位圖的數據。可是這些數據和當前位圖的格式有關,主要是色深方面的問題,不一樣的色深會有不一樣格式的數據。另外比對過程當中也須要對該屬性進行頻繁的調用。因爲比對過程徹底是數據的比較,不須要進行繪製操做。因此能夠一次性將位圖的數據提取出來放置到一個緩衝區中再進行比對,這樣程序的性能會更高,也便於查找算法的實現。這時能夠調用API函數GetDIBits得到設備無關位圖的RGB數據,其實ScanLine屬性也是調用這個函數實現的。GetDIBits函數格式聲明以下:數據結構
function GetDIBits(
DC: HDC; //設備上下文句柄;
Bitmap: HBitmap; //位圖句柄,注意不是TBitmap對象;
StartScan, //開始檢索的第一條掃描線;
NumScans: UINT; //共檢索的掃描線數;
Bits: Pointer; //數據緩衝區指針;
var BitInfo: TBitmapInfo; //位圖信息結構,此結構肯定了設備無關位圖的數據格式;
Usage: UINT //指定TBitmapInfo結構的bmiColors成員的格式。
): Integer; stdcall;ide
其中TBitmapInfo結構的格式以下:函數
tagBITMAPINFO = packed record
bmiHeader: TBitmapInfoHeader; //位圖信息頭,該結構用於說明位圖的格式;
bmiColors: array[0..0] of TRGBQuad; //顏色表,給出調色板數據。
end;性能
在上述結構中主要使用bmiHeader成員,TBitmapInfoHeader結構的格式以下:測試
tagBITMAPINFOHEADER = packed record
biSize: DWORD; //當前結構的大小;
biWidth: Longint; //以像素爲單位,給出該結構所描述位圖的寬度;
biHeight: Longint; //以像素爲單位,給出該結構所描述位圖的高度;
biPlanes: Word; //目標設備的平面數,必須爲1;
biBitCount: Word; //每一個像素所須要的位數,當圖像爲真彩色時,該成員的取值爲24;
biCompression: DWORD; //位圖的壓縮類型,若該成員的取值爲BI_RGB,則圖像數據沒有通過壓縮處理;
biSizeImage: DWORD; //以字節爲單位,給出圖像數據的大小,若圖像爲BI_RGB位圖,則該成員的值必須設爲0;
biXPelsPerMeter: Longint; //以每米像素數爲單位,給出位圖水平方向的分辨率;
biYPelsPerMeter: Longint; //以每米像素數爲單位,給出位圖垂直方向的分辨率;
biClrUsed: DWORD; //位圖實際使用的顏色表中的顏色變址數;
biClrImportant: DWORD; //位圖顯示過程當中重要顏色的變址數。
end;動畫
在上面兩個結構中,bmiColours成員指向一個顏色表,它包含多少個表項是由bmiHeader.biBitCount成員定義。當該成員的取值爲24時,則顏色表中的表項爲空。當biBitCount取值24同時biCompression取值BI_RGB時表示當前位圖爲24位真彩色無壓縮位圖。這時能夠將位圖數據緩衝區當作是一個一維的字節數組。其中每3個字節表明1個像素。這3個字節以藍(B)、綠(G)、紅(R)爲順序,直接定義了像素顏色。這裏要注意一個字節順序,通常咱們使用的TColor顏色格式是以紅(R)、綠(G)、藍(B)爲順序的RGB顏色,而緩衝區中使用的是順序相反的BGR顏色。另外利用GetDIBits提取的位圖數據是自下而上從左到右保存到緩衝區中的,即先保存位圖最後一行從左到右的象素數據,再保存倒數第二行的數據,以此類推第一行最後保存。除了數據反相保存外,每行數據都以4字節(32位)對齊,一行數據的長度不能被4整除時就在每行的末尾填充值爲0的字節使之能被4整除。例如:對於寬5象素的位圖每行數據佔16個字節,前15個字節每3個字節保存1個象素顏色,最後填充1個字節。對於寬10象素的位圖每行數據佔32個字節,前30個字節每3個字節保存1個象素顏色,最後填充2個字節。spa
知道了緩衝區數據的格式,就能夠對緩衝區中的數據進行訪問。如今給出相關訪問的示範代碼:首先位圖數據緩衝區是一個一維的字節數組,那麼這個數組Bits能夠按如下代碼進行定義:
type
TByteAry = array [0..0] of Byte;
PByteAry = ^TByteAry;
var
Bits : PByteAry;
接着假設有一個位圖,高Height象素,寬Width象素。那麼對齊後每行數據長度LineWidth字節能夠用如下的代碼計算出來:
LineWidth:=(((Width*24)+31) and ($7FFFFFFF-31)) shr 3;
因而前面數組Bits的大小Size就爲:LineWidth*Height。對於任意一個象素在位圖上的位置Left,Top(二維)能夠用如下代碼換算出該象素數據在數組Bits中的位置Off(一維):
Off:=((Height-Top-1)*LineWidth)+(Left*3);
假設一個BGR格式的顏色值Color,如下代碼能夠從數組Bits的Off位置讀取一個象素顏色值:
Color:=((PInteger(@(Bits[Off])))^ and $FFFFFF);
使用GetDIBits函數後就能夠再也不使用TBitmap對象。如下的示範代碼實現對當前屏幕的全屏截圖,並將截圖後的位圖數據提取到緩衝區中返回:
procedure CopyScreen(var Bits : PByteAry; var Size : Integer);
var
Width,Height,LineWidth : Integer;
Wnd : HWND;
DC,MemDC : HDC;
Bitmap,OldBitmap : HBITMAP;
BitInfo : TBitmapInfo;
begin
//數據初始化
Width:=GetSystemMetrics(SM_CXSCREEN);
Height:=GetSystemMetrics(SM_CYSCREEN);
LineWidth:=(((Width*24)+31) and ($7FFFFFFF-31)) shr 3;
Size:=LineWidth*Height;
GetMem(Bits,Size);
//截圖
Wnd:=GetDesktopWindow();
DC:=GetWindowDC(Wnd);
MemDC:=CreateCompatibleDC(DC);
Bitmap:=CreateCompatibleBitmap(DC,Width,Height);
OldBitmap:=SelectObject(MemDC,Bitmap);
BitBlt(MemDC,0,0,Width,Height,DC,0,0,SRCCOPY);
Bitmap:=SelectObject(MemDC,OldBitmap);
//位圖信息初始化
with BitInfo.bmiHeader do
begin
biSize:=SizeOf(TBitmapInfoHeader);
biWidth:=Width;
biHeight:=Height;
biPlanes:=1;
biBitCount:=24;
biCompression:=BI_RGB;
biSizeImage:=0;
biXPelsPerMeter:=0;
biYPelsPerMeter:=0;
biClrUsed:=0;
biClrImportant:=0;
end;
//提取數據
GetDIBits(DC,Bitmap,0,Height,Pointer(Bits),BitInfo,DIB_RGB_COLORS);
DeleteDC(MemDC);
DeleteObject(Bitmap);
DeleteObject(OldBitmap);
ReleaseDC(Wnd,DC);
end;
對於標準的24位BMP位圖文件,其中的位圖數據也是以上述格式保存的。有的24位BMP文件並不標準,因此文件最好使用Windows自帶的畫圖程序保存。如下的示範代碼實現從標準的24位BMP格式文件中導入位圖數據到緩衝區中返回:
procedure LoadFile(const FileName : string; var Bits : PByteAry; var Size : Integer);
var
Stream : TFileStream;
FileHeader : TBitmapFileHeader;
InfoHeader : TBitmapInfoHeader;
LineWidth : Integer;
begin
Stream:=TFileStream.Create(FileName,fmOpenRead);
//讀取文件頭
Stream.Read(FileHeader,SizeOf(TBitmapFileHeader));
Stream.Read(InfoHeader,SizeOf(TBitmapInfoHeader));
with FileHeader,InfoHeader do
begin
//肯定圖片格式
if (bfType<>$4D42) or (biSize<>SizeOf(TBitmapInfoHeader)) or
(biBitCount<>24) or (biCompression<>BI_RGB) then
begin
Bits:=nil;
Size:=0;
exit;
end;
//數據初始化
LineWidth:=(((biWidth*24)+31) and ($7FFFFFFF-31)) shr 3;
Size:=LineWidth*biHeight;
GetMem(Bits,Size);
end;
//讀入數據
Stream.Read(Bits^,Size);
Stream.Free;
end;
綜上所述,當位圖數據提取到一個緩衝區中,找圖找色就是對這個緩衝區中的數據進行訪問的過程。而這個緩衝區能夠做爲一個矩陣來進行訪問。只要對矩陣進行遍歷就能夠實現找圖找色的算法。
2、矩陣遍歷
矩陣遍歷是一個數據結構方面的問題。假設有一個矩陣Matrix,它共有RowCount行,每行有ColCount列,當利用y表示行數,x表示列數,那麼利用Matrix[y,x]就能夠訪問矩陣中的任意元素。假設有一個10×10大小的矩陣,它的遍歷方法有如下三種:
在上圖中矩陣中的數字表示遍歷到元素的前後次序,箭頭表示遍歷的方向。第一種的通常遍歷法在不少編程書上都有介紹,並且常常做爲循環代碼的示範程序使用。這種遍歷方法稍加修改就能夠作到從右上角開始、從左下角開始、從右下角開始。這種遍歷方法很簡單,這裏就很少說了。與通常遍歷相反,螺旋遍歷在全部的編程書和數據結構書上都沒有講到。如今詳細的說明一下螺旋遍歷。
螺旋遍歷能夠作到以一個基點爲中心向四周遍歷,這個基點能夠不是矩陣的中心點,實際上基點能夠是矩陣上的任意一點,甚至能夠是矩陣外的點。注意:這裏所說的「點」是指能夠用(y,x)訪問的元素,當(y,x)座標超出矩陣範圍,例如(-1,-1),這就是矩陣外的點。能夠看出螺旋遍歷對於找圖找色很是有用。螺旋遍歷實現起來並不難,仔細觀察圖1中的螺旋遍歷就會發現遍歷能夠由遍歷方向和遍歷步數組成。從(3,2)點開始向上遍歷一步,再向右遍歷一步,再向下遍歷二步,再向左遍歷二步,這時完成一輪,遍歷方向又開始向上、向右、向下、向左一輪又一輪,同時遍歷步數逐步加大。當向上遍歷時y老是減1;當向右遍歷時x老是加1;當向下遍歷時y老是加1;當向左遍歷時x老是減1,這樣能夠根據遍歷方向計算出座標的變化。另外螺旋遍歷有可能會訪問到矩陣外的點,在訪問時要進行判斷。正是因爲螺旋遍歷會訪問矩陣外的點,遍歷循環將沒法中止從而出現死循環。這時要設定一個訪問計數VisitCount,當遍歷循環訪問了矩陣中的全部點後退出循環。綜上所述,螺旋遍歷的示範代碼以下:
type
//遍歷方向
TAspect = (asLeft, asRight, asUp, asDown);
const
//移動座標差
MoveVal : array [asLeft..asDown] of TPoint = (
(X : -1; Y : 0), //asLeft
(X : 1; Y : 0), //asRight
(X : 0; Y : -1), //asUp
(X : 0; Y : 1) //asDown
);
//矩陣大小
RowCount = 10;
ColCount = 10;
var
//矩陣
Matrix : array [0..RowCount-1,0..ColCount-1] of Integer;
//螺旋遍歷(不支持步長)
procedure MatrixOrder1_(y,x : Integer);
var
Aspect : TAspect;
VisitCount,Count,i : Integer;
begin
VisitCount:=0;
Aspect:=asUp;
Count:=1;
while VisitCount<(RowCount*ColCount) do
begin
for i:=0 to Count-1 do
begin
if (x>=0) and (x<ColCount) and
(y>=0) and (y<RowCount) then
begin
//訪問矩陣元素
Matrix[y,x]:=VisitCount;
VisitCount:=VisitCount+1;
end;
x:=x+MoveVal[Aspect].X;
y:=y+MoveVal[Aspect].Y;
end;
case Aspect of
asLeft : begin Aspect:=asUp; Count:=Count+1; end;
asRight : begin Aspect:=asDown; Count:=Count+1; end;
asUp : begin Aspect:=asRight; end;
asDown : begin Aspect:=asLeft; end;
end;
end;
end;
這裏還有一個步長的問題,所謂步長就是指在遍歷的時候跳過一些點,只平均訪問矩陣中的某些點。例如如下數據就是步長爲2以(3,2)爲基點的螺旋遍歷後的矩陣,其中「-」表示遍歷時沒有訪問到的點。
輸出矩陣:
+ 0 1 2 3 4 5 6 7 8 9
0 : - - - - - - - - - -
1 : 8 - 1 - 2 - 9 - 16 -
2 : - - - - - - - - - -
3 : 7 - 0 - 3 - 10 - 17 -
4 : - - - - - - - - - -
5 : 6 - 5 - 4 - 11 - 18 -
6 : - - - - - - - - - -
7 : 15 - 14 - 13 - 12 - 19 -
8 : - - - - - - - - - -
9 : 24 - 23 - 22 - 21 - 20 -
使用步長能夠實現矩陣的抽樣查找,但上面給出的螺旋遍歷算法卻不支持步長。由於它要利用訪問計數退出循環,使用步長時會使矩陣中訪問到的點的數目不肯定,使的上述算法出現死循環。對上述算法的一個改進是使用一個邏輯變量記錄遍歷一輪是否有訪問到點。若是沒有,說明這一輪訪問已經以位於矩陣以外能夠退出循環。當步長爲1時這種改進的算法要比前面的算法更慢,由於它要「空轉」一輪。並且這種算法也不支持矩陣外的點做爲基點,它會使循環提早退出。支持步長的螺旋遍歷算法的示範代碼以下:注意這時的VisitCount僅做爲測試使用,不做爲退出循環的條件。
type
//遍歷方向
TAspect = (asLeft, asRight, asUp, asDown);
const
//遍歷步長
Interval = 2;
//移動座標差
MoveVal : array [asLeft..asDown] of TPoint = (
(X : -Interval; Y : 0), //asLeft
(X : Interval; Y : 0), //asRight
(X : 0; Y : -Interval), //asUp
(X : 0; Y : Interval) //asDown
);
//矩陣大小
RowCount = 10;
ColCount = 10;
var
//矩陣
Matrix : array [0..RowCount-1,0..ColCount-1] of Integer;
//螺旋遍歷2(支持步長)
procedure MatrixOrder2(y,x : Integer);
var
Aspect : TAspect;
VisitCount : Integer; //訪問計數,測試用
Count,i : Integer;
Visit : Boolean;
begin
VisitCount:=0; //訪問計數,測試用
Visit:=false;
Aspect:=asUp;
Count:=1;
while true do
begin
for i:=0 to Count-1 do
begin
if (x>=0) and (x<ColCount) and
(y>=0) and (y<RowCount) then
begin
//訪問矩陣元素
Matrix[y,x]:=VisitCount;
VisitCount:=VisitCount+1; //訪問計數,測試用
Visit:=true;
end;
x:=x+MoveVal[Aspect].X;
y:=y+MoveVal[Aspect].Y;
end;
case Aspect of
asLeft : begin
if not Visit then break;
Visit:=false;
Aspect:=asUp;
Count:=Count+1;
end;
asRight : begin Aspect:=asDown; Count:=Count+1; end;
asUp : begin Aspect:=asRight; end;
asDown : begin Aspect:=asLeft; end;
end;
end;
end;
對於回形遍歷與螺旋遍歷大同小異,這裏就很少說了。在下面的壓縮包中是矩陣遍歷的示範程序,裏面有通常遍歷、螺旋遍歷和回形遍歷的示範代碼,能夠用於參考。
項目文件:
點擊瀏覽該文件
3、找圖找色
結合本文第一節和第二節的內容設計一個找圖找色的程序應該不是問題。對於一個位圖能夠當作是由象素組成的矩陣,Top至關於y,Left至關於x,利用(Top,Left)能夠象訪問矩陣元素同樣訪問位圖上的象素。查找過程就是對位圖象素的遍歷。相關的代碼在BitmapData.pas文件中都有,這裏就不重複了。在BitmapData.pas文件中我實現的查找過程主要仍是一對一的比對,這是一種較慢的匹配算法。對於一些字符串匹配算法,在查找過程當中能夠在匹配失敗時跳過一些字符從而加快查找的速度。在矩陣查找中也有相似的算法,但我沒有找到比較好的算法,因此在實現上仍是採用了一對一的比對。這就意味着查找過程的速度還有提高的可能,雖然如今的查找速度已是能夠接受的。
另外還有一個問題:在屏幕或大圖上查找一個位圖,這個位圖能夠被稱爲子圖。採用顏色比較算法能夠容許子圖出現必定的顏色誤差,這不會影響查找結果。可是這種比較算法卻不容許子圖出現扭曲或旋轉,只要子圖出現輕微的扭曲或旋轉都沒法查找到。若是要容許子圖出現扭曲或旋轉就要用到複雜的圖形圖象分析算法。因爲圖形圖象分析算法太複雜,我也沒有作太深的研究,因此在BitmapData.pas中我只實現了簡單的子圖查找
4、BitmapData.pas的使用
項目文件:
點擊瀏覽該文件
(注:以上壓縮包中的BitmapData.pas文件有個小BGU,主要是截取鼠標指針的圖片時沒有考慮當前的背景顏色,始終爲黑色。在本貼三樓的壓縮包中有更新後的BitmapData.pas文件下載。)
在上面的壓縮包中是BitmapData.pas使用的示範程序,BitmapData.pas文件能夠從壓縮包中得到。在BitmapData.pas文件中我將位圖數據封裝成了類TBDBitmapData,以便於使用。另外我編寫一系列的函數用以BGR格式顏色的構建、轉換、模糊比較。注意在BitmapData.pas文件中我定義了一些常量,這些常量只是爲了增長程序的可讀性,修改這些常量不會修改程序支持數據的格式,只會使程序運行錯誤。BitmapData.pas文件的詳細說明以下:
一、function BGR(B,G,R : Byte): TBDColor;
根據藍(B)、綠(G)、紅(R)三個通道的值生成一個BGR格式顏色。
二、function RGBtoBGR(C : TColor): TBDColor;
將一個RGB顏色格式轉換到BGR顏色格式。
三、function BGRtoRGB(C : TBDColor): TColor;
將一個BGR顏色格式轉換到RGB顏色格式。
四、function BDCompareColor(C1,C2 : TBDColor; const Range : TBDColorRange): Boolean;
根據顏色範圍Range比較顏色C1和C2,返回C1和C2是否類似。C1和C2是BGR格式的顏色,Range是顏色的變化範圍。TBDColorRange的定義以下:
TBDColorRange = record
R : Integer;
G : Integer;
B : Integer;
end;
其中,R表示C1和C2中紅色通道最大的相差值;G表示C1和C2中綠色通道最大的相差值;B表示C1和C2中藍色通道最大的相差值。
示範程序,比較兩個顏色:
var
C1,C2 : TBDColor;
Range : TBDColorRange;
begin
Range.R:=5;
Range.G:=5;
Range.B:=5;
C1:=BGR(125,125,125);
C2:=BGR(120,120,120);
BDCompareColor(C1,C2,Range); //成功
C1:=BGR(125,120,125);
C2:=BGR(120,120,120);
BDCompareColor(C1,C2,Range); //成功
C1:=BGR(125,200,125);
C2:=BGR(120,120,120);
BDCompareColor(C1,C2,Range); //失敗
end;
五、constructor TBDBitmapData.Create(const AName : String);
新建一個TBDBitmapData對象的實例。能夠爲實例指定一個名字,便於之後的管理。
六、procedure TBDBitmapData.Clear;
清除當前TBDBitmapData對象中加載的位圖數據。
七、function TBDBitmapData.LoadFromStream(Stream : TStream; ABackColor : TBDColor): Boolean;
從數據流Stream中導入位圖數據,返回是否成功。若是失敗將設置Error成員說明狀況。數據流中的數據必需是24位BMP格式文件數據。利用ABackColor能夠設定圖片的背景顏色,該參數能夠省略,省略時表示圖片不使用背景顏色。
八、function TBDBitmapData.SaveToStream(Stream : TStream):Boolean;
將當前加載的位圖數據導出到數據流Stream中,返回是否成功。若是失敗將設置Error成員說明狀況。數據將按24位BMP文件數據格式導出到數據流中。
九、function TBDBitmapData.LoadFromFile(const FileName : string; ABackColor : TBDColor): Boolean;
從文件FileName中導入位圖數據,返回是否成功。若是失敗將設置Error成員說明狀況。文件必需是24位BMP格式文件。利用ABackColor能夠設定圖片的背景顏色,該參數能夠省略,省略時表示圖片不使用背景顏色。
十、function TBDBitmapData.SaveToFile(const FileName : string): Boolean;
將當前加載的位圖數據導出到文件中,返回是否成功。若是失敗將設置Error成員說明狀況。數據按24位BMP文件數據格式導出到文件中。
十一、function TBDBitmapData.LoadFromBitmap(Bitmap : TBitmap): Boolean;
從一個TBitmap對象中導入數據,返回是否成功。若是失敗將設置Error成員說明狀況。導入時圖片的背景顏色由Bitmap.Transparent和Bitmap.TransparentColor決定。
十二、function TBDBitmapData.SaveToBitmap(Bitmap : TBitmap): Boolean;
將當前的位圖數據導出到一個TBitmap對象中,返回是否成功。若是失敗將設置Error成員說明狀況。導出時將根據當前的背景顏色設置Bitmap.Transparent和Bitmap.TransparentColor成員。利用LoadFromBitmap和SaveToBitmap兩個函數能夠實現TBDBitmapData對象和TBitmap對象的相互轉換。
1三、function TBDBitmapData.CopyFormScreen(Left,Top,AWidth,AHeight : Integer): Boolean;
從屏幕上的指定範圍中截圖,並導入數據,返回是否成功。若是失敗將設置Error成員說明狀況。Left爲截圖的左邊距,可省略,默認爲0;Top爲截圖的頂邊距,可省略,默認爲0;AWidth爲截圖的寬度,可省略,默認爲從Left到屏幕右邊的寬度;AHeight爲截圖的高度,可省略,默認爲從Top到屏幕底邊的高度。
1四、function TBDBitmapData.CopyFormCursor: Boolean;
截取鼠標當前指針的圖片,並導入數據,返回是否成功。若是失敗將設置Error成員說明狀況。若是鼠標指針是動畫指針,默認截取第一幀畫面。截取時會使用當前背景顏色填充背景,若是沒有指定背景顏色則使用白色(RGB(255,255,255))填充。
1五、function TBDBitmapData.Compare(Bmp : TBDBitmapData; Left,Top : Integer): Boolean;
1六、function TBDBitmapData.Compare(Bmp : TBDBitmapData; const Range : TBDColorRange; Left,Top : Integer): Boolean;
重載的兩個函數,用於在當前位圖的指定位置比較Bmp指定的位圖,返回是否一致。不管比較是否一致都不會修改Error成員。第一個函數用於精確比較,第二個函數用於模糊比較。Bmp指定的位圖面幅要小於等於當前位圖的面幅,Bmp指定的位圖不能超出當前位圖,不然比較失敗。Bmp爲指定的位圖數據;Left爲比較時的左邊距,可省略,默認爲0;Top爲比較時的頂邊距,可省略,默認爲0;Range爲顏色變化範圍。
1七、function TBDBitmapData.FindImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean;
1八、function TBDBitmapData.FindImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean;
重載的兩個函數,從當前位圖中查找與Bmp一致的子圖,返回是否找到。不管是否找到都不會修改Error成員。第一個函數用於精確比較,第二個函數用於模糊比較。查找時忽略Left和Top的設置,從當前位圖的左上角開始按從左到右,從上到下的順序查找。找到返回true,設置Left和Top爲找到子圖的位置;沒找到返回false,設置Left和Top爲-1。Bmp爲指定的子圖數據;Left爲找到子圖的左邊距;Top爲找到子圖的頂邊距;Range爲顏色變化範圍。
示範程序,在屏幕上查找子圖:
var
Bit1,Bit2 : TBDBitmapData;
Left,Top : Integer;
begin
Bit1:=TBDBitmapData.Create;
Bit2:=TBDBitmapData.Create;
Bit1.CopyFormScreen;
Bit2.LoadFromFile('文件名');
if Bit1.FindImage(Bit2,Left,Top) then
begin
{已找到子圖,進行相應的處理...}
end;
Bit1.Free;
Bit2.Free;
end;
1九、function TBDBitmapData.FindCenterImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean;
20、function TBDBitmapData.FindCenterImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean;
重載的兩個函數,從當前位圖中查找與Bmp一致的子圖,返回是否找到。不管是否找到都不會修改Error成員。第一個函數用於精確比較,第二個函數用於模糊比較。查找時以Left和Top的設置爲基點,從中心向四周查找。找到返回true,設置Left和Top爲找到子圖的位置;沒找到返回false,設置Left和Top爲-1。Bmp爲指定的子圖數據;Left爲找到子圖的左邊距;Top爲找到子圖的頂邊距;Range爲顏色變化範圍。
2一、function TBDBitmapData.EnumImage(Bmp : TBDBitmapData; EnumImageProc : TBDEnumImageProc; lParam : Integer): Boolean;
2二、function TBDBitmapData.EnumImage(Bmp : TBDBitmapData; const Range : TBDColorRange; EnumImageProc : TBDEnumImageProc; lParam : Integer): Boolean;
重載的兩個函數,從當前位圖中查找全部與Bmp一致的子圖,即枚舉位圖,返回是否找到。不管是否找到都不會修改Error成員。第一個函數用於精確比較,第二個函數用於模糊比較。查找時從當前位圖的左上角開始按從左到右,從上到下的順序查找。每當查找到一個子圖,就調用回調函數EnumImageProc,若是EnumImageProc返回false就中止查找,結束函數。Bmp爲子圖數據;EnumImageProc爲回調函數;lParam爲調用回調函數時發出的參數,可省略,默認爲0;Range爲顏色變化範圍。TBDEnumImageProc的聲明格式以下:
TBDEnumImageProc = function (Left,Top : Integer; Bmp : TBDBitmapData; lParam : Integer): Boolean;
其中,Left爲找到子圖的左邊距;Top爲找到子圖的頂邊距;Bmp爲調用EnumImage時給出的查找子圖數據;lParam爲調用EnumImage時給出的設置參數。該函數的返回值表示是否繼續枚舉。
2三、function TBDBitmapData.FindColor(Color : TBDColor; var Left,Top : Integer): Boolean;
2四、function TBDBitmapData.FindColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean;
重載的兩個函數,從當前位圖中查找指定的顏色,忽略當前位圖背景顏色BackColor的設置,返回是否找到。不管是否找到都不會修改Error成員。第一個函數用於精確比較,第二個函數用於模糊比較。查找時忽略Left和Top的設置,從當前位圖的左上角開始按從左到右,從上到下的順序查找。找到返回true,設置Left和Top爲找到顏色的位置,沒找到返回false,設置Left和Top爲-1。Color爲BGR格式顏色;Left爲找到顏色的左邊距;Top爲找到顏色的頂邊距;Range爲顏色變化範圍。
2五、function TBDBitmapData.FindCenterColor(Color : TBDColor; var Left,Top : Integer): Boolean;
2六、function TBDBitmapData.FindCenterColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean;
重載的兩個函數,從當前位圖中查找指定的顏色,忽略當前位圖背景顏色BackColor的設置,返回是否找到。不管是否找到都不會修改Error成員。第一個函數用於精確比較,第二個函數用於模糊比較。查找時以Left和Top的設置爲基點,從中心向四周查找。找到返回true,設置Left和Top爲找到顏色的位置,沒找到返回false,設置Left和Top爲-1。Color爲BGR格式顏色;Left爲找到顏色的左邊距;Top爲找到顏色的頂邊距;Range爲顏色變化範圍。
示範程序,在屏幕上以某點爲中心向四周模糊查找顏色:
var
Bit : TBDBitmapData;
Range : TBDColorRange;
Left,Top : Integer;
begin
Bit:=TBDBitmapData.Create;
Bit.CopyFormScreen;
Range.R:=5;
Range.G:=5;
Range.B:=5;
Left:=600;
Top:=380;
if Bit.FindCenterColor(BGR(0,250,250),Range,Left,Top) then
begin
{已找到顏色,進行相應的處理...}
end;
Bit.Free;
end;
2七、function TBDBitmapData.EnumColor(Color : TBDColor; EnumColorProc : TBDEnumColorProc; lParam : Integer): Boolean;
2八、function TBDBitmapData.EnumColor(Color : TBDColor; const Range : TBDColorRange; EnumColorProc : TBDEnumColorProc; lParam : Integer): Boolean;
重載的兩個函數,從當前圖片中查找全部指定的顏色,即枚舉顏色,忽略當前位圖背景顏色BackColor的設置,返回是否找到。不管是否找到都不會修改Error成員。第一個函數用於精確比較,第二個函數用於模糊比較。查找時從當前位圖的左上角開始按從左到右,從上到下的順序查找。每找到一個顏色,就調用回調函數EnumColorProc,若是EnumColorProc返回false就中止查找,結束函數。Color爲BGR格式顏色;EnumColorProc爲回調函數;lParam爲調用回調函數時發出的參數,可省略,默認爲0;Range爲顏色變化範圍。TBDEnumColorProc的聲明格式以下:
TBDEnumColorProc = function (Left,Top : Integer; Color : TBDColor; lParam : Integer): Boolean;
其中,Left爲找到顏色的左邊距;Top爲找到顏色的頂邊距;Color爲找到的顏色,當使用模糊查找時該顏色爲實際找到的顏色;lParam爲調用EnumColor時給出的設置參數。該函數的返回值表示是否繼續枚舉。
2九、TBDBitmapData.Error
最近一次操做出現的錯誤的說明。出於性能方面的考慮,只有導入、導出、截圖等操做纔會修改這個成員。而查找、枚舉等操做不管是否成功都不會修改這個成員。
30、TBDBitmapData.Name
當前位圖的名稱,可讀寫。方便位圖數據的管理。
3一、TBDBitmapData.Width
當前位圖寬度,以象素爲單位,只讀。
3二、TBDBitmapData.Height
當前位圖高度,以象素爲單位,只讀。
3三、TBDBitmapData.BackColor
當前位圖的背景顏色,BGR格式的顏色,可讀寫。當該顏色爲BD_COLORLESS時,表示該位圖不使用背景顏色。
3四、TBDBitmapData.LineWidth
對齊後每行位圖數據的寬度,以字節爲單位,只讀。
3五、TBDBitmapData.SpareWidth
對齊後每行位圖數據填充的多餘寬度,以字節爲單位,只讀。
3六、TBDBitmapData.Size
位圖數據的長度,以字節爲單位,只讀。
3七、TBDBitmapData.Bits
位圖數據緩衝區指針,只讀。這個指針是隻讀的,但它指向的數據是可讀寫的。能夠將這個屬性當作是一個一維的字節數組,能夠對緩衝區中的數據進行訪問和修改。
3八、TBDBitmapData.Pixels[Left,Top : Integer]
位圖的象素顏色,BGR格式的顏色,可讀寫。利用這個屬性能夠將位圖當作是一個二維的象素矩陣,能夠對矩陣中的象素顏色進行訪問和修改。
示範代碼,位圖數據的訪問:
var
Bit : TBDBitmapData;
begin
Bit:=TBDBitmapData.Create;
Bit.CopyFormScreen;
Bit.Bits[50]; //以Byte格式訪問
Bit.Pixels[10,10]; //以BGR顏色格式訪問
Bit[10,10]; //等同於Bit.Pixels[10,10];
Bit.Free;
end;
文件下載:http://files.cnblogs.com/rogee/BitMap%5bNOBUG%5d.zip
1 unit BitmapData; 2 3 // 4 //位圖數據處理,主要用於位圖的找圖找色 5 //做者:yeye55 2009年5月31日 6 // 7 //版權 2009,由 yeye55 擁有,保留全部權利。 8 //本文件中的代碼是免費程序,無需任何受權或許可便可用於我的和商業目的。使用者一切後果自負。 9 // 10 //若是你轉載了本文件中的代碼,請註明代碼出處和代碼做者; 11 //若是你修改了本文件中的代碼,請註明修改位置和修改做者。 12 // 13 //本文件最先在http://www.programbbs.com/bbs/上發佈 14 // 15 16 interface 17 18 uses 19 Windows, Classes, SysUtils, Graphics; 20 21 const 22 BD_COLORLESS = -1; //無色 23 BD_BITCOUNT = 24; //圖象位數 24 BD_BYTECOUNT = BD_BITCOUNT shr 3; //每象素佔用字節數 25 BD_LINEWIDTH = 32; //每行數據對齊寬度(位) 26 27 type 28 //字節數組 29 TByteAry = array [0..0] of Byte; 30 PByteAry = ^TByteAry; 31 32 //顏色變化範圍,R、G、B三個通道的絕對差值 33 TBDColorRange = record 34 R : Integer; 35 G : Integer; 36 B : Integer; 37 end; 38 39 TBDColor = Integer; //BGR格式顏色 40 41 //轉換函數 42 function BGR(B,G,R : Byte): TBDColor; 43 function RGBtoBGR(C : TColor): TBDColor; 44 function BGRtoRGB(C : TBDColor): TColor; 45 //比較顏色 46 function BDCompareColor(C1,C2 : TBDColor; const Range : TBDColorRange): Boolean; 47 48 type 49 TBDBitmapData = class; //位圖數據 50 51 //枚舉子圖回調函數,查找多個子圖時回調,返回是否繼續枚舉, 52 //Left:找到子圖的左邊距; 53 //Top:找到子圖的頂邊距; 54 //Bmp:找到子圖數據; 55 //lParam:調用時設置的參數。 56 TBDEnumImageProc = function (Left,Top : Integer; Bmp : TBDBitmapData; lParam : Integer): Boolean; 57 58 //枚舉顏色回調函數,查找多個顏色時回調,返回是否繼續枚舉, 59 //Left:找到顏色的左邊距; 60 //Top:找到顏色的頂邊距; 61 //Color:找到的顏色; 62 //lParam:調用時設置的參數。 63 TBDEnumColorProc = function (Left,Top : Integer; Color : TBDColor; lParam : Integer): Boolean; 64 65 //位圖數據 66 TBDBitmapData = class 67 private 68 FName : String; //位圖名稱 69 FWidth : Integer; //位圖寬度(象素) 70 FHeight : Integer; //位圖高度(象素) 71 FBackColor : TBDColor; //背景顏色(BGR格式) 72 FLineWidth : Integer; //對齊後每行數據寬度(字節) 73 FSpareWidth : Integer; //對齊後每行數據多餘寬度(字節) 74 FSize : Integer; //位圖數據長度 75 FBufSize : Integer; //緩衝區實際長度 76 FBits : PByteAry; //位圖數據緩衝區 77 function InitData(AWidth,AHeight : Integer): Boolean; 78 function GetPixels(Left,Top : Integer): TBDColor; 79 procedure SetPixels(Left,Top : Integer; Value : TBDColor); 80 public 81 Error : String; 82 constructor Create(const AName : String = ''); 83 destructor Destroy; override; 84 procedure Clear; 85 function LoadFromStream(Stream : TStream; ABackColor : TBDColor = BD_COLORLESS): Boolean; 86 function SaveToStream(Stream : TStream):Boolean; 87 function LoadFromFile(const FileName : string; ABackColor : TBDColor = BD_COLORLESS): Boolean; 88 function SaveToFile(const FileName : string): Boolean; 89 function LoadFromBitmap(Bitmap : TBitmap): Boolean; 90 function SaveToBitmap(Bitmap : TBitmap): Boolean; 91 function CopyFormScreen(Left : Integer = -1; Top : Integer = -1; AWidth : Integer = -1; AHeight : Integer = -1): Boolean; 92 function CopyFormCursor: Boolean; 93 function Compare(Bmp : TBDBitmapData; Left : Integer = 0; Top : Integer = 0): Boolean; overload; 94 function Compare(Bmp : TBDBitmapData; const Range : TBDColorRange; Left : Integer = 0; Top : Integer = 0): Boolean; overload; 95 function FindImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean; overload; 96 function FindImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean; overload; 97 function FindCenterImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean; overload; 98 function FindCenterImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean; overload; 99 function EnumImage(Bmp : TBDBitmapData; EnumImageProc : TBDEnumImageProc; lParam : Integer = 0): Boolean; overload; 100 function EnumImage(Bmp : TBDBitmapData; const Range : TBDColorRange; EnumImageProc : TBDEnumImageProc; lParam : Integer = 0): Boolean; overload; 101 function FindColor(Color : TBDColor; var Left,Top : Integer): Boolean; overload; 102 function FindColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean; overload; 103 function FindCenterColor(Color : TBDColor; var Left,Top : Integer): Boolean; overload; 104 function FindCenterColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean; overload; 105 function EnumColor(Color : TBDColor; EnumColorProc : TBDEnumColorProc; lParam : Integer = 0): Boolean; overload; 106 function EnumColor(Color : TBDColor; const Range : TBDColorRange; EnumColorProc : TBDEnumColorProc; lParam : Integer = 0): Boolean; overload; 107 property Name : String read FName write FName; //位圖名稱 108 property Width : Integer read FWidth; //位圖寬度(象素) 109 property Height : Integer read FHeight; //位圖高度(象素) 110 property BackColor : TBDColor read FBackColor write FBackColor; //背景顏色(BGR格式) 111 property LineWidth : Integer read FLineWidth; //對齊後每行數據寬度(字節) 112 property SpareWidth : Integer read FSpareWidth; //對齊後每行數據多餘寬度(字節) 113 property Size : Integer read FSize; //位圖數據長度 114 property Bits : PByteAry read FBits; //位圖數據緩衝區 115 property Pixels[Left,Top : Integer] : TBDColor read GetPixels write SetPixels; default; 116 end; 117 118 implementation 119 120 type 121 //矩陣遍歷方向 122 TAspect = (asLeft, asRight, asUp, asDown); 123 124 const 125 //移動座標差,用於矩陣遍歷 126 MoveVal : array [asLeft..asDown] of TPoint = ( 127 (X : -1; Y : 0), //asLeft 128 (X : 1; Y : 0), //asRight 129 (X : 0; Y : -1), //asUp 130 (X : 0; Y : 1) //asDown 131 ); 132 133 var 134 ScreenWidth : Integer; 135 ScreenHeight : Integer; 136 IconWidth : Integer; 137 IconHeight : Integer; 138 139 //根據B、G、R三個通道的值生成一個BGR格式顏色。 140 function BGR(B,G,R : Byte): TBDColor; 141 begin 142 result:=(B or (G shl 8) or (R shl 16)); 143 end; 144 145 //RGB顏色格式轉換到BGR顏色格式。 146 function RGBtoBGR(C : TColor): TBDColor; 147 begin 148 result:=((C and $FF0000) shr 16) or (C and $00FF00) or ((C and $0000FF) shl 16); 149 end; 150 151 //BGR顏色格式轉換到RGB顏色格式。 152 function BGRtoRGB(C : TBDColor): TColor; 153 begin 154 result:=((C and $FF0000) shr 16) or (C and $00FF00) or ((C and $0000FF) shl 16); 155 end; 156 157 //根據顏色範圍Range比較顏色C1和C2,返回C1和C2是否類似, 158 //C1,C2:BGR格式顏色; 159 //Range:爲顏色變化範圍。 160 function BDCompareColor(C1,C2 : TBDColor; const Range : TBDColorRange): Boolean; 161 var 162 C : Integer; 163 begin 164 result:=false; 165 //B 166 C:=(C1 and $FF)-(C2 and $FF); 167 if (C>Range.B) or (C<-Range.B) then exit; 168 //G 169 C:=((C1 and $FF00) shr 8)-((C2 and $FF00) shr 8); 170 if (C>Range.G) or (C<-Range.G) then exit; 171 //R 172 C:=((C1 and $FF0000) shr 16)-((C2 and $FF0000) shr 16); 173 if (C>Range.R) or (C<-Range.R) then exit; 174 // 175 result:=true; 176 end; 177 178 {TBDBitmapData} //位圖數據 179 180 constructor TBDBitmapData.Create(const AName : String); 181 begin 182 self.FName:=AName; 183 self.FWidth:=0; 184 self.FHeight:=0; 185 self.FBackColor:=BD_COLORLESS; 186 self.FLineWidth:=0; 187 self.FSize:=0; 188 self.FBufSize:=0; 189 self.FBits:=nil; 190 self.Error:=''; 191 end; 192 193 destructor TBDBitmapData.Destroy; 194 begin 195 self.Clear; 196 end; 197 198 //根據當前的AWidth和AHeight初始化數據,分配內存,返回是否成功, 199 //若是失敗將設置self.Error說明狀況, 200 //AWidth:位圖的寬度; 201 //AHeight:位圖的高度。 202 function TBDBitmapData.InitData(AWidth,AHeight : Integer): Boolean; 203 var 204 Align : Integer; 205 begin 206 self.Error:=''; 207 result:=true; 208 if (self.FWidth=AWidth) and 209 (self.FHeight=AHeight) then exit; 210 //計算對齊後的每行數據寬度 211 self.FWidth:=AWidth; 212 self.FHeight:=AHeight; 213 Align:=BD_LINEWIDTH-1; 214 self.FLineWidth:=(((self.FWidth*BD_BITCOUNT)+Align) and ($7FFFFFFF-Align)) shr 3; 215 self.FSpareWidth:=self.FLineWidth-(self.FWidth*BD_BYTECOUNT); 216 self.FSize:=self.FLineWidth*self.FHeight; 217 //分配內存 218 if self.FSize<=self.FBufSize then exit; 219 if self.FBits<>nil then FreeMem(self.FBits); 220 try 221 GetMem(self.FBits,self.FSize); 222 except 223 on EOutOfMemory do begin 224 self.FSize:=0; 225 self.FBufSize:=0; 226 self.FBits:=nil; 227 self.Error:='內存不足!'; 228 result:=false; 229 exit; 230 end; 231 end; 232 self.FBufSize:=self.FSize; 233 end; 234 235 //獲取指定位置象素的顏色值, 236 //Left:象素的左邊距; 237 //Top:象素的頂邊距。 238 function TBDBitmapData.GetPixels(Left,Top : Integer): TBDColor; 239 begin 240 if (Left<0) or (Left>=self.FWidth) or 241 (Top<0) or (Top>=self.FHeight) then 242 begin 243 result:=0; 244 exit; 245 end; 246 result:=((PInteger(@(self.FBits[ 247 ((self.FHeight-Top-1)*self.FLineWidth)+(Left*BD_BYTECOUNT) 248 ])))^ and $FFFFFF); 249 end; 250 251 //設置指定位置象素的顏色值, 252 //Left:象素的左邊距; 253 //Top:象素的頂邊距; 254 //Value:BGR格式顏色。 255 procedure TBDBitmapData.SetPixels(Left,Top : Integer; Value : TBDColor); 256 var 257 Off : Integer; 258 begin 259 if (Left<0) or (Left>=self.FWidth) or 260 (Top<0) or (Top>=self.FHeight) then exit; 261 Off:=((self.FHeight-Top-1)*self.FLineWidth)+(Left*BD_BYTECOUNT); 262 //B 263 self.FBits[Off]:=Byte(Value and $FF); 264 //G 265 self.FBits[Off+1]:=Byte((Value and $FF00) shr 8); 266 //R 267 self.FBits[Off+2]:=Byte((Value and $FF0000) shr 16); 268 end; 269 270 //清除當前的位圖數據。 271 procedure TBDBitmapData.Clear; 272 begin 273 self.FWidth:=0; 274 self.FHeight:=0; 275 self.FBackColor:=BD_COLORLESS; 276 self.FLineWidth:=0; 277 self.FSize:=0; 278 self.FBufSize:=0; 279 if self.FBits<>nil then 280 begin 281 FreeMem(self.FBits); 282 self.FBits:=nil; 283 end; 284 self.Error:=''; 285 end; 286 287 //從數據流中導入位圖數據,返回是否成功, 288 //若是失敗將設置self.Error說明狀況, 289 //數據流中的數據必需是24位BMP格式文件數據, 290 //Stream:數據流; 291 //ABackColor:位圖的背景顏色,可省略。 292 function TBDBitmapData.LoadFromStream(Stream : TStream; ABackColor : TBDColor): Boolean; 293 var 294 FileHeader : TBitmapFileHeader; 295 InfoHeader : TBitmapInfoHeader; 296 begin 297 if Stream=nil then 298 begin 299 self.Error:='沒有指定數據流!'; 300 result:=false; 301 exit; 302 end; 303 //讀取文件頭 304 Stream.Read(FileHeader,SizeOf(TBitmapFileHeader)); 305 Stream.Read(InfoHeader,SizeOf(TBitmapInfoHeader)); 306 with FileHeader,InfoHeader do 307 begin 308 //肯定位圖格式 309 if (bfType<>$4D42) or (biSize<>SizeOf(TBitmapInfoHeader)) or 310 (biBitCount<>BD_BITCOUNT) or (biCompression<>BI_RGB) then 311 begin 312 self.Error:='錯誤的數據格式!'; 313 result:=false; 314 exit; 315 end; 316 //數據初始化 317 self.FBackColor:=ABackColor; 318 if not self.InitData(biWidth,biHeight) then 319 begin 320 result:=false; 321 exit; 322 end; 323 end; 324 //讀入數據 325 result:=Stream.Read((self.FBits)^,self.FSize)=self.FSize; 326 if result then self.Error:='' 327 else self.Error:='讀取的數據不完整!'; 328 end; 329 330 //將當前的位圖數據導出到數據流中,返回是否成功, 331 //若是失敗將設置self.Error說明狀況, 332 //數據按24位BMP文件數據格式導出到數據流中, 333 //Stream:數據流。 334 function TBDBitmapData.SaveToStream(Stream : TStream):Boolean; 335 var 336 FileHeader : TBitmapFileHeader; 337 InfoHeader : TBitmapInfoHeader; 338 HeaderLen,n : Integer; 339 begin 340 if Stream=nil then 341 begin 342 self.Error:='沒有指定數據流!'; 343 result:=false; 344 exit; 345 end; 346 //初始化文件頭 347 HeaderLen:=SizeOf(TBitmapFileHeader)+SizeOf(TBitmapInfoHeader); 348 with FileHeader,InfoHeader do 349 begin 350 bfType:=$4D42; 351 bfSize:=self.FSize+HeaderLen; 352 bfReserved1:=0; 353 bfReserved2:=0; 354 bfOffBits:=HeaderLen; 355 biSize:=SizeOf(TBitmapInfoHeader); 356 biWidth:=self.FWidth; 357 biHeight:=self.FHeight; 358 biPlanes:=1; 359 biBitCount:=BD_BITCOUNT; 360 biCompression:=BI_RGB; 361 biSizeImage:=self.FSize; 362 biXPelsPerMeter:=$EC4; 363 biYPelsPerMeter:=$EC4; 364 biClrUsed:=0; 365 biClrImportant:=0; 366 end; 367 //寫入數據 368 n:=0; 369 n:=n+Stream.Write(FileHeader,SizeOf(TBitmapFileHeader)); 370 n:=n+Stream.Write(InfoHeader,SizeOf(TBitmapInfoHeader)); 371 n:=n+Stream.Write((self.FBits)^,self.FSize); 372 result:=n=(self.FSize+HeaderLen); 373 if result then self.Error:='' 374 else self.Error:='寫入的數據不完整!'; 375 end; 376 377 //從文件中導入位圖數據,返回是否成功, 378 //若是失敗將設置self.Error說明狀況, 379 //文件必需是24位BMP格式文件, 380 //FileName:BMP文件名; 381 //ABackColor:位圖的背景顏色,可省略。 382 function TBDBitmapData.LoadFromFile(const FileName : string; ABackColor : TBDColor): Boolean; 383 var 384 Stream : TFileStream; 385 begin 386 Stream:=TFileStream.Create(FileName,fmOpenRead); 387 result:=self.LoadFromStream(Stream,ABackColor); 388 Stream.Free; 389 end; 390 391 //將當前的位圖數據導出到文件中,返回是否成功, 392 //若是失敗將設置self.Error說明狀況, 393 //數據按24位BMP文件數據格式導出到文件中, 394 //FileName:BMP文件名。 395 function TBDBitmapData.SaveToFile(const FileName : string): Boolean; 396 var 397 Stream : TFileStream; 398 begin 399 Stream:=TFileStream.Create(FileName,fmCreate); 400 result:=self.SaveToStream(Stream); 401 Stream.Free; 402 end; 403 404 //從一個TBitmap對象中導入數據,返回是否成功,位圖的背景顏色由 405 //TBitmap.Transparent和TBitmap.TransparentColor決定, 406 //若是失敗將設置self.Error說明狀況, 407 //Bitmap:TBitmap對象。 408 function TBDBitmapData.LoadFromBitmap(Bitmap : TBitmap): Boolean; 409 var 410 Stream : TMemoryStream; 411 ABackColor : TBDColor; 412 begin 413 if Bitmap=nil then 414 begin 415 self.Error:='沒有指定位圖!'; 416 result:=false; 417 exit; 418 end; 419 if Bitmap.Transparent then 420 ABackColor:=RGBtoBGR(Bitmap.TransparentColor) 421 else 422 ABackColor:=BD_COLORLESS; 423 Stream:=TMemoryStream.Create; 424 Bitmap.SaveToStream(Stream); 425 Stream.Position:=0; 426 result:=self.LoadFromStream(Stream,ABackColor); 427 Stream.Free; 428 end; 429 430 //將當前的位圖數據導出到一個TBitmap對象中,返回是否成功,根據當前 431 //的背景顏色設置TBitmap.Transparent和TBitmap.TransparentColor成員, 432 //若是失敗將設置self.Error說明狀況, 433 //Bitmap:TBitmap對象。 434 function TBDBitmapData.SaveToBitmap(Bitmap : TBitmap): Boolean; 435 var 436 Stream : TMemoryStream; 437 begin 438 if Bitmap=nil then 439 begin 440 self.Error:='沒有指定位圖!'; 441 result:=false; 442 exit; 443 end; 444 Stream:=TMemoryStream.Create; 445 result:=self.SaveToStream(Stream); 446 if not result then 447 begin 448 Stream.Free; 449 exit; 450 end; 451 Stream.Position:=0; 452 Bitmap.LoadFromStream(Stream); 453 if self.FBackColor<>BD_COLORLESS then 454 begin 455 Bitmap.TransparentColor:=BGRtoRGB(self.FBackColor); 456 Bitmap.Transparent:=true; 457 end 458 else Bitmap.Transparent:=false; 459 Stream.Free; 460 end; 461 462 //從屏幕上的指定範圍中截圖,並導入數據,返回是否成功, 463 //若是失敗將設置self.Error說明狀況, 464 //Left:截圖的左邊距,可省略; 465 //Top:截圖的頂邊距,可省略; 466 //AWidth:截圖的寬度,可省略; 467 //AHeight:截圖的高度,可省略。 468 function TBDBitmapData.CopyFormScreen(Left,Top,AWidth,AHeight : Integer): Boolean; 469 var 470 Wnd : HWND; 471 DC,MemDC : HDC; 472 Bitmap,OldBitmap : HBITMAP; 473 BitInfo : TBitmapInfo; 474 begin 475 //參數調整 476 if (Left<0) or (Left>=ScreenWidth) then Left:=0; 477 if (Top<0) or (Top>=ScreenHeight) then Top:=0; 478 if AWidth<=0 then AWidth:=ScreenWidth-Left; 479 if AHeight<=0 then AHeight:=ScreenHeight-Top; 480 //數據初始化 481 if not self.InitData(AWidth,AHeight) then 482 begin 483 result:=false; 484 exit; 485 end; 486 //截圖 487 Wnd:=GetDesktopWindow(); 488 DC:=GetWindowDC(Wnd); 489 MemDC:=CreateCompatibleDC(DC); 490 Bitmap:=CreateCompatibleBitmap(DC,self.FWidth,self.FHeight); 491 OldBitmap:=SelectObject(MemDC,Bitmap); 492 result:=BitBlt(MemDC,0,0,self.FWidth,self.FHeight,DC,Left,Top,SRCCOPY); 493 Bitmap:=SelectObject(MemDC,OldBitmap); 494 if not result then 495 begin 496 DeleteDC(MemDC); 497 DeleteObject(Bitmap); 498 ReleaseDC(Wnd,DC); 499 self.Error:='截圖失敗!'; 500 exit; 501 end; 502 //位圖信息初始化 503 with BitInfo.bmiHeader do 504 begin 505 biSize:=SizeOf(TBitmapInfoHeader); 506 biWidth:=self.FWidth; 507 biHeight:=self.FHeight; 508 biPlanes:=1; 509 biBitCount:=BD_BITCOUNT; 510 biCompression:=BI_RGB; 511 biSizeImage:=0; 512 biXPelsPerMeter:=0; 513 biYPelsPerMeter:=0; 514 biClrUsed:=0; 515 biClrImportant:=0; 516 end; 517 //提取數據 518 result:=GetDIBits(DC,Bitmap,0,self.FHeight,Pointer(self.FBits),BitInfo,DIB_RGB_COLORS)<>0; 519 if result then self.Error:='' 520 else self.Error:='提取數據失敗!'; 521 DeleteDC(MemDC); 522 DeleteObject(Bitmap); 523 ReleaseDC(Wnd,DC); 524 end; 525 526 //截取鼠標指針的位圖,並導入數據,返回是否成功, 527 //若是失敗將設置self.Error說明狀況, 528 //若是鼠標指針是動畫指針,默認截取第一幀畫面, 529 //截取時會使用當前背景顏色填充背景, 530 //若是沒有指定背景顏色則使用白色(RGB(255,255,255))填充。 531 function TBDBitmapData.CopyFormCursor: Boolean; 532 var 533 Wnd : HWND; 534 DC,MemDC : HDC; 535 Bitmap,OldBitmap : HBITMAP; 536 Pen,OldPen : HPEN; 537 Brush,OldBrush : HBRUSH; 538 C : TColor; 539 CurInfo : TCursorInfo; 540 BitInfo : TBitmapInfo; 541 begin 542 //數據初始化 543 if not self.InitData(IconWidth,IconHeight) then 544 begin 545 result:=false; 546 exit; 547 end; 548 if self.FBackColor=BD_COLORLESS then 549 C:=RGB(255,255,255) 550 else 551 C:=BGRToRGB(self.FBackColor); 552 //獲取鼠標指針信息 553 FillChar(CurInfo,SizeOf(TCursorInfo),0); 554 CurInfo.cbSize:=SizeOf(TCursorInfo); 555 if not GetCursorInfo(CurInfo) then 556 begin 557 self.Error:='獲取鼠標指針信息失敗!'; 558 result:=false; 559 exit; 560 end; 561 //繪製鼠標指針位圖 562 Wnd:=GetDesktopWindow(); 563 DC:=GetWindowDC(Wnd); 564 MemDC :=CreateCompatibleDC(DC); 565 Bitmap:=CreateCompatibleBitmap(DC,self.FWidth,self.FHeight); 566 Pen :=CreatePen(PS_SOLID,1,C); 567 Brush :=CreateSolidBrush(C); 568 OldBitmap:=SelectObject(MemDC,Bitmap); 569 OldPen :=SelectObject(MemDC,Pen); 570 OldBrush :=SelectObject(MemDC,Brush); 571 Rectangle(MemDC,0,0,IconWidth,IconHeight); 572 result:=DrawIconEx(MemDC,0,0,CurInfo.hCursor,0,0,0,0,DI_NORMAL); 573 Bitmap:=SelectObject(MemDC,OldBitmap); 574 Pen :=SelectObject(MemDC,OldPen); 575 Brush :=SelectObject(MemDC,OldBrush); 576 DeleteDC(MemDC); 577 DeleteObject(Pen); 578 DeleteObject(Brush); 579 if not result then 580 begin 581 DeleteObject(Bitmap); 582 ReleaseDC(Wnd,DC); 583 self.Error:='截取鼠標指針位圖失敗!'; 584 exit; 585 end; 586 //位圖信息初始化 587 with BitInfo.bmiHeader do 588 begin 589 biSize:=SizeOf(TBitmapInfoHeader); 590 biWidth:=self.FWidth; 591 biHeight:=self.FHeight; 592 biPlanes:=1; 593 biBitCount:=BD_BITCOUNT; 594 biCompression:=BI_RGB; 595 biSizeImage:=0; 596 biXPelsPerMeter:=0; 597 biYPelsPerMeter:=0; 598 biClrUsed:=0; 599 biClrImportant:=0; 600 end; 601 //提取數據 602 result:=GetDIBits(DC,Bitmap,0,self.FHeight,Pointer(self.FBits),BitInfo,DIB_RGB_COLORS)<>0; 603 if result then self.Error:='' 604 else self.Error:='提取數據失敗!'; 605 DeleteObject(Bitmap); 606 ReleaseDC(Wnd,DC); 607 end; 608 609 //在當前位圖的指定位置比較Bmp位圖,返回是否一致, 610 //不管是否一致都不會修改self.Error, 611 //Bmp位圖面幅要小於等於當前位圖的面幅,Bmp位圖不能超出當前位圖, 612 //Bmp:位圖數據; 613 //Left:比較時的左邊距,可省略; 614 //Top:比較時的頂邊距,可省略。 615 function TBDBitmapData.Compare(Bmp : TBDBitmapData; Left,Top : Integer): Boolean; 616 var 617 x,y,Off1,Off2 : Integer; 618 c1,c2 : TBDColor; 619 begin 620 if ((Left+Bmp.FWidth)>self.FWidth) or 621 ((Top+Bmp.FHeight)>self.FHeight) then 622 begin 623 result:=false; 624 exit; 625 end; 626 Off1:=((self.FHeight-Bmp.FHeight-Top)*self.FLineWidth)+(Left*BD_BYTECOUNT); 627 Off2:=0; 628 result:=true; 629 for y:=0 to Bmp.FHeight-1 do 630 begin 631 for x:=0 to Bmp.FWidth-1 do 632 begin 633 c1:=((PInteger(@(self.FBits[Off1])))^ and $FFFFFF); 634 c2:=((PInteger(@(Bmp.FBits[Off2])))^ and $FFFFFF); 635 if (c1<>self.FBackColor) and (c2<>Bmp.FBackColor) and 636 (c1<>c2) then 637 begin 638 result:=false; 639 break; 640 end; 641 Off1:=Off1+3; 642 Off2:=Off2+3; 643 end; 644 if not result then break; 645 Off1:=Off1+(self.FLineWidth-Bmp.FLineWidth)+Bmp.FSpareWidth; 646 Off2:=Off2+Bmp.FSpareWidth; 647 end; 648 end; 649 650 //在當前位圖的指定位置模糊比較Bmp位圖,返回是否一致, 651 //不管是否一致都不會修改self.Error, 652 //Bmp位圖面幅要小於等於當前位圖的面幅,Bmp位圖不能超出當前位圖, 653 //Bmp:位圖數據; 654 //Range:爲顏色變化範圍 655 //Left:比較時的左邊距,可省略; 656 //Top:比較時的頂邊距,可省略。 657 function TBDBitmapData.Compare(Bmp : TBDBitmapData; const Range : TBDColorRange; Left,Top : Integer): Boolean; 658 var 659 x,y,Off1,Off2 : Integer; 660 c1,c2 : TBDColor; 661 begin 662 if ((Left+Bmp.FWidth)>self.FWidth) or 663 ((Top+Bmp.FHeight)>self.FHeight) then 664 begin 665 result:=false; 666 exit; 667 end; 668 Off1:=((self.FHeight-Bmp.FHeight-Top)*self.FLineWidth)+(Left*BD_BYTECOUNT); 669 Off2:=0; 670 result:=true; 671 for y:=0 to Bmp.FHeight-1 do 672 begin 673 for x:=0 to Bmp.FWidth-1 do 674 begin 675 c1:=((PInteger(@(self.FBits[Off1])))^ and $FFFFFF); 676 c2:=((PInteger(@(Bmp.FBits[Off2])))^ and $FFFFFF); 677 if (c1<>self.FBackColor) and (c2<>Bmp.FBackColor) and 678 (not BDCompareColor(c1,c2,Range)) then 679 begin 680 result:=false; 681 break; 682 end; 683 Off1:=Off1+3; 684 Off2:=Off2+3; 685 end; 686 if not result then break; 687 Off1:=Off1+(self.FLineWidth-Bmp.FLineWidth)+Bmp.FSpareWidth; 688 Off2:=Off2+Bmp.FSpareWidth; 689 end; 690 end; 691 692 //從當前位圖中查找與Bmp一致的子圖,返回是否找到, 693 //不管是否找到都不會修改self.Error, 694 //按從左到右,從上到下的順序查找, 695 //找到返回true,設置Left和Top爲找到子圖的位置, 696 //沒找到返回false,設置Left和Top爲-1。 697 //Bmp:子圖數據; 698 //Left:找到子圖的左邊距; 699 //Top:找到子圖的頂邊距。 700 function TBDBitmapData.FindImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean; 701 var 702 x,y : Integer; 703 begin 704 result:=false; x:=0; 705 for y:=0 to self.FHeight-Bmp.FHeight-1 do 706 begin 707 for x:=0 to self.FWidth-Bmp.FWidth-1 do 708 begin 709 if self.Compare(Bmp,x,y) then 710 begin 711 result:=true; 712 break; 713 end; 714 end; 715 if result then break; 716 end; 717 if result then 718 begin 719 Left:=x; Top:=y; 720 end 721 else 722 begin 723 Left:=-1; Top:=-1; 724 end; 725 end; 726 727 //從當前位圖中模糊查找與Bmp一致的子圖,返回是否找到, 728 //不管是否找到都不會修改self.Error, 729 //按從左到右,從上到下的順序查找, 730 //找到返回true,設置Left和Top爲找到的位置, 731 //沒找到返回false,設置Left和Top爲-1。 732 //Bmp:子圖數據; 733 //Range:爲顏色變化範圍; 734 //Left:找到子圖的左邊距; 735 //Top:找到子圖的頂邊距。 736 function TBDBitmapData.FindImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean; 737 var 738 x,y : Integer; 739 begin 740 result:=false; x:=0; 741 for y:=0 to self.FHeight-Bmp.FHeight-1 do 742 begin 743 for x:=0 to self.FWidth-Bmp.FWidth-1 do 744 begin 745 if self.Compare(Bmp,Range,x,y) then 746 begin 747 result:=true; 748 break; 749 end; 750 end; 751 if result then break; 752 end; 753 if result then 754 begin 755 Left:=x; Top:=y; 756 end 757 else 758 begin 759 Left:=-1; Top:=-1; 760 end; 761 end; 762 763 //從當前位圖中查找與Bmp一致的子圖,返回是否找到, 764 //不管是否找到都不會修改self.Error, 765 //以(Left,Top)爲基點,從中心向四周查找, 766 //找到返回true,設置Left和Top爲找到子圖的位置, 767 //沒找到返回false,設置Left和Top爲-1。 768 //Bmp:子圖數據; 769 //Left:找到子圖的左邊距; 770 //Top:找到子圖的頂邊距。 771 function TBDBitmapData.FindCenterImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean; 772 var 773 Aspect : TAspect; 774 VisitCount,Count,i : Integer; 775 begin 776 result:=false; 777 VisitCount:=0; 778 Aspect:=asUp; 779 Count:=1; 780 while VisitCount<(self.FWidth*self.FHeight) do 781 begin 782 for i:=0 to Count-1 do 783 begin 784 if (Left>=0) and (Left<self.FWidth) and 785 (Top>=0) and (Top<self.FHeight) then 786 begin 787 if self.Compare(Bmp,Left,Top) then 788 begin 789 result:=true; 790 break; 791 end; 792 VisitCount:=VisitCount+1; 793 end; 794 Left:=Left+MoveVal[Aspect].X; 795 Top:=Top+MoveVal[Aspect].Y; 796 end; 797 if result then break; 798 case Aspect of 799 asLeft : begin Aspect:=asUp; Count:=Count+1; end; 800 asRight : begin Aspect:=asDown; Count:=Count+1; end; 801 asUp : begin Aspect:=asRight; end; 802 asDown : begin Aspect:=asLeft; end; 803 end; 804 end; 805 if not result then 806 begin 807 Left:=-1; Top:=-1; 808 end; 809 end; 810 811 //從當前位圖中模糊查找與Bmp一致的子圖,返回是否找到, 812 //不管是否找到都不會修改self.Error, 813 //以(Left,Top)爲基點,從中心向四周查找, 814 //找到返回true,設置Left和Top爲找到子圖的位置, 815 //沒找到返回false,設置Left和Top爲-1。 816 //Bmp:子圖數據; 817 //Range:爲顏色變化範圍; 818 //Left:找到子圖的左邊距; 819 //Top:找到子圖的頂邊距。 820 function TBDBitmapData.FindCenterImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean; 821 var 822 Aspect : TAspect; 823 VisitCount,Count,i : Integer; 824 begin 825 result:=false; 826 VisitCount:=0; 827 Aspect:=asUp; 828 Count:=1; 829 while VisitCount<(self.FWidth*self.FHeight) do 830 begin 831 for i:=0 to Count-1 do 832 begin 833 if (Left>=0) and (Left<self.FWidth) and 834 (Top>=0) and (Top<self.FHeight) then 835 begin 836 if self.Compare(Bmp,Range,Left,Top) then 837 begin 838 result:=true; 839 break; 840 end; 841 VisitCount:=VisitCount+1; 842 end; 843 Left:=Left+MoveVal[Aspect].X; 844 Top:=Top+MoveVal[Aspect].Y; 845 end; 846 if result then break; 847 case Aspect of 848 asLeft : begin Aspect:=asUp; Count:=Count+1; end; 849 asRight : begin Aspect:=asDown; Count:=Count+1; end; 850 asUp : begin Aspect:=asRight; end; 851 asDown : begin Aspect:=asLeft; end; 852 end; 853 end; 854 if not result then 855 begin 856 Left:=-1; Top:=-1; 857 end; 858 end; 859 860 //從當前位圖中查找全部與Bmp一致的子圖,返回是否找到, 861 //不管是否找到都不會修改self.Error, 862 //按從左到右,從上到下的順序查找, 863 //每找到一個子圖,就調用回調函數EnumImageProc,若是EnumImageProc 864 //返回false就中止查找,結束函數, 865 //Bmp:子圖數據; 866 //EnumImageProc:回調函數; 867 //lParam:調用回調函數時發出的參數,可省略。 868 function TBDBitmapData.EnumImage(Bmp : TBDBitmapData; EnumImageProc : TBDEnumImageProc; lParam : Integer): Boolean; 869 var 870 x,y : Integer; 871 Res : Boolean; 872 begin 873 result:=false; Res:=true; 874 for y:=0 to self.FHeight-Bmp.FHeight-1 do 875 begin 876 for x:=0 to self.FWidth-Bmp.FWidth-1 do 877 begin 878 if self.Compare(Bmp,x,y) then 879 begin 880 result:=true; 881 Res:=EnumImageProc(x,y,Bmp,lParam); 882 if not Res then break; 883 end; 884 end; 885 if not Res then break; 886 end; 887 end; 888 889 //從當前位圖中模糊查找全部與Bmp一致的子圖,返回是否找到, 890 //不管是否找到都不會修改self.Error, 891 //按從左到右,從上到下的順序查找, 892 //每找到一個子圖,就調用回調函數EnumImageProc,若是EnumImageProc 893 //返回false就中止查找,結束函數, 894 //Bmp:子圖數據; 895 //Range:爲顏色變化範圍; 896 //EnumImageProc:回調函數; 897 //lParam:調用回調函數時發出的參數,可省略。 898 function TBDBitmapData.EnumImage(Bmp : TBDBitmapData; const Range : TBDColorRange; EnumImageProc : TBDEnumImageProc; lParam : Integer): Boolean; 899 var 900 x,y : Integer; 901 Res : Boolean; 902 begin 903 result:=false; Res:=true; 904 for y:=0 to self.FHeight-Bmp.FHeight-1 do 905 begin 906 for x:=0 to self.FWidth-Bmp.FWidth-1 do 907 begin 908 if self.Compare(Bmp,Range,x,y) then 909 begin 910 result:=true; 911 Res:=EnumImageProc(x,y,Bmp,lParam); 912 if not Res then break; 913 end; 914 end; 915 if not Res then break; 916 end; 917 end; 918 919 //從當前位圖中查找指定的顏色,忽略self.FBackColor設置,返回是否找到, 920 //不管是否找到都不會修改self.Error, 921 //按從左到右,從上到下的順序查找, 922 //找到返回true,設置Left和Top爲找到顏色的位置, 923 //沒找到返回false,設置Left和Top爲-1。 924 //Color:BGR格式顏色; 925 //Left:找到顏色的左邊距; 926 //Top:找到顏色的頂邊距。 927 function TBDBitmapData.FindColor(Color : TBDColor; var Left,Top : Integer): Boolean; 928 var 929 x,y,LineOff,Off : Integer; 930 begin 931 result:=false; 932 LineOff:=self.FSize; x:=0; 933 for y:=0 to self.FHeight-1 do 934 begin 935 LineOff:=LineOff-self.FLineWidth; 936 Off:=LineOff; 937 for x:=0 to self.FWidth-1 do 938 begin 939 result:=((PInteger(@(self.FBits[Off])))^ and $FFFFFF)=Color; 940 if result then break; 941 Off:=Off+3; 942 end; 943 if result then break; 944 end; 945 if result then 946 begin 947 Left:=x; Top:=y; 948 end 949 else 950 begin 951 Left:=-1; Top:=-1; 952 end; 953 end; 954 955 //從當前位圖中模糊查找指定的顏色,忽略self.FBackColor設置,返回是否找到, 956 //不管是否找到都不會修改self.Error, 957 //按從左到右,從上到下的順序查找, 958 //找到返回true,設置Left和Top爲找到顏色的位置, 959 //沒找到返回false,設置Left和Top爲-1。 960 //Color:BGR格式顏色; 961 //Range:爲顏色變化範圍; 962 //Left:找到顏色的左邊距; 963 //Top:找到顏色的頂邊距。 964 function TBDBitmapData.FindColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean; 965 var 966 x,y,LineOff,Off : Integer; 967 begin 968 result:=false; 969 LineOff:=self.FSize; x:=0; 970 for y:=0 to self.FHeight-1 do 971 begin 972 LineOff:=LineOff-self.FLineWidth; 973 Off:=LineOff; 974 for x:=0 to self.FWidth-1 do 975 begin 976 result:=BDCompareColor( 977 ((PInteger(@(self.FBits[Off])))^ and $FFFFFF), 978 Color,Range); 979 if result then break; 980 Off:=Off+3; 981 end; 982 if result then break; 983 end; 984 if result then 985 begin 986 Left:=x; Top:=y; 987 end 988 else 989 begin 990 Left:=-1; Top:=-1; 991 end; 992 end; 993 994 //從當前位圖中查找指定的顏色,忽略self.FBackColor設置,返回是否找到, 995 //不管是否找到都不會修改self.Error, 996 //以(Left,Top)爲基點,從中心向四周查找, 997 //找到返回true,設置Left和Top爲找到顏色的位置, 998 //沒找到返回false,設置Left和Top爲-1。 999 //Color:BGR格式顏色; 1000 //Left:找到顏色的左邊距; 1001 //Top:找到顏色的頂邊距。 1002 function TBDBitmapData.FindCenterColor(Color : TBDColor; var Left,Top : Integer): Boolean; 1003 var 1004 Aspect : TAspect; 1005 VisitCount,Count,i : Integer; 1006 begin 1007 result:=false; 1008 VisitCount:=0; 1009 Aspect:=asUp; 1010 Count:=1; 1011 while VisitCount<(self.FWidth*self.FHeight) do 1012 begin 1013 for i:=0 to Count-1 do 1014 begin 1015 if (Left>=0) and (Left<self.FWidth) and 1016 (Top>=0) and (Top<self.FHeight) then 1017 begin 1018 if self.GetPixels(Left,Top)=Color then 1019 begin 1020 result:=true; 1021 break; 1022 end; 1023 VisitCount:=VisitCount+1; 1024 end; 1025 Left:=Left+MoveVal[Aspect].X; 1026 Top:=Top+MoveVal[Aspect].Y; 1027 end; 1028 if result then break; 1029 case Aspect of 1030 asLeft : begin Aspect:=asUp; Count:=Count+1; end; 1031 asRight : begin Aspect:=asDown; Count:=Count+1; end; 1032 asUp : begin Aspect:=asRight; end; 1033 asDown : begin Aspect:=asLeft; end; 1034 end; 1035 end; 1036 if not result then 1037 begin 1038 Left:=-1; Top:=-1; 1039 end; 1040 end; 1041 1042 //從當前位圖中模糊查找指定的顏色,忽略self.FBackColor設置,返回是否找到, 1043 //不管是否找到都不會修改self.Error, 1044 //以(Left,Top)爲基點,從中心向四周查找, 1045 //找到返回true,設置Left和Top爲找到顏色的位置, 1046 //沒找到返回false,設置Left和Top爲-1。 1047 //Color:BGR格式顏色; 1048 //Range:爲顏色變化範圍; 1049 //Left:找到顏色的左邊距; 1050 //Top:找到顏色的頂邊距。 1051 function TBDBitmapData.FindCenterColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean; 1052 var 1053 Aspect : TAspect; 1054 VisitCount,Count,i : Integer; 1055 begin 1056 result:=false; 1057 VisitCount:=0; 1058 Aspect:=asUp; 1059 Count:=1; 1060 while VisitCount<(self.FWidth*self.FHeight) do 1061 begin 1062 for i:=0 to Count-1 do 1063 begin 1064 if (Left>=0) and (Left<self.FWidth) and 1065 (Top>=0) and (Top<self.FHeight) then 1066 begin 1067 if BDCompareColor(self.GetPixels(Left,Top),Color,Range) then 1068 begin 1069 result:=true; 1070 break; 1071 end; 1072 VisitCount:=VisitCount+1; 1073 end; 1074 Left:=Left+MoveVal[Aspect].X; 1075 Top:=Top+MoveVal[Aspect].Y; 1076 end; 1077 if result then break; 1078 case Aspect of 1079 asLeft : begin Aspect:=asUp; Count:=Count+1; end; 1080 asRight : begin Aspect:=asDown; Count:=Count+1; end; 1081 asUp : begin Aspect:=asRight; end; 1082 asDown : begin Aspect:=asLeft; end; 1083 end; 1084 end; 1085 if not result then 1086 begin 1087 Left:=-1; Top:=-1; 1088 end; 1089 end; 1090 1091 //從當前位圖中查找全部指定的顏色,忽略self.FBackColor設置,返回是否找到, 1092 //不管是否找到都不會修改self.Error, 1093 //按從左到右,從上到下的順序查找, 1094 //每找到一個顏色,就調用回調函數EnumColorProc,若是EnumColorProc 1095 //返回false就中止查找,結束函數, 1096 //Color:BGR格式顏色; 1097 //EnumColorProc:回調函數; 1098 //lParam:調用回調函數時發出的參數,可省略。 1099 function TBDBitmapData.EnumColor(Color : TBDColor; EnumColorProc : TBDEnumColorProc; lParam : Integer): Boolean; 1100 var 1101 x,y,LineOff,Off : Integer; 1102 Res : Boolean; 1103 c : TBDColor; 1104 begin 1105 result:=false; 1106 LineOff:=self.FSize; Res:=true; 1107 for y:=0 to self.FHeight-1 do 1108 begin 1109 LineOff:=LineOff-self.FLineWidth; 1110 Off:=LineOff; 1111 for x:=0 to self.FWidth-1 do 1112 begin 1113 c:=((PInteger(@(self.FBits[Off])))^ and $FFFFFF); 1114 result:=c=Color; 1115 if result then 1116 begin 1117 Res:=EnumColorProc(x,y,c,lParam); 1118 if not Res then break; 1119 end; 1120 Off:=Off+3; 1121 end; 1122 if not Res then break; 1123 end; 1124 end; 1125 1126 //從當前位圖中模糊查找全部指定的顏色,忽略self.FBackColor設置,返回是否找到, 1127 //不管是否找到都不會修改self.Error, 1128 //按從左到右,從上到下的順序查找, 1129 //每找到一個顏色,就調用回調函數EnumColorProc,若是EnumColorProc 1130 //返回false就中止查找,結束函數, 1131 //Color:BGR格式顏色; 1132 //Range:爲顏色變化範圍; 1133 //EnumColorProc:回調函數; 1134 //lParam:調用回調函數時發出的參數,可省略。 1135 function TBDBitmapData.EnumColor(Color : TBDColor; const Range : TBDColorRange; EnumColorProc : TBDEnumColorProc; lParam : Integer): Boolean; 1136 var 1137 x,y,LineOff,Off : Integer; 1138 Res : Boolean; 1139 c : TBDColor; 1140 begin 1141 result:=false; 1142 LineOff:=self.FSize; Res:=true; 1143 for y:=0 to self.FHeight-1 do 1144 begin 1145 LineOff:=LineOff-self.FLineWidth; 1146 Off:=LineOff; 1147 for x:=0 to self.FWidth-1 do 1148 begin 1149 c:=((PInteger(@(self.FBits[Off])))^ and $FFFFFF); 1150 result:=BDCompareColor(c,Color,Range); 1151 if result then 1152 begin 1153 Res:=EnumColorProc(x,y,c,lParam); 1154 if not Res then break; 1155 end; 1156 Off:=Off+3; 1157 end; 1158 if not Res then break; 1159 end; 1160 end; 1161 1162 //單元初始化 1163 initialization 1164 begin 1165 ScreenWidth :=GetSystemMetrics(SM_CXSCREEN); 1166 ScreenHeight:=GetSystemMetrics(SM_CYSCREEN); 1167 IconWidth :=GetSystemMetrics(SM_CXICON); 1168 IconHeight :=GetSystemMetrics(SM_CYICON); 1169 end; 1170 1171 end.