四、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;
利用TBDBitmapData对象查找两张图片上的不同,从右上角开始利用双层循环遍历两图上的所有象素点,并相互比较。不完整代码如下:
procedure TForm1.Button5Click(Sender: TObject); var Bmp1,Bmp2 : TBDBitmapData; Left,Top : Integer; IsExit : Boolean; begin Bmp1:=TBDBitmapData.Create; Bmp2:=TBDBitmapData.Create;
Bmp1.LoadFromFile('文件名1'); Bmp2.LoadFromFile('文件名2');
//假设两张图片一样大
IsExit:=false; for Top:=0 to Bmp1.Height-1 do begin for Left:=0 to Bmp1.Width-1 do begin if Bmp1[Left,Top]<>Bmp2[Left,Top] then begin //在(Left,Top)位置两张图片有不同
//相应的处理...
if {如果不继续查找其它不同} then begin IsExit:=true; //用以退出循环 break; end; end; end; if IsExit then break; end;
Bmp1.Free; Bmp2.Free; end;
以上代码不完整,可以根据需要进行修改。
|
请发表评论