解决方案 »

  1.   

    文件2,BitmapData.pas
    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.
      

  2.   

    主调函数里面的MyEnumImageProc变量没有初始化
      

  3.   

    TBDEnumImageProc = function(Left, Top: Integer; Bmp: TBDBitmapData; lParam:    Integer): Boolean
    这是一个函数指针的定义,所以LZ需要定义一个独立的函数--注意,不是在类里面定义,而是一个单独的函数作为句柄来传入
    譬如
    function aTest(Left, Top: Integer; Bmp: TBDBitmapData; lParam:    Integer): Boolean
    begin
    showMessage("this is a test");
    end;然后调用的地方加上
    MyEnumImageProc:= aTest;