Delphi下實現全屏快速找圖找色

前言算法

 

  最近有好幾個朋友都在問我找圖找色的問題,奇怪?因而乎寫了一個專門用於找圖找色的單元文件「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大小的矩陣,它的遍歷方法有如下三種:


此主題相關圖片以下:
按此在新窗口瀏覽圖片(圖1)

  在上圖中矩陣中的數字表示遍歷到元素的前後次序,箭頭表示遍歷的方向。第一種的通常遍歷法在不少編程書上都有介紹,並且常常做爲循環代碼的示範程序使用。這種遍歷方法稍加修改就能夠作到從右上角開始、從左下角開始、從右下角開始。這種遍歷方法很簡單,這裏就很少說了。與通常遍歷相反,螺旋遍歷在全部的編程書和數據結構書上都沒有講到。如今詳細的說明一下螺旋遍歷。

  螺旋遍歷能夠作到以一個基點爲中心向四周遍歷,這個基點能夠不是矩陣的中心點,實際上基點能夠是矩陣上的任意一點,甚至能夠是矩陣外的點。注意:這裏所說的「點」是指能夠用(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.
View Code
相關文章
相關標籤/搜索