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大小的矩阵,它的遍历方法有以下三种:
在上图中矩阵中的数字表示遍历到元素的先后次序,箭头表示遍历的方向。第一种的一般遍历法在很多编程书上都有介绍,而且经常作为循环代码的示范程序使用。这种遍历方法稍加修改就可以做到从右上角开始、从左下角开始、从右下角开始。这种遍历方法很简单,这里就不多说了。与一般遍历相反,螺旋遍历在所有的编程书和数据结构书上都没有讲到。现在详细的说明一下螺旋遍历。
螺旋遍历可以做到以一个基点为中心向四周遍历,这个基点可以不是矩阵的中心点,实际上基点可以是矩阵上的任意一点,甚至可以是矩阵外的点。注意:这里所说的“点”是指可以用(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.
posted on 2016-04-07 23:25 Delphi7456 阅读(1605) 评论(0) 编辑 收藏 举报