Delphi下实现全屏快速找图找色

前言

 

  最近有好几个朋友都在问我找图找色的问题,奇怪?于是乎写了一个专门用于找图找色的单元文件“BitmapData.pas”。在这个单元文件中我实现了从文件中导入位图、屏幕截图、鼠标指针截图、在图片上查找子图、在图片上查找颜色等功能。在查找过程中可以设定颜色变化范围、可以从左到右从上到下查找、也可以从指定点向四周查找。关于这个文件的下载和使用,可以参考本文的第四节。下面详细说说这些功能的实现。

一、数据提取

  位图其实可以看成是一个由象素组成的矩阵,找图找色可以看成是象素值的比对。很多新手在设计这类的程序时喜欢使用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;

  其中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个字节。

  知道了缓冲区数据的格式,就可以对缓冲区中的数据进行访问。现在给出相关访问的示范代码:首先位图数据缓冲区是一个一维的字节数组,那么这个数组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;

  综上所述,当位图数据提取到一个缓冲区中,找图找色就是对这个缓冲区中的数据进行访问的过程。而这个缓冲区可以作为一个矩阵来进行访问。只要对矩阵进行遍历就可以实现找图找色的算法。

二、矩阵遍历

  矩阵遍历是一个数据结构方面的问题。假设有一个矩阵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;

  对于回形遍历与螺旋遍历大同小异,这里就不多说了。在下面的压缩包中是矩阵遍历的示范程序,里面有一般遍历、螺旋遍历和回形遍历的示范代码,可以用于参考。

项目文件:
 点击浏览该文件

三、找图找色

  结合本文第一节和第二节的内容设计一个找图找色的程序应该不是问题。对于一个位图可以看成是由象素组成的矩阵,Top相当于y,Left相当于x,利用(Top,Left)可以象访问矩阵元素一样访问位图上的象素。查找过程就是对位图象素的遍历。相关的代码在BitmapData.pas文件中都有,这里就不重复了。在BitmapData.pas文件中我实现的查找过程主要还是一对一的比对,这是一种较慢的匹配算法。对于一些字符串匹配算法,在查找过程中可以在匹配失败时跳过一些字符从而加快查找的速度。在矩阵查找中也有类似的算法,但我没有找到比较好的算法,所以在实现上还是采用了一对一的比对。这就意味着查找过程的速度还有提升的可能,虽然现在的查找速度已经是可以接受的。

  另外还有一个问题:在屏幕或大图上查找一个位图,这个位图可以被称为子图。采用颜色比较算法可以允许子图出现一定的颜色偏差,这不会影响查找结果。但是这种比较算法却不允许子图出现扭曲或旋转,只要子图出现轻微的扭曲或旋转都无法查找到。如果要允许子图出现扭曲或旋转就要用到复杂的图形图象分析算法。由于图形图象分析算法太复杂,我也没有做太深的研究,所以在BitmapData.pas中我只实现了简单的子图查找

四、BitmapData.pas的使用

 

项目文件:
 点击浏览该文件

   (注:以上压缩包中的BitmapData.pas文件有个小BGU,主要是截取鼠标指针的图片时没有考虑当前的背景颜色,始终为黑色。在本贴三楼的压缩包中有更新后的BitmapData.pas文件下载。)

  在上面的压缩包中是BitmapData.pas使用的示范程序,BitmapData.pas文件可以从压缩包中获得。在BitmapData.pas文件中我将位图数据封装成了类TBDBitmapData,以便于使用。另外我编写一系列的函数用以BGR格式颜色的构建、转换、模糊比较。注意在BitmapData.pas文件中我定义了一些常量,这些常量只是为了增加程序的可读性,修改这些常量不会修改程序支持数据的格式,只会使程序运行错误。BitmapData.pas文件的详细说明如下:

1、function BGR(B,G,R : Byte): TBDColor;
  根据蓝(B)、绿(G)、红(R)三个通道的值生成一个BGR格式颜色。

2、function RGBtoBGR(C : TColor): TBDColor;
  将一个RGB颜色格式转换到BGR颜色格式。

3、function BGRtoRGB(C : TBDColor): TColor;
  将一个BGR颜色格式转换到RGB颜色格式。

4、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;

5、constructor TBDBitmapData.Create(const AName : String);
  新建一个TBDBitmapData对象的实例。可以为实例指定一个名字,便于以后的管理。

6、procedure TBDBitmapData.Clear;
  清除当前TBDBitmapData对象中加载的位图数据。

7、function TBDBitmapData.LoadFromStream(Stream : TStream; ABackColor : TBDColor): Boolean;
  从数据流Stream中导入位图数据,返回是否成功。如果失败将设置Error成员说明情况。数据流中的数据必需是24位BMP格式文件数据。利用ABackColor可以设定图片的背景颜色,该参数可以省略,省略时表示图片不使用背景颜色。

8、function TBDBitmapData.SaveToStream(Stream : TStream):Boolean;
  将当前加载的位图数据导出到数据流Stream中,返回是否成功。如果失败将设置Error成员说明情况。数据将按24位BMP文件数据格式导出到数据流中。

9、function TBDBitmapData.LoadFromFile(const FileName : string; ABackColor : TBDColor): Boolean;
  从文件FileName中导入位图数据,返回是否成功。如果失败将设置Error成员说明情况。文件必需是24位BMP格式文件。利用ABackColor可以设定图片的背景颜色,该参数可以省略,省略时表示图片不使用背景颜色。

10、function TBDBitmapData.SaveToFile(const FileName : string): Boolean;
  将当前加载的位图数据导出到文件中,返回是否成功。如果失败将设置Error成员说明情况。数据按24位BMP文件数据格式导出到文件中。

11、function TBDBitmapData.LoadFromBitmap(Bitmap : TBitmap): Boolean;
  从一个TBitmap对象中导入数据,返回是否成功。如果失败将设置Error成员说明情况。导入时图片的背景颜色由Bitmap.Transparent和Bitmap.TransparentColor决定。

12、function TBDBitmapData.SaveToBitmap(Bitmap : TBitmap): Boolean;
  将当前的位图数据导出到一个TBitmap对象中,返回是否成功。如果失败将设置Error成员说明情况。导出时将根据当前的背景颜色设置Bitmap.Transparent和Bitmap.TransparentColor成员。利用LoadFromBitmap和SaveToBitmap两个函数可以实现TBDBitmapData对象和TBitmap对象的相互转换。

13、function TBDBitmapData.CopyFormScreen(Left,Top,AWidth,AHeight : Integer): Boolean;
  从屏幕上的指定范围中截图,并导入数据,返回是否成功。如果失败将设置Error成员说明情况。Left为截图的左边距,可省略,默认为0;Top为截图的顶边距,可省略,默认为0;AWidth为截图的宽度,可省略,默认为从Left到屏幕右边的宽度;AHeight为截图的高度,可省略,默认为从Top到屏幕底边的高度。

14、function TBDBitmapData.CopyFormCursor: Boolean;
  截取鼠标当前指针的图片,并导入数据,返回是否成功。如果失败将设置Error成员说明情况。如果鼠标指针是动画指针,默认截取第一帧画面。截取时会使用当前背景颜色填充背景,如果没有指定背景颜色则使用白色(RGB(255,255,255))填充。

15、function TBDBitmapData.Compare(Bmp : TBDBitmapData; Left,Top : Integer): Boolean;
16、function TBDBitmapData.Compare(Bmp : TBDBitmapData; const Range : TBDColorRange; Left,Top : Integer): Boolean;
  重载的两个函数,用于在当前位图的指定位置比较Bmp指定的位图,返回是否一致。无论比较是否一致都不会修改Error成员。第一个函数用于精确比较,第二个函数用于模糊比较。Bmp指定的位图面幅要小于等于当前位图的面幅,Bmp指定的位图不能超出当前位图,否则比较失败。Bmp为指定的位图数据;Left为比较时的左边距,可省略,默认为0;Top为比较时的顶边距,可省略,默认为0;Range为颜色变化范围。

17、function TBDBitmapData.FindImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean;
18、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;

19、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为颜色变化范围。

21、function TBDBitmapData.EnumImage(Bmp : TBDBitmapData; EnumImageProc : TBDEnumImageProc; lParam : Integer): Boolean;
22、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时给出的设置参数。该函数的返回值表示是否继续枚举。

23、function TBDBitmapData.FindColor(Color : TBDColor; var Left,Top : Integer): Boolean;
24、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为颜色变化范围。

25、function TBDBitmapData.FindCenterColor(Color : TBDColor; var Left,Top : Integer): Boolean;
26、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;

27、function TBDBitmapData.EnumColor(Color : TBDColor; EnumColorProc : TBDEnumColorProc; lParam : Integer): Boolean;
28、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时给出的设置参数。该函数的返回值表示是否继续枚举。

29、TBDBitmapData.Error
  最近一次操作出现的错误的说明。出于性能方面的考虑,只有导入、导出、截图等操作才会修改这个成员。而查找、枚举等操作无论是否成功都不会修改这个成员。

30、TBDBitmapData.Name
  当前位图的名称,可读写。方便位图数据的管理。

31、TBDBitmapData.Width
  当前位图宽度,以象素为单位,只读。

32、TBDBitmapData.Height
  当前位图高度,以象素为单位,只读。

33、TBDBitmapData.BackColor
  当前位图的背景颜色,BGR格式的颜色,可读写。当该颜色为BD_COLORLESS时,表示该位图不使用背景颜色。

34、TBDBitmapData.LineWidth
  对齐后每行位图数据的宽度,以字节为单位,只读。

35、TBDBitmapData.SpareWidth
  对齐后每行位图数据填充的多余宽度,以字节为单位,只读。

36、TBDBitmapData.Size
  位图数据的长度,以字节为单位,只读。

37、TBDBitmapData.Bits
  位图数据缓冲区指针,只读。这个指针是只读的,但它指向的数据是可读写的。可以将这个属性看成是一个一维的字节数组,可以对缓冲区中的数据进行访问和修改。

38、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;

文件下载:https://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

 

posted on 2016-04-07 23:25  Delphi7456  阅读(1541)  评论(0编辑  收藏  举报

导航