返回
{***************************************************************}
{***               FVision Unit Version1.0                   ***}
{***                    蓝蚂蚁工作室                         ***}
{***************************************************************}
{***                 BMP图形文件支持单元                     ***}
{***************************************************************}
{$O+,F+,X+,I-,S-}
Unit FBmp;
Interface
Uses
  Dos,Graph,FGraph,FView,FTool,FDac,SvgaDrv,FCutgra,FWrite;

Type
  BitMapFile=record
   bfType:Integer;
   bfSize:Longint;
   Reserved1:Integer;
   Reserved2:Integer;
   bfOffset:Longint;
  end;
  BitMapInfo=record
   biSize:Longint;
   biWidth:Longint;
   biHeight:Longint;
   biPlanes:Integer;
   biBitcount:Integer;
   biCompression:Longint;
   biSizeImage:Longint;
   biXPelspermeter:Longint;
   biYPelspermeter:Longint;
   biClrused:Longint;
   biClrImportant:Longint;
  end;
  BitMapRgb=record
   Blue:Byte;
   Green:Byte;
   Red:Byte;
   Reserved:Byte;
  end;

  PBmp=^TBmp;
  TBmp=object(TView)
   Fp:file;
   Result:Word;
   FileName:PathStr;
   BmpHead:BitMapFile;
   BmpInfo:BitMapInfo;
   BmpDac:DacType;
   BmpPal:array[0..255] of BitMapRgb;
   Line:array[0..2047] of Byte;
   Height,Width,TrueWid:Integer;
   ColorNum:Integer;
   VideoMode256,VideoMode16:Word;
   TempAttr:Word;
   Center,ShowInfo,ReSetVideo,ReSetDac,BackGround:Boolean;
   InfoStr:string;
   constructor Init(AFileName:string;Intx,Inty:Integer);
   destructor Done;virtual;
   procedure SetOption(V256,V16:Word;Cen,ShIn,RV,RD,BC:Boolean);
   procedure SetPosition(x,y:Integer);
   procedure GetInfo(var Wid,Hig,Col:Integer);
   procedure ProHeader;
   procedure OpenFile;
   procedure Draw;virtual;
   procedure Creat(x,y:Integer);
  end;

Implementation
constructor TBmp.Init;
begin
  Inherited Init;
  FileName:=AFileName;
  Origin.x:=Intx;
  Origin.y:=Inty;
  SetOption($101,$12,False,False,False,False,False);
  TempAttr:=Archive;
end;

destructor TBmp.Done;
begin
  SetFAttr(Fp,TempAttr);
  {$i-}Close(Fp);{$i+}
end;

procedure TBmp.SetOption;
begin
  VideoMode256:=V256;
  VideoMode16:=V16;
  Center:=Cen;
  ShowInfo:=ShIn;
  ReSetVideo:=RV;
  ReSetDac:=RD;
  BackGround:=BC;
end;

procedure TBmp.SetPosition;
begin
  Origin.x:=x;
  Origin.y:=y;
end;

procedure TBmp.GetInfo;
begin
  Wid:=Width+1;
  Hig:=Height+1;
  Col:=ColorNum;
end;

procedure TBmp.ProHeader;
var
  DacMark:Byte;
  i:Integer;
begin
  Height:=BmpInfo.biHeight;
  Width:=BmpInfo.biWidth;
  TrueWid:=(BmpInfo.biWidth*BmpInfo.biBitCount) div 8;
  if (BmpInfo.biWidth*BmpInfo.biBitCount) mod 32<>0 then
    TrueWid:=TrueWid+4-(BmpInfo.biWidth*BmpInfo.biBitCount div 8) mod 4;
  if BmpInfo.biClrUsed=0 then
  begin
    if BmpInfo.biBitCount=1 then ColorNum:=2
    else if BmpInfo.biBitCount=4 then ColorNum:=16
    else if BmpInfo.biBitcount=8 then ColorNum:=256
    else ColorNum:=0;
  end else
    ColorNum:=BmpInfo.biClrUsed;
  BlockRead(Fp,BmpPal,ColorNum*SizeOf(BitMapRgb),Result);
  FillChar(BmpDac,SizeOf(DacType),0);
  if ColorNum=0 then Exit;
  if ColorNum<256 then
  for i:=0 to ColorNum-1 do
  begin
    BmpDac[GetDacIndex(i)*3+1]:=BmpPal[i].Red shr 2;
    BmpDac[GetDacIndex(i)*3+2]:=BmpPal[i].Green shr 2;
    BmpDac[GetDacIndex(i)*3+3]:=BmpPal[i].Blue shr 2;
  end else
  for i:=0 to 255 do
  begin
    BmpDac[i*3+1]:=BmpPal[i].Red shr 2;
    BmpDac[i*3+2]:=BmpPal[i].Green shr 2;
    BmpDac[i*3+3]:=BmpPal[i].Blue shr 2;
  end;
end;

procedure TBmp.OpenFile;
begin
  IsValid:=False;
  Assign(Fp,FileName);
  GetFAttr(Fp,TempAttr);
  SetFAttr(Fp,Archive);
  {$i-}Reset(Fp,1);{$i+}
  if IOResult<>0 then
  begin
    Writecs(10,10,'Open File '+FileName+' Error!',15);
    Exit;
  end;
  BlockRead(Fp,BmpHead,SizeOf(BitMapFile),Result);
  blockread(Fp,BmpInfo,SizeOf(BitMapInfo),Result);
  if BmpHead.bfType<>$4D42 then Exit;
  if BmpInfo.biCompression<>0 then Exit;
  if not (BmpInfo.biBitCount in [1,4,8]) then Exit;
  ProHeader;
  IsValid:=True;
end;

procedure TBmp.Draw;
  procedure SetCenter;
  begin
    if Center then
    begin
      Origin.x:=0;
      Origin.y:=0;
      if Maxx>Width then
      Origin.X:=(Maxx-Width) div 2;
      if Maxy>Height then
      Origin.Y:=(Maxy-Height) div 2;
    end;
  end;

  procedure Draw_Bmp2;
  var
    i,j,k:Integer;
  begin
    if ReSetVideo then SetVideoMode(VideoMode16);
    SetCenter;
    if ReSetDac then Dac.SetNewDac(BmpDac);
    for i:=Height-1 downto 0 do
    begin
      BlockRead(Fp,Line,TrueWid,Result);
      for j:=0 to TrueWid-1 do
      begin
        for k:=0 to 7 do
        if j*8+k<Width then
        if Line[j] and (1 shl (7-k))<>0 then
          PutPixel4(Origin.x+j*8+k,Origin.y+i,1)
        else
          PutPixel4(Origin.x+j*8+k,Origin.y+i,0);
      end;
    end;
  end;

  procedure Draw_Bmp16;
  var
    i,j:Integer;
  begin
    if ReSetVideo then SetVideoMode(VideoMode16);
    SetCenter;
    if ReSetDac then Dac.SetNewDac(BmpDac);
    for i:=Height-1 downto 0 do
    begin
      BlockRead(Fp,Line,TrueWid,Result);
      for j:=0 to TrueWid-1 do
      begin
        if j*2<Width then
          PutPixel4(Origin.x+j*2,Origin.y+i,(line[j] and $F0) shr 4);
        if j*2+1<Width then
          PutPixel4(Origin.x+j*2+1,Origin.y+i,Line[j] and $0F);
      end;
    end;
  end;

  procedure Draw_Bmp256;
  var
    i,j:Integer;
  begin
    if ReSetVideo then SetVideoMode(VideoMode256);
    SetCenter;
    if ReSetDac then Dac.SetNewDac(BmpDac);
    for i:=Height-1 downto 0 do
    begin
      BlockRead(Fp,Line,TrueWid,Result);
{      PutLine8(Origin.x,Origin.y+i,Seg(Line),Ofs(Line),Width);}
      for j:=0 to TrueWid-1 do
      if j<Width then
      if (Origin.x+j<=Maxx)and(Origin.y+i<=Maxy) then
      if not ((Line[j]=0)and BackGround) then
        PutPixel8(Origin.x+j,Origin.y+i,Line[j]);
    end;
  end;
begin
  if not IsValid then Exit;
  GetVideoMode;
  Seek(Fp,BmpHead.bfOffset);
  if BmpInfo.biBitCount=1 then Draw_Bmp2
  else if BmpInfo.biBitCount=4 then Draw_Bmp16
  else if BmpInfo.biBitCount=8 then Draw_Bmp256;
  if ShowInfo then
  begin
    SvgaDrv.SetColor(GetLightColor(DacRegsType(BmpDac)));
    SvgaDrv.MoveTo(Maxx div 2 - 70,Maxy-20);
    InfoStr:=Intstr(Width)+'*'+Intstr(Height)+' '+Intstr(ColorNum)+'Color';
    SvgaDrv.OutText(InfoStr);
  end;
end;

procedure TBmp.Creat;
  procedure ConvertDac;
  var
    i:Integer;
  begin
   if ColorNum=0 then Exit;
   if ColorNum<256 then
   for i:=0 to ColorNum-1 do
   begin
     BmpPal[i].Red:=BmpDac[GetDacIndex(i)*3+1] shl 2;
     BmpPal[i].Green:=BmpDac[GetDacIndex(i)*3+2] shl 2;
     BmpPal[i].Blue:=BmpDac[GetDacIndex(i)*3+3] shl 2;
     BmpPal[i].Reserved:=0;
   end
   else
   for i:=0 to 255 do
   begin
     BmpPal[i].Red:=BmpDac[i*3+1] shl 2;
     BmpPal[i].Green:=BmpDac[i*3+2] shl 2;
     BmpPal[i].Blue:=BmpDac[i*3+3] shl 2;
     BmpPal[i].Reserved:=0;
   end;
  end;

  procedure WriteBmp16;
  var
    i,j:Integer;
  begin
   for i:=Height-1 downto 0 do
   begin
    for j:=0 to TrueWid-1 do
    begin
      if j*2<Width then
      Line[j]:=Byte(GetPixel(Origin.x+j*2,Origin.y+i) shl 4);
      if j*2+1<Width then
      Line[j]:=Line[j] or Byte(GetPixel(Origin.x+j*2+1,Origin.y+i) and $0F);
    end;
    BlockWrite(Fp,Line,TrueWid,Result);
   end;
  end;

  procedure WriteBmp256;
  var
    i,j:Integer;
  begin
   for i:=Height-1 downto 0 do
   begin
    for j:=0 to TrueWid-1 do
    if j<Width then
    Line[j]:=GetPixel8(Origin.x+j,Origin.y+i);
    BlockWrite(Fp,Line,TrueWid,Result);
   end;
  end;

var i:Integer;
begin
  GetVideoMode;
  Assign(Fp,FileName);
  {$i-}ReWrite(Fp,1);{$i+}
  if IOResult<>0 then Exit;
  Width:=x;
  Height:=y;
  BmpHead.bfType:=$4D42;
  BmpHead.Reserved1:=0;
  BmpHead.Reserved2:=0;
  BmpInfo.biSize:=40;
  BmpInfo.biWidth:=Width;
  BmpInfo.biHeight:=Height;
  BmpInfo.biPlanes:=1;
  for i:=1 to 24 do
  if MaxColor shr i=1 then
  BmpInfo.biBitCount:=i;
  TrueWid:=(BmpInfo.biWidth*BmpInfo.biBitCount) div 8;
  if (BmpInfo.biWidth*BmpInfo.biBitCount) mod 32<>0 then
  TrueWid:=TrueWid+4-(BmpInfo.biWidth*BmpInfo.biBitCount div 8) mod 4;
  BmpInfo.biCompression:=0;
  BmpInfo.biSizeImage:=TrueWid*Height;
  BmpInfo.biXPelspermeter:=Maxx;
  BmpInfo.biYPelspermeter:=Maxy;
  BmpInfo.biClrused:=0;
  BmpInfo.biClrImportant:=0;
  if MaxColor>256 then
    ColorNum:=0
  else
    ColorNum:=MaxColor;
  BmpHead.bfOffset:=54+ColorNum*4;
  BmpHead.bfSize:=54+ColorNum*4+TrueWid*Height;
  BlockWrite(Fp,BmpHead,SizeOf(BitMapFile),Result);
  BlockWrite(Fp,BmpInfo,SizeOf(BitMapInfo),Result);
  Dac.GetDac(BmpDac);
  ConvertDac;
  BlockWrite(Fp,BmpPal,ColorNum*SizeOf(BitMapRgb),Result);
  if BmpInfo.biBitCount=4 then WriteBmp16
  else if BmpInfo.biBitCount=8 then WriteBmp256;
end;

end.