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;
文件下载:http://files.cnblogs.com/rogee/BitMap%5bNOBUG%5d.zip
unit BitmapData; //
//位图数据处理,主要用于位图的找图找色
//作者:yeye55 2009年5月31日
//
//版权 2009,由 yeye55 拥有,保留所有权利。
//本文件中的代码是免费程序,无需任何授权或许可即可用于个人和商业目的。使用者一切后果自负。
//
//如果你转载了本文件中的代码,请注明代码出处和代码作者;
//如果你修改了本文件中的代码,请注明修改位置和修改作者。
//
//本文件最早在http://www.programbbs.com/bbs/上发布
// interface uses
Windows, Classes, SysUtils, Graphics; const
BD_COLORLESS = -; //无色
BD_BITCOUNT = ; //图象位数
BD_BYTECOUNT = BD_BITCOUNT shr ; //每象素占用字节数
BD_LINEWIDTH = ; //每行数据对齐宽度(位) type
//字节数组
TByteAry = array [..] of Byte;
PByteAry = ^TByteAry; //颜色变化范围,R、G、B三个通道的绝对差值
TBDColorRange = record
R : Integer;
G : Integer;
B : Integer;
end; TBDColor = Integer; //BGR格式颜色 //转换函数
function BGR(B,G,R : Byte): TBDColor;
function RGBtoBGR(C : TColor): TBDColor;
function BGRtoRGB(C : TBDColor): TColor;
//比较颜色
function BDCompareColor(C1,C2 : TBDColor; const Range : TBDColorRange): Boolean; type
TBDBitmapData = class; //位图数据 //枚举子图回调函数,查找多个子图时回调,返回是否继续枚举,
//Left:找到子图的左边距;
//Top:找到子图的顶边距;
//Bmp:找到子图数据;
//lParam:调用时设置的参数。
TBDEnumImageProc = function (Left,Top : Integer; Bmp : TBDBitmapData; lParam : Integer): Boolean; //枚举颜色回调函数,查找多个颜色时回调,返回是否继续枚举,
//Left:找到颜色的左边距;
//Top:找到颜色的顶边距;
//Color:找到的颜色;
//lParam:调用时设置的参数。
TBDEnumColorProc = function (Left,Top : Integer; Color : TBDColor; lParam : Integer): Boolean; //位图数据
TBDBitmapData = class
private
FName : String; //位图名称
FWidth : Integer; //位图宽度(象素)
FHeight : Integer; //位图高度(象素)
FBackColor : TBDColor; //背景颜色(BGR格式)
FLineWidth : Integer; //对齐后每行数据宽度(字节)
FSpareWidth : Integer; //对齐后每行数据多余宽度(字节)
FSize : Integer; //位图数据长度
FBufSize : Integer; //缓冲区实际长度
FBits : PByteAry; //位图数据缓冲区
function InitData(AWidth,AHeight : Integer): Boolean;
function GetPixels(Left,Top : Integer): TBDColor;
procedure SetPixels(Left,Top : Integer; Value : TBDColor);
public
Error : String;
constructor Create(const AName : String = '');
destructor Destroy; override;
procedure Clear;
function LoadFromStream(Stream : TStream; ABackColor : TBDColor = BD_COLORLESS): Boolean;
function SaveToStream(Stream : TStream):Boolean;
function LoadFromFile(const FileName : string; ABackColor : TBDColor = BD_COLORLESS): Boolean;
function SaveToFile(const FileName : string): Boolean;
function LoadFromBitmap(Bitmap : TBitmap): Boolean;
function SaveToBitmap(Bitmap : TBitmap): Boolean;
function CopyFormScreen(Left : Integer = -; Top : Integer = -; AWidth : Integer = -; AHeight : Integer = -): Boolean;
function CopyFormCursor: Boolean;
function Compare(Bmp : TBDBitmapData; Left : Integer = ; Top : Integer = ): Boolean; overload;
function Compare(Bmp : TBDBitmapData; const Range : TBDColorRange; Left : Integer = ; Top : Integer = ): Boolean; overload;
function FindImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean; overload;
function FindImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean; overload;
function FindCenterImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean; overload;
function FindCenterImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean; overload;
function EnumImage(Bmp : TBDBitmapData; EnumImageProc : TBDEnumImageProc; lParam : Integer = ): Boolean; overload;
function EnumImage(Bmp : TBDBitmapData; const Range : TBDColorRange; EnumImageProc : TBDEnumImageProc; lParam : Integer = ): Boolean; overload;
function FindColor(Color : TBDColor; var Left,Top : Integer): Boolean; overload;
function FindColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean; overload;
function FindCenterColor(Color : TBDColor; var Left,Top : Integer): Boolean; overload;
function FindCenterColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean; overload;
function EnumColor(Color : TBDColor; EnumColorProc : TBDEnumColorProc; lParam : Integer = ): Boolean; overload;
function EnumColor(Color : TBDColor; const Range : TBDColorRange; EnumColorProc : TBDEnumColorProc; lParam : Integer = ): Boolean; overload;
property Name : String read FName write FName; //位图名称
property Width : Integer read FWidth; //位图宽度(象素)
property Height : Integer read FHeight; //位图高度(象素)
property BackColor : TBDColor read FBackColor write FBackColor; //背景颜色(BGR格式)
property LineWidth : Integer read FLineWidth; //对齐后每行数据宽度(字节)
property SpareWidth : Integer read FSpareWidth; //对齐后每行数据多余宽度(字节)
property Size : Integer read FSize; //位图数据长度
property Bits : PByteAry read FBits; //位图数据缓冲区
property Pixels[Left,Top : Integer] : TBDColor read GetPixels write SetPixels; default;
end; implementation type
//矩阵遍历方向
TAspect = (asLeft, asRight, asUp, asDown); const
//移动坐标差,用于矩阵遍历
MoveVal : array [asLeft..asDown] of TPoint = (
(X : -; Y : ), //asLeft
(X : ; Y : ), //asRight
(X : ; Y : -), //asUp
(X : ; Y : ) //asDown
); var
ScreenWidth : Integer;
ScreenHeight : Integer;
IconWidth : Integer;
IconHeight : Integer; //根据B、G、R三个通道的值生成一个BGR格式颜色。
function BGR(B,G,R : Byte): TBDColor;
begin
result:=(B or (G shl ) or (R shl ));
end; //RGB颜色格式转换到BGR颜色格式。
function RGBtoBGR(C : TColor): TBDColor;
begin
result:=((C and $FF0000) shr ) or (C and $00FF00) or ((C and $0000FF) shl );
end; //BGR颜色格式转换到RGB颜色格式。
function BGRtoRGB(C : TBDColor): TColor;
begin
result:=((C and $FF0000) shr ) or (C and $00FF00) or ((C and $0000FF) shl );
end; //根据颜色范围Range比较颜色C1和C2,返回C1和C2是否相似,
//C1,C2:BGR格式颜色;
//Range:为颜色变化范围。
function BDCompareColor(C1,C2 : TBDColor; const Range : TBDColorRange): Boolean;
var
C : Integer;
begin
result:=false;
//B
C:=(C1 and $FF)-(C2 and $FF);
if (C>Range.B) or (C<-Range.B) then exit;
//G
C:=((C1 and $FF00) shr )-((C2 and $FF00) shr );
if (C>Range.G) or (C<-Range.G) then exit;
//R
C:=((C1 and $FF0000) shr )-((C2 and $FF0000) shr );
if (C>Range.R) or (C<-Range.R) then exit;
//
result:=true;
end; {TBDBitmapData} //位图数据 constructor TBDBitmapData.Create(const AName : String);
begin
self.FName:=AName;
self.FWidth:=;
self.FHeight:=;
self.FBackColor:=BD_COLORLESS;
self.FLineWidth:=;
self.FSize:=;
self.FBufSize:=;
self.FBits:=nil;
self.Error:='';
end; destructor TBDBitmapData.Destroy;
begin
self.Clear;
end; //根据当前的AWidth和AHeight初始化数据,分配内存,返回是否成功,
//如果失败将设置self.Error说明情况,
//AWidth:位图的宽度;
//AHeight:位图的高度。
function TBDBitmapData.InitData(AWidth,AHeight : Integer): Boolean;
var
Align : Integer;
begin
self.Error:='';
result:=true;
if (self.FWidth=AWidth) and
(self.FHeight=AHeight) then exit;
//计算对齐后的每行数据宽度
self.FWidth:=AWidth;
self.FHeight:=AHeight;
Align:=BD_LINEWIDTH-;
self.FLineWidth:=(((self.FWidth*BD_BITCOUNT)+Align) and ($7FFFFFFF-Align)) shr ;
self.FSpareWidth:=self.FLineWidth-(self.FWidth*BD_BYTECOUNT);
self.FSize:=self.FLineWidth*self.FHeight;
//分配内存
if self.FSize<=self.FBufSize then exit;
if self.FBits<>nil then FreeMem(self.FBits);
try
GetMem(self.FBits,self.FSize);
except
on EOutOfMemory do begin
self.FSize:=;
self.FBufSize:=;
self.FBits:=nil;
self.Error:='内存不足!';
result:=false;
exit;
end;
end;
self.FBufSize:=self.FSize;
end; //获取指定位置象素的颜色值,
//Left:象素的左边距;
//Top:象素的顶边距。
function TBDBitmapData.GetPixels(Left,Top : Integer): TBDColor;
begin
if (Left<) or (Left>=self.FWidth) or
(Top<) or (Top>=self.FHeight) then
begin
result:=;
exit;
end;
result:=((PInteger(@(self.FBits[
((self.FHeight-Top-)*self.FLineWidth)+(Left*BD_BYTECOUNT)
])))^ and $FFFFFF);
end; //设置指定位置象素的颜色值,
//Left:象素的左边距;
//Top:象素的顶边距;
//Value:BGR格式颜色。
procedure TBDBitmapData.SetPixels(Left,Top : Integer; Value : TBDColor);
var
Off : Integer;
begin
if (Left<) or (Left>=self.FWidth) or
(Top<) or (Top>=self.FHeight) then exit;
Off:=((self.FHeight-Top-)*self.FLineWidth)+(Left*BD_BYTECOUNT);
//B
self.FBits[Off]:=Byte(Value and $FF);
//G
self.FBits[Off+]:=Byte((Value and $FF00) shr );
//R
self.FBits[Off+]:=Byte((Value and $FF0000) shr );
end; //清除当前的位图数据。
procedure TBDBitmapData.Clear;
begin
self.FWidth:=;
self.FHeight:=;
self.FBackColor:=BD_COLORLESS;
self.FLineWidth:=;
self.FSize:=;
self.FBufSize:=;
if self.FBits<>nil then
begin
FreeMem(self.FBits);
self.FBits:=nil;
end;
self.Error:='';
end; //从数据流中导入位图数据,返回是否成功,
//如果失败将设置self.Error说明情况,
//数据流中的数据必需是24位BMP格式文件数据,
//Stream:数据流;
//ABackColor:位图的背景颜色,可省略。
function TBDBitmapData.LoadFromStream(Stream : TStream; ABackColor : TBDColor): Boolean;
var
FileHeader : TBitmapFileHeader;
InfoHeader : TBitmapInfoHeader;
begin
if Stream=nil then
begin
self.Error:='没有指定数据流!';
result:=false;
exit;
end;
//读取文件头
Stream.Read(FileHeader,SizeOf(TBitmapFileHeader));
Stream.Read(InfoHeader,SizeOf(TBitmapInfoHeader));
with FileHeader,InfoHeader do
begin
//确定位图格式
if (bfType<>$4D42) or (biSize<>SizeOf(TBitmapInfoHeader)) or
(biBitCount<>BD_BITCOUNT) or (biCompression<>BI_RGB) then
begin
self.Error:='错误的数据格式!';
result:=false;
exit;
end;
//数据初始化
self.FBackColor:=ABackColor;
if not self.InitData(biWidth,biHeight) then
begin
result:=false;
exit;
end;
end;
//读入数据
result:=Stream.Read((self.FBits)^,self.FSize)=self.FSize;
if result then self.Error:=''
else self.Error:='读取的数据不完整!';
end; //将当前的位图数据导出到数据流中,返回是否成功,
//如果失败将设置self.Error说明情况,
//数据按24位BMP文件数据格式导出到数据流中,
//Stream:数据流。
function TBDBitmapData.SaveToStream(Stream : TStream):Boolean;
var
FileHeader : TBitmapFileHeader;
InfoHeader : TBitmapInfoHeader;
HeaderLen,n : Integer;
begin
if Stream=nil then
begin
self.Error:='没有指定数据流!';
result:=false;
exit;
end;
//初始化文件头
HeaderLen:=SizeOf(TBitmapFileHeader)+SizeOf(TBitmapInfoHeader);
with FileHeader,InfoHeader do
begin
bfType:=$4D42;
bfSize:=self.FSize+HeaderLen;
bfReserved1:=;
bfReserved2:=;
bfOffBits:=HeaderLen;
biSize:=SizeOf(TBitmapInfoHeader);
biWidth:=self.FWidth;
biHeight:=self.FHeight;
biPlanes:=;
biBitCount:=BD_BITCOUNT;
biCompression:=BI_RGB;
biSizeImage:=self.FSize;
biXPelsPerMeter:=$EC4;
biYPelsPerMeter:=$EC4;
biClrUsed:=;
biClrImportant:=;
end;
//写入数据
n:=;
n:=n+Stream.Write(FileHeader,SizeOf(TBitmapFileHeader));
n:=n+Stream.Write(InfoHeader,SizeOf(TBitmapInfoHeader));
n:=n+Stream.Write((self.FBits)^,self.FSize);
result:=n=(self.FSize+HeaderLen);
if result then self.Error:=''
else self.Error:='写入的数据不完整!';
end; //从文件中导入位图数据,返回是否成功,
//如果失败将设置self.Error说明情况,
//文件必需是24位BMP格式文件,
//FileName:BMP文件名;
//ABackColor:位图的背景颜色,可省略。
function TBDBitmapData.LoadFromFile(const FileName : string; ABackColor : TBDColor): Boolean;
var
Stream : TFileStream;
begin
Stream:=TFileStream.Create(FileName,fmOpenRead);
result:=self.LoadFromStream(Stream,ABackColor);
Stream.Free;
end; //将当前的位图数据导出到文件中,返回是否成功,
//如果失败将设置self.Error说明情况,
//数据按24位BMP文件数据格式导出到文件中,
//FileName:BMP文件名。
function TBDBitmapData.SaveToFile(const FileName : string): Boolean;
var
Stream : TFileStream;
begin
Stream:=TFileStream.Create(FileName,fmCreate);
result:=self.SaveToStream(Stream);
Stream.Free;
end; //从一个TBitmap对象中导入数据,返回是否成功,位图的背景颜色由
//TBitmap.Transparent和TBitmap.TransparentColor决定,
//如果失败将设置self.Error说明情况,
//Bitmap:TBitmap对象。
function TBDBitmapData.LoadFromBitmap(Bitmap : TBitmap): Boolean;
var
Stream : TMemoryStream;
ABackColor : TBDColor;
begin
if Bitmap=nil then
begin
self.Error:='没有指定位图!';
result:=false;
exit;
end;
if Bitmap.Transparent then
ABackColor:=RGBtoBGR(Bitmap.TransparentColor)
else
ABackColor:=BD_COLORLESS;
Stream:=TMemoryStream.Create;
Bitmap.SaveToStream(Stream);
Stream.Position:=;
result:=self.LoadFromStream(Stream,ABackColor);
Stream.Free;
end; //将当前的位图数据导出到一个TBitmap对象中,返回是否成功,根据当前
//的背景颜色设置TBitmap.Transparent和TBitmap.TransparentColor成员,
//如果失败将设置self.Error说明情况,
//Bitmap:TBitmap对象。
function TBDBitmapData.SaveToBitmap(Bitmap : TBitmap): Boolean;
var
Stream : TMemoryStream;
begin
if Bitmap=nil then
begin
self.Error:='没有指定位图!';
result:=false;
exit;
end;
Stream:=TMemoryStream.Create;
result:=self.SaveToStream(Stream);
if not result then
begin
Stream.Free;
exit;
end;
Stream.Position:=;
Bitmap.LoadFromStream(Stream);
if self.FBackColor<>BD_COLORLESS then
begin
Bitmap.TransparentColor:=BGRtoRGB(self.FBackColor);
Bitmap.Transparent:=true;
end
else Bitmap.Transparent:=false;
Stream.Free;
end; //从屏幕上的指定范围中截图,并导入数据,返回是否成功,
//如果失败将设置self.Error说明情况,
//Left:截图的左边距,可省略;
//Top:截图的顶边距,可省略;
//AWidth:截图的宽度,可省略;
//AHeight:截图的高度,可省略。
function TBDBitmapData.CopyFormScreen(Left,Top,AWidth,AHeight : Integer): Boolean;
var
Wnd : HWND;
DC,MemDC : HDC;
Bitmap,OldBitmap : HBITMAP;
BitInfo : TBitmapInfo;
begin
//参数调整
if (Left<) or (Left>=ScreenWidth) then Left:=;
if (Top<) or (Top>=ScreenHeight) then Top:=;
if AWidth<= then AWidth:=ScreenWidth-Left;
if AHeight<= then AHeight:=ScreenHeight-Top;
//数据初始化
if not self.InitData(AWidth,AHeight) then
begin
result:=false;
exit;
end;
//截图
Wnd:=GetDesktopWindow();
DC:=GetWindowDC(Wnd);
MemDC:=CreateCompatibleDC(DC);
Bitmap:=CreateCompatibleBitmap(DC,self.FWidth,self.FHeight);
OldBitmap:=SelectObject(MemDC,Bitmap);
result:=BitBlt(MemDC,,,self.FWidth,self.FHeight,DC,Left,Top,SRCCOPY);
Bitmap:=SelectObject(MemDC,OldBitmap);
if not result then
begin
DeleteDC(MemDC);
DeleteObject(Bitmap);
ReleaseDC(Wnd,DC);
self.Error:='截图失败!';
exit;
end;
//位图信息初始化
with BitInfo.bmiHeader do
begin
biSize:=SizeOf(TBitmapInfoHeader);
biWidth:=self.FWidth;
biHeight:=self.FHeight;
biPlanes:=;
biBitCount:=BD_BITCOUNT;
biCompression:=BI_RGB;
biSizeImage:=;
biXPelsPerMeter:=;
biYPelsPerMeter:=;
biClrUsed:=;
biClrImportant:=;
end;
//提取数据
result:=GetDIBits(DC,Bitmap,,self.FHeight,Pointer(self.FBits),BitInfo,DIB_RGB_COLORS)<>;
if result then self.Error:=''
else self.Error:='提取数据失败!';
DeleteDC(MemDC);
DeleteObject(Bitmap);
ReleaseDC(Wnd,DC);
end; //截取鼠标指针的位图,并导入数据,返回是否成功,
//如果失败将设置self.Error说明情况,
//如果鼠标指针是动画指针,默认截取第一帧画面,
//截取时会使用当前背景颜色填充背景,
//如果没有指定背景颜色则使用白色(RGB(255,255,255))填充。
function TBDBitmapData.CopyFormCursor: Boolean;
var
Wnd : HWND;
DC,MemDC : HDC;
Bitmap,OldBitmap : HBITMAP;
Pen,OldPen : HPEN;
Brush,OldBrush : HBRUSH;
C : TColor;
CurInfo : TCursorInfo;
BitInfo : TBitmapInfo;
begin
//数据初始化
if not self.InitData(IconWidth,IconHeight) then
begin
result:=false;
exit;
end;
if self.FBackColor=BD_COLORLESS then
C:=RGB(,,)
else
C:=BGRToRGB(self.FBackColor);
//获取鼠标指针信息
FillChar(CurInfo,SizeOf(TCursorInfo),);
CurInfo.cbSize:=SizeOf(TCursorInfo);
if not GetCursorInfo(CurInfo) then
begin
self.Error:='获取鼠标指针信息失败!';
result:=false;
exit;
end;
//绘制鼠标指针位图
Wnd:=GetDesktopWindow();
DC:=GetWindowDC(Wnd);
MemDC :=CreateCompatibleDC(DC);
Bitmap:=CreateCompatibleBitmap(DC,self.FWidth,self.FHeight);
Pen :=CreatePen(PS_SOLID,,C);
Brush :=CreateSolidBrush(C);
OldBitmap:=SelectObject(MemDC,Bitmap);
OldPen :=SelectObject(MemDC,Pen);
OldBrush :=SelectObject(MemDC,Brush);
Rectangle(MemDC,,,IconWidth,IconHeight);
result:=DrawIconEx(MemDC,,,CurInfo.hCursor,,,,,DI_NORMAL);
Bitmap:=SelectObject(MemDC,OldBitmap);
Pen :=SelectObject(MemDC,OldPen);
Brush :=SelectObject(MemDC,OldBrush);
DeleteDC(MemDC);
DeleteObject(Pen);
DeleteObject(Brush);
if not result then
begin
DeleteObject(Bitmap);
ReleaseDC(Wnd,DC);
self.Error:='截取鼠标指针位图失败!';
exit;
end;
//位图信息初始化
with BitInfo.bmiHeader do
begin
biSize:=SizeOf(TBitmapInfoHeader);
biWidth:=self.FWidth;
biHeight:=self.FHeight;
biPlanes:=;
biBitCount:=BD_BITCOUNT;
biCompression:=BI_RGB;
biSizeImage:=;
biXPelsPerMeter:=;
biYPelsPerMeter:=;
biClrUsed:=;
biClrImportant:=;
end;
//提取数据
result:=GetDIBits(DC,Bitmap,,self.FHeight,Pointer(self.FBits),BitInfo,DIB_RGB_COLORS)<>;
if result then self.Error:=''
else self.Error:='提取数据失败!';
DeleteObject(Bitmap);
ReleaseDC(Wnd,DC);
end; //在当前位图的指定位置比较Bmp位图,返回是否一致,
//无论是否一致都不会修改self.Error,
//Bmp位图面幅要小于等于当前位图的面幅,Bmp位图不能超出当前位图,
//Bmp:位图数据;
//Left:比较时的左边距,可省略;
//Top:比较时的顶边距,可省略。
function TBDBitmapData.Compare(Bmp : TBDBitmapData; Left,Top : Integer): Boolean;
var
x,y,Off1,Off2 : Integer;
c1,c2 : TBDColor;
begin
if ((Left+Bmp.FWidth)>self.FWidth) or
((Top+Bmp.FHeight)>self.FHeight) then
begin
result:=false;
exit;
end;
Off1:=((self.FHeight-Bmp.FHeight-Top)*self.FLineWidth)+(Left*BD_BYTECOUNT);
Off2:=;
result:=true;
for y:= to Bmp.FHeight- do
begin
for x:= to Bmp.FWidth- do
begin
c1:=((PInteger(@(self.FBits[Off1])))^ and $FFFFFF);
c2:=((PInteger(@(Bmp.FBits[Off2])))^ and $FFFFFF);
if (c1<>self.FBackColor) and (c2<>Bmp.FBackColor) and
(c1<>c2) then
begin
result:=false;
break;
end;
Off1:=Off1+;
Off2:=Off2+;
end;
if not result then break;
Off1:=Off1+(self.FLineWidth-Bmp.FLineWidth)+Bmp.FSpareWidth;
Off2:=Off2+Bmp.FSpareWidth;
end;
end; //在当前位图的指定位置模糊比较Bmp位图,返回是否一致,
//无论是否一致都不会修改self.Error,
//Bmp位图面幅要小于等于当前位图的面幅,Bmp位图不能超出当前位图,
//Bmp:位图数据;
//Range:为颜色变化范围
//Left:比较时的左边距,可省略;
//Top:比较时的顶边距,可省略。
function TBDBitmapData.Compare(Bmp : TBDBitmapData; const Range : TBDColorRange; Left,Top : Integer): Boolean;
var
x,y,Off1,Off2 : Integer;
c1,c2 : TBDColor;
begin
if ((Left+Bmp.FWidth)>self.FWidth) or
((Top+Bmp.FHeight)>self.FHeight) then
begin
result:=false;
exit;
end;
Off1:=((self.FHeight-Bmp.FHeight-Top)*self.FLineWidth)+(Left*BD_BYTECOUNT);
Off2:=;
result:=true;
for y:= to Bmp.FHeight- do
begin
for x:= to Bmp.FWidth- do
begin
c1:=((PInteger(@(self.FBits[Off1])))^ and $FFFFFF);
c2:=((PInteger(@(Bmp.FBits[Off2])))^ and $FFFFFF);
if (c1<>self.FBackColor) and (c2<>Bmp.FBackColor) and
(not BDCompareColor(c1,c2,Range)) then
begin
result:=false;
break;
end;
Off1:=Off1+;
Off2:=Off2+;
end;
if not result then break;
Off1:=Off1+(self.FLineWidth-Bmp.FLineWidth)+Bmp.FSpareWidth;
Off2:=Off2+Bmp.FSpareWidth;
end;
end; //从当前位图中查找与Bmp一致的子图,返回是否找到,
//无论是否找到都不会修改self.Error,
//按从左到右,从上到下的顺序查找,
//找到返回true,设置Left和Top为找到子图的位置,
//没找到返回false,设置Left和Top为-1。
//Bmp:子图数据;
//Left:找到子图的左边距;
//Top:找到子图的顶边距。
function TBDBitmapData.FindImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean;
var
x,y : Integer;
begin
result:=false; x:=;
for y:= to self.FHeight-Bmp.FHeight- do
begin
for x:= to self.FWidth-Bmp.FWidth- do
begin
if self.Compare(Bmp,x,y) then
begin
result:=true;
break;
end;
end;
if result then break;
end;
if result then
begin
Left:=x; Top:=y;
end
else
begin
Left:=-; Top:=-;
end;
end; //从当前位图中模糊查找与Bmp一致的子图,返回是否找到,
//无论是否找到都不会修改self.Error,
//按从左到右,从上到下的顺序查找,
//找到返回true,设置Left和Top为找到的位置,
//没找到返回false,设置Left和Top为-1。
//Bmp:子图数据;
//Range:为颜色变化范围;
//Left:找到子图的左边距;
//Top:找到子图的顶边距。
function TBDBitmapData.FindImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean;
var
x,y : Integer;
begin
result:=false; x:=;
for y:= to self.FHeight-Bmp.FHeight- do
begin
for x:= to self.FWidth-Bmp.FWidth- do
begin
if self.Compare(Bmp,Range,x,y) then
begin
result:=true;
break;
end;
end;
if result then break;
end;
if result then
begin
Left:=x; Top:=y;
end
else
begin
Left:=-; Top:=-;
end;
end; //从当前位图中查找与Bmp一致的子图,返回是否找到,
//无论是否找到都不会修改self.Error,
//以(Left,Top)为基点,从中心向四周查找,
//找到返回true,设置Left和Top为找到子图的位置,
//没找到返回false,设置Left和Top为-1。
//Bmp:子图数据;
//Left:找到子图的左边距;
//Top:找到子图的顶边距。
function TBDBitmapData.FindCenterImage(Bmp : TBDBitmapData; var Left,Top : Integer): Boolean;
var
Aspect : TAspect;
VisitCount,Count,i : Integer;
begin
result:=false;
VisitCount:=;
Aspect:=asUp;
Count:=;
while VisitCount<(self.FWidth*self.FHeight) do
begin
for i:= to Count- do
begin
if (Left>=) and (Left<self.FWidth) and
(Top>=) and (Top<self.FHeight) then
begin
if self.Compare(Bmp,Left,Top) then
begin
result:=true;
break;
end;
VisitCount:=VisitCount+;
end;
Left:=Left+MoveVal[Aspect].X;
Top:=Top+MoveVal[Aspect].Y;
end;
if result then break;
case Aspect of
asLeft : begin Aspect:=asUp; Count:=Count+; end;
asRight : begin Aspect:=asDown; Count:=Count+; end;
asUp : begin Aspect:=asRight; end;
asDown : begin Aspect:=asLeft; end;
end;
end;
if not result then
begin
Left:=-; Top:=-;
end;
end; //从当前位图中模糊查找与Bmp一致的子图,返回是否找到,
//无论是否找到都不会修改self.Error,
//以(Left,Top)为基点,从中心向四周查找,
//找到返回true,设置Left和Top为找到子图的位置,
//没找到返回false,设置Left和Top为-1。
//Bmp:子图数据;
//Range:为颜色变化范围;
//Left:找到子图的左边距;
//Top:找到子图的顶边距。
function TBDBitmapData.FindCenterImage(Bmp : TBDBitmapData; const Range : TBDColorRange; var Left,Top : Integer): Boolean;
var
Aspect : TAspect;
VisitCount,Count,i : Integer;
begin
result:=false;
VisitCount:=;
Aspect:=asUp;
Count:=;
while VisitCount<(self.FWidth*self.FHeight) do
begin
for i:= to Count- do
begin
if (Left>=) and (Left<self.FWidth) and
(Top>=) and (Top<self.FHeight) then
begin
if self.Compare(Bmp,Range,Left,Top) then
begin
result:=true;
break;
end;
VisitCount:=VisitCount+;
end;
Left:=Left+MoveVal[Aspect].X;
Top:=Top+MoveVal[Aspect].Y;
end;
if result then break;
case Aspect of
asLeft : begin Aspect:=asUp; Count:=Count+; end;
asRight : begin Aspect:=asDown; Count:=Count+; end;
asUp : begin Aspect:=asRight; end;
asDown : begin Aspect:=asLeft; end;
end;
end;
if not result then
begin
Left:=-; Top:=-;
end;
end; //从当前位图中查找所有与Bmp一致的子图,返回是否找到,
//无论是否找到都不会修改self.Error,
//按从左到右,从上到下的顺序查找,
//每找到一个子图,就调用回调函数EnumImageProc,如果EnumImageProc
//返回false就停止查找,结束函数,
//Bmp:子图数据;
//EnumImageProc:回调函数;
//lParam:调用回调函数时发出的参数,可省略。
function TBDBitmapData.EnumImage(Bmp : TBDBitmapData; EnumImageProc : TBDEnumImageProc; lParam : Integer): Boolean;
var
x,y : Integer;
Res : Boolean;
begin
result:=false; Res:=true;
for y:= to self.FHeight-Bmp.FHeight- do
begin
for x:= to self.FWidth-Bmp.FWidth- do
begin
if self.Compare(Bmp,x,y) then
begin
result:=true;
Res:=EnumImageProc(x,y,Bmp,lParam);
if not Res then break;
end;
end;
if not Res then break;
end;
end; //从当前位图中模糊查找所有与Bmp一致的子图,返回是否找到,
//无论是否找到都不会修改self.Error,
//按从左到右,从上到下的顺序查找,
//每找到一个子图,就调用回调函数EnumImageProc,如果EnumImageProc
//返回false就停止查找,结束函数,
//Bmp:子图数据;
//Range:为颜色变化范围;
//EnumImageProc:回调函数;
//lParam:调用回调函数时发出的参数,可省略。
function TBDBitmapData.EnumImage(Bmp : TBDBitmapData; const Range : TBDColorRange; EnumImageProc : TBDEnumImageProc; lParam : Integer): Boolean;
var
x,y : Integer;
Res : Boolean;
begin
result:=false; Res:=true;
for y:= to self.FHeight-Bmp.FHeight- do
begin
for x:= to self.FWidth-Bmp.FWidth- do
begin
if self.Compare(Bmp,Range,x,y) then
begin
result:=true;
Res:=EnumImageProc(x,y,Bmp,lParam);
if not Res then break;
end;
end;
if not Res then break;
end;
end; //从当前位图中查找指定的颜色,忽略self.FBackColor设置,返回是否找到,
//无论是否找到都不会修改self.Error,
//按从左到右,从上到下的顺序查找,
//找到返回true,设置Left和Top为找到颜色的位置,
//没找到返回false,设置Left和Top为-1。
//Color:BGR格式颜色;
//Left:找到颜色的左边距;
//Top:找到颜色的顶边距。
function TBDBitmapData.FindColor(Color : TBDColor; var Left,Top : Integer): Boolean;
var
x,y,LineOff,Off : Integer;
begin
result:=false;
LineOff:=self.FSize; x:=;
for y:= to self.FHeight- do
begin
LineOff:=LineOff-self.FLineWidth;
Off:=LineOff;
for x:= to self.FWidth- do
begin
result:=((PInteger(@(self.FBits[Off])))^ and $FFFFFF)=Color;
if result then break;
Off:=Off+;
end;
if result then break;
end;
if result then
begin
Left:=x; Top:=y;
end
else
begin
Left:=-; Top:=-;
end;
end; //从当前位图中模糊查找指定的颜色,忽略self.FBackColor设置,返回是否找到,
//无论是否找到都不会修改self.Error,
//按从左到右,从上到下的顺序查找,
//找到返回true,设置Left和Top为找到颜色的位置,
//没找到返回false,设置Left和Top为-1。
//Color:BGR格式颜色;
//Range:为颜色变化范围;
//Left:找到颜色的左边距;
//Top:找到颜色的顶边距。
function TBDBitmapData.FindColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean;
var
x,y,LineOff,Off : Integer;
begin
result:=false;
LineOff:=self.FSize; x:=;
for y:= to self.FHeight- do
begin
LineOff:=LineOff-self.FLineWidth;
Off:=LineOff;
for x:= to self.FWidth- do
begin
result:=BDCompareColor(
((PInteger(@(self.FBits[Off])))^ and $FFFFFF),
Color,Range);
if result then break;
Off:=Off+;
end;
if result then break;
end;
if result then
begin
Left:=x; Top:=y;
end
else
begin
Left:=-; Top:=-;
end;
end; //从当前位图中查找指定的颜色,忽略self.FBackColor设置,返回是否找到,
//无论是否找到都不会修改self.Error,
//以(Left,Top)为基点,从中心向四周查找,
//找到返回true,设置Left和Top为找到颜色的位置,
//没找到返回false,设置Left和Top为-1。
//Color:BGR格式颜色;
//Left:找到颜色的左边距;
//Top:找到颜色的顶边距。
function TBDBitmapData.FindCenterColor(Color : TBDColor; var Left,Top : Integer): Boolean;
var
Aspect : TAspect;
VisitCount,Count,i : Integer;
begin
result:=false;
VisitCount:=;
Aspect:=asUp;
Count:=;
while VisitCount<(self.FWidth*self.FHeight) do
begin
for i:= to Count- do
begin
if (Left>=) and (Left<self.FWidth) and
(Top>=) and (Top<self.FHeight) then
begin
if self.GetPixels(Left,Top)=Color then
begin
result:=true;
break;
end;
VisitCount:=VisitCount+;
end;
Left:=Left+MoveVal[Aspect].X;
Top:=Top+MoveVal[Aspect].Y;
end;
if result then break;
case Aspect of
asLeft : begin Aspect:=asUp; Count:=Count+; end;
asRight : begin Aspect:=asDown; Count:=Count+; end;
asUp : begin Aspect:=asRight; end;
asDown : begin Aspect:=asLeft; end;
end;
end;
if not result then
begin
Left:=-; Top:=-;
end;
end; //从当前位图中模糊查找指定的颜色,忽略self.FBackColor设置,返回是否找到,
//无论是否找到都不会修改self.Error,
//以(Left,Top)为基点,从中心向四周查找,
//找到返回true,设置Left和Top为找到颜色的位置,
//没找到返回false,设置Left和Top为-1。
//Color:BGR格式颜色;
//Range:为颜色变化范围;
//Left:找到颜色的左边距;
//Top:找到颜色的顶边距。
function TBDBitmapData.FindCenterColor(Color : TBDColor; const Range : TBDColorRange; var Left,Top : Integer): Boolean;
var
Aspect : TAspect;
VisitCount,Count,i : Integer;
begin
result:=false;
VisitCount:=;
Aspect:=asUp;
Count:=;
while VisitCount<(self.FWidth*self.FHeight) do
begin
for i:= to Count- do
begin
if (Left>=) and (Left<self.FWidth) and
(Top>=) and (Top<self.FHeight) then
begin
if BDCompareColor(self.GetPixels(Left,Top),Color,Range) then
begin
result:=true;
break;
end;
VisitCount:=VisitCount+;
end;
Left:=Left+MoveVal[Aspect].X;
Top:=Top+MoveVal[Aspect].Y;
end;
if result then break;
case Aspect of
asLeft : begin Aspect:=asUp; Count:=Count+; end;
asRight : begin Aspect:=asDown; Count:=Count+; end;
asUp : begin Aspect:=asRight; end;
asDown : begin Aspect:=asLeft; end;
end;
end;
if not result then
begin
Left:=-; Top:=-;
end;
end; //从当前位图中查找所有指定的颜色,忽略self.FBackColor设置,返回是否找到,
//无论是否找到都不会修改self.Error,
//按从左到右,从上到下的顺序查找,
//每找到一个颜色,就调用回调函数EnumColorProc,如果EnumColorProc
//返回false就停止查找,结束函数,
//Color:BGR格式颜色;
//EnumColorProc:回调函数;
//lParam:调用回调函数时发出的参数,可省略。
function TBDBitmapData.EnumColor(Color : TBDColor; EnumColorProc : TBDEnumColorProc; lParam : Integer): Boolean;
var
x,y,LineOff,Off : Integer;
Res : Boolean;
c : TBDColor;
begin
result:=false;
LineOff:=self.FSize; Res:=true;
for y:= to self.FHeight- do
begin
LineOff:=LineOff-self.FLineWidth;
Off:=LineOff;
for x:= to self.FWidth- do
begin
c:=((PInteger(@(self.FBits[Off])))^ and $FFFFFF);
result:=c=Color;
if result then
begin
Res:=EnumColorProc(x,y,c,lParam);
if not Res then break;
end;
Off:=Off+;
end;
if not Res then break;
end;
end; //从当前位图中模糊查找所有指定的颜色,忽略self.FBackColor设置,返回是否找到,
//无论是否找到都不会修改self.Error,
//按从左到右,从上到下的顺序查找,
//每找到一个颜色,就调用回调函数EnumColorProc,如果EnumColorProc
//返回false就停止查找,结束函数,
//Color:BGR格式颜色;
//Range:为颜色变化范围;
//EnumColorProc:回调函数;
//lParam:调用回调函数时发出的参数,可省略。
function TBDBitmapData.EnumColor(Color : TBDColor; const Range : TBDColorRange; EnumColorProc : TBDEnumColorProc; lParam : Integer): Boolean;
var
x,y,LineOff,Off : Integer;
Res : Boolean;
c : TBDColor;
begin
result:=false;
LineOff:=self.FSize; Res:=true;
for y:= to self.FHeight- do
begin
LineOff:=LineOff-self.FLineWidth;
Off:=LineOff;
for x:= to self.FWidth- do
begin
c:=((PInteger(@(self.FBits[Off])))^ and $FFFFFF);
result:=BDCompareColor(c,Color,Range);
if result then
begin
Res:=EnumColorProc(x,y,c,lParam);
if not Res then break;
end;
Off:=Off+;
end;
if not Res then break;
end;
end; //单元初始化
initialization
begin
ScreenWidth :=GetSystemMetrics(SM_CXSCREEN);
ScreenHeight:=GetSystemMetrics(SM_CYSCREEN);
IconWidth :=GetSystemMetrics(SM_CXICON);
IconHeight :=GetSystemMetrics(SM_CYICON);
end; end.
Delphi下实现全屏快速找图找色的更多相关文章
- audio与video控件/标签的隐藏,iso/Android下自动全屏播放,短暂黑屏问题
(一)audio音频标签 <audio src="xxx.mp3"></audio> (二)video视频标签 <video src="xx ...
- 基于js全屏动画焦点图幻灯片
今天给大家分享一款基于js全屏动画焦点图幻灯片.这款焦点图内的内容以动画形式出现和消失.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div class="sl ...
- C#实现按键精灵的'找图' '找色' '找字'的功能
http://www.cnblogs.com/JimmyBright/p/4355862.html 背景:游戏辅助功能通常使用按键精灵编写脚本,按键精灵的最大卖点就是能够找到画面中字,图,色,这对于模 ...
- html5下F11全屏化的几点注意
1.实现全屏化 var docElm = document.documentElement; //W3C if (docElm.requestFullscreen) { docElm.requestF ...
- VMware下Ubuntu全屏显示
开始是这样的 完了之后应该是这样的 1.点开菜单栏的 虚拟机---------> 安装VMware Tools 安装完了之后桌面会出现一个这样的图标 双击这个DVD,进去之后左侧目录出现了 ...
- delphi实现截全屏功能
procedure TForm1.Button10Click(Sender: TObject);var bmp: TBitmap; can: TCanvas; dc: HDC; Image1: TIm ...
- HTML:给body增加全屏的背景图
只需要在head中增加如下代码即可 <head> {#设置背景#} <style> body { height: 100%;width: 100%; background: u ...
- Swiper 移动端全屏轮播图效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- Python实现按键精灵(二)-找图找色
一.实现功能 判断在指定坐标范围内,是否存在相似度大于n的图片,并返回坐标. 二.基本思路 A=你需要寻找的图片 B=截取当前页面中指定范围的图片 利用opencv 判断A在B中的位置, 在该位置截取 ...
随机推荐
- php约瑟夫环
<?php function popChar($str , $m , $current = 0){ $number = count($str); $num = 1; if(count($str) ...
- thinkphp3.2 namespace及use用法
PHP 5.3中的namespace其实是个不错的东西,可以简化编程,下面介绍三类在代码中 访问namespace中类的方法 1 引用namespace和类 假设namespace的程序为name ...
- Android2.2 API —— ImageView
注意 请查看本文后期更新完整版: http://www.cnblogs.com/over140/archive/2011/06/08/2075054.html 来源: 农民伯伯: http://www ...
- 鸟哥的linux私房菜——第12章 正则表达式与文件格式化处理
12.1什么是正则表达式 正则表达式就是处理字符串的方法,它是以行为单位来进行字符串的处理行为,正则表达式通过一些特殊符号的辅助,可以让用户轻易达到查找.删除.替换某特定字符串的处理程序. vi.gr ...
- C#编写自动关机程序复习的知识
首先一个程序第一要素是logo 在设置里面可以设置程序图标,在ICON里设置. ICON图标可以在网上下载. 这些都是表面功夫 程序中涉及到Buton.Label.Timer.Notiflcon控件 ...
- BZOJ 2301: [HAOI2011]Problem b 莫比乌斯反演
2301: [HAOI2011]Problem b Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 1007 Solved: 415[Submit][ ...
- Shoot the Bullet
zoj3229:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442 题意:一个摄影师,在n天内给m个女神拍照.每个女神至少要 ...
- Hibernate 使用HQL的 in 时要注意判断in的值(list)是否包含数据
如果你使用 HQL的 in,例如: sessionFactory.getCurrentSession() .createQuery("select hlInfo.id, count(id) ...
- (转)Mono for Android 优势与劣势
最近有兴趣了解一下Mono for Andriod,也就是使用.NET平台来开发Andriod程序.Mono for Android API 几乎映射标准的Andriod API.例如,两边API几乎 ...
- 【CF】244C Checkposts
题目需要求啥很明确了.主要思想是先计算机联通块,然后每个块内找到一个最小值(以及该值的次数).最小值和结果1,次数乘积为结果2.联通块tarjan可解. /* 427C */ #include < ...