解决方案 »
- 大家帮我看看这段代码怎么错了?2
- 关于数据库表操作的问题?
- 初学pascal,问各位一个问题:对于控制台下的input文件,在什么时候eof能取得真值,怎样操作可以使eof返回true呢?
- ★★★★★撒分了★★★★★
- 为什么我在做asp组件时为什么TChart用不成?找到解决办法立即给分!
- =====高手来帮忙啊=====怎么样用NMUDP这个玩意儿来传输数据和进行数据转换???
- 关于finger的问题。
- 不使用midas技术,如何编写一个dcom服务器来进行多层数据库开发?
- 请问如何像netants一样做出有颜色的dbgrid?
- delphi1.0的程序运行出错。。。?
- SecondsIdle函数返回问题
- delphi 关于fastreport的问题
unit BitmapData;
//
//位图数据处理,主要用于位图的找图找色
//作者:yeye55 2009年5月31日
{
原理: 位图其实可以看成是一个由象素组成的矩阵,找图找色可以看成是象素值的比对。
接着假设有一个位图,高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);来源: http://www.cxy.me/bbs/viewbbs.asp?BoardID=12&ID=20778&star=1&skin=0
}
interface
uses
Windows, Classes, SysUtils, Graphics, Dialogs;
const
BD_COLORLESS = -1; //无色
BD_BITCOUNT = 24; //图象位数
BD_BYTECOUNT = BD_BITCOUNT shr 3; //每象素占用字节数
BD_LINEWIDTH = 32; //每行数据对齐宽度(位)
type
//字节数组
TByteAry = array[0..0] 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;type
TBDBitmapData = class; //位图数据
//枚举子图回调函数,查找多个子图时回调,返回是否继续枚举,
//Left:找到子图的左边距;
//Top:找到子图的顶边距;
//Bmp:找到子图数据;
//lParam:调用时设置的参数。
TBDEnumImageProc = function(Left, Top: Integer; Bmp: TBDBitmapData; 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 MyBDEnumImageProc(Left, Top: Integer; Bmp: TBDBitmapData; lParam: Integer): Boolean;
public
Error: string;
constructor Create(const AName: string = '');
destructor Destroy; override;
procedure Clear;
function LoadFromStream(Stream: TStream; ABackColor: TBDColor =
BD_COLORLESS): Boolean;
function LoadFromBitmap(Bitmap: TBitmap): Boolean;
function Compare(Bmp: TBDBitmapData; Left: Integer = 0; Top: Integer = 0): Boolean; overload;
function EnumImage(Bmp: TBDBitmapData; EnumImageProc: TBDEnumImageProc;
lParam: Integer = 0): 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; //位图数据缓冲区
end;
implementation
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
);
var
ScreenWidth: Integer;
ScreenHeight: Integer;
IconWidth: Integer;
IconHeight: Integer;
//从数据流中导入位图数据,返回是否成功,
//如果失败将设置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;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 := 0;
result := self.LoadFromStream(Stream, ABackColor);
Stream.Free;
end;//清除当前的位图数据。
procedure TBDBitmapData.Clear;
begin
self.FWidth := 0;
self.FHeight := 0;
self.FBackColor := BD_COLORLESS;
self.FLineWidth := 0;
self.FSize := 0;
self.FBufSize := 0;
if self.FBits <> nil then
begin
FreeMem(self.FBits);
self.FBits := nil;
end;
self.Error := '';
end;
//根据B、G、R三个通道的值生成一个BGR格式颜色。
function BGR(B, G, R: Byte): TBDColor;
begin
result := (B or (G shl 8) or (R shl 16));
end;
//RGB颜色格式转换到BGR颜色格式。
function RGBtoBGR(C: TColor): TBDColor;
begin
result := ((C and $FF0000) shr 16) or (C and $00FF00) or ((C and $0000FF) shl
16);
end;
//BGR颜色格式转换到RGB颜色格式。
function BGRtoRGB(C: TBDColor): TColor;
begin
result := ((C and $FF0000) shr 16) or (C and $00FF00) or ((C and $0000FF) shl
16);
end;{TBDBitmapData}//位图数据
constructor TBDBitmapData.Create(const AName: string);
begin
self.FName := AName;
self.FWidth := 0;
self.FHeight := 0;
self.FBackColor := BD_COLORLESS;
self.FLineWidth := 0;
self.FSize := 0;
self.FBufSize := 0;
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 - 1;
self.FLineWidth := (((self.FWidth * BD_BITCOUNT) + Align) and ($7FFFFFFF -
Align)) shr 3;
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 := 0;
self.FBufSize := 0;
self.FBits := nil;
self.Error := '内存不足!';
result := false;
exit;
end;
end;
self.FBufSize := self.FSize;
end;
{A1.************************************正常对比图片**************************************************8}
//在当前位图的指定位置比较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);
Off1 := ((self.FHeight - Bmp.FHeight - Top) * self.FLineWidth) + (left * BD_BYTECOUNT);
Off2 := 0; result := true; //默认为相同
//循环小图片像索点
for y := 0 to Bmp.FHeight - 1 do
begin
for x := 0 to Bmp.FWidth - 1 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 + 3;
Off2 := Off2 + 3;
end;
if not result then
break;
Off1 := Off1 + (self.FLineWidth - Bmp.FLineWidth) + Bmp.FSpareWidth;
Off2 := Off2 + Bmp.FSpareWidth;
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 := 0 to self.FHeight - Bmp.FHeight - 1 do
begin
for x := 0 to self.FWidth - Bmp.FWidth - 1 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;
//单元初始化
initialization
begin
ScreenWidth := GetSystemMetrics(SM_CXSCREEN);
ScreenHeight := GetSystemMetrics(SM_CYSCREEN);
IconWidth := GetSystemMetrics(SM_CXICON);
IconHeight := GetSystemMetrics(SM_CYICON);
end;
end.
这是一个函数指针的定义,所以LZ需要定义一个独立的函数--注意,不是在类里面定义,而是一个单独的函数作为句柄来传入
譬如
function aTest(Left, Top: Integer; Bmp: TBDBitmapData; lParam: Integer): Boolean
begin
showMessage("this is a test");
end;然后调用的地方加上
MyEnumImageProc:= aTest;