24BITBMP位图的文件结构及创建

            下面这些结构说明来自http://blog.csdn.net/lanbing510/article/details/8176231,讲的很详尽。因为本文主要讲述24BIT的位图,所以关于16位的调色板就跳过了,至于原文,我觉得有一个地方是有误的,就是infoheader的biSizeImage 这个元素的描述,biSizeImage应该等于真正像素的数据的大小,并非宽为241就取244XheightX3.通过各种比较,这个数值应该等于每一行width填充byte[offset]后,offset如果不能被4整除,那么offset继续递加并往byte[offset]数组里面填充0(其他也可以,反正reader会跳过),它这个补齐,是基于储存像素时每行的byte长度不被4整齐时的补齐,并非单纯的width不被4整除时的补齐。


           根据位图的结构,也即是这几个语句就可以构成一张Bitmap了。这些代码的前身是java版本,翻译过来才发现,java版那个也有bug,自己好不容易纠正了。。

class procedure YUVTool.JBitmapToBitmapStream(pixels: TIntegerDynArray;
  w, h: integer; outStream: TStream);
var
  w_headerinfo: tBITMAPINFOHEADER;
  w_fileheader: TBitmapFileHeader;
  w_rgb: TByteDynArray;
begin
  w_rgb := addbmp_rgb_888(pixels, w, h);
  w_fileheader := addBMPImageHeader(length(w_rgb) * sizeof(byte));
  w_headerinfo := addBMPImageInfosHeader(w, h,length(w_rgb));
  outStream.Write(w_fileheader, Sizeof(TBitmapFileHeader));
  outStream.Write(w_headerinfo, SizeOf(w_headerinfo));
  outStream.Write(w_rgb[0], Length(w_rgb));
end;  

class function YUVTool.addBMPImageHeader(size: integer): TBitmapFileHeader;
begin
  FillChar(Result, sizeof(Result), 0);
  with Result do
  begin
    bfType := $4D42;
    bfSize := size + sizeof(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader);
    bfReserved1 := 0;
    bfReserved2 := 0;
    bfOffBits := $36;
  end;
end;

class function YUVTool.addBMPImageInfosHeader(w, h: integer;imgSize:DWORD): TBitmapInfoHeader;
begin
  FillChar(Result, sizeof(Result), 0);
  with Result do
  begin
    biSize := SizeOf(Result);
    biWidth := w;
    biHeight := h;
    biPlanes := 1;
    biBitCount := 24;
    biCompression := 0;//BI_RGB
    biSizeImage :=imgSize;
    biXPelsPerMeter := $1274;
    biYPelsPerMeter := $1274;
    biClrUsed := 0;
    biClrImportant := 0;

 { buffer[0] := $28;
  buffer[1] := $00;
  buffer[2] := $00;
  buffer[3] := $00;
  buffer[4] := byte(w shr 0);
  buffer[5] := byte(w shr 8);
  buffer[6] := byte(w shr 16);
  buffer[7] := byte(w shr 24);
  buffer[8] := byte(h shr 0);
  buffer[9] := byte(h shr 8);
  buffer[10] := byte(h shr 16);
  buffer[11] := byte(h shr 24);
  buffer[12] := $01;
  buffer[13] := $00;
  buffer[14] := $18;
  buffer[15] := $00;
  buffer[16] := $00;
  buffer[17] := $00;
  buffer[18] := $00;
  buffer[19] := $00;
  buffer[20] := $00;
  buffer[21] := $00;
  buffer[22] := $00;
  buffer[23] := $00;
  buffer[24] := byte($E0);
  buffer[25] := $01;
  buffer[26] := $00;
  buffer[27] := $00;
  buffer[28] := $02;
  buffer[29] := $03;
  buffer[30] := $00;
  buffer[31] := $00;
  buffer[32] := $00;
  buffer[33] := $00;
  buffer[34] := $00;
  buffer[35] := $00;
  buffer[36] := $00;
  buffer[37] := $00;
  buffer[38] := $00;
  buffer[39] := $00;
  Result := buffer;
          }
  end;
end;


    下面这个代码是今天临时写的对比两个位图文件header结构差异的,用它来验证生产的位图跟原图是否一直,方面多了,先对比header,OK后再用beyond compare对比两个文件。。

program bmpcomp;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, CustApp
  { you can add units after this };

type
  FXPT2DOT30 = longint;

  LPFXPT2DOT30 = ^longint;

  PCIEXYZ = ^TCIEXYZ;
  {$EXTERNALSYM tagCIEXYZ}
  tagCIEXYZ = packed record
    ciexyzX: FXPT2DOT30;
    ciexyzY: FXPT2DOT30;
    ciexyzZ: FXPT2DOT30;
  end;
  TCIEXYZ = tagCIEXYZ;
  {$EXTERNALSYM CIEXYZ}
  CIEXYZ = tagCIEXYZ;

  PCIEXYZTriple = ^TCIEXYZTriple;
  {$EXTERNALSYM tagICEXYZTRIPLE}
  tagICEXYZTRIPLE = packed record
    ciexyzRed: TCIEXYZ;
    ciexyzGreen: TCIEXYZ;
    ciexyzBlue: TCIEXYZ;
  end;
  TCIEXYZTriple = tagICEXYZTRIPLE;
  {$EXTERNALSYM CIEXYZTRIPLE}
  CIEXYZTRIPLE = tagICEXYZTRIPLE;
  PBitmapV4Header = ^TBitmapV4Header;
  {$EXTERNALSYM BITMAPV4HEADER}
  BITMAPV4HEADER = packed record
    bV4Size: DWORD;
    bV4Width: longint;
    bV4Height: longint;
    bV4Planes: word;
    bV4BitCount: word;
    bV4V4Compression: DWORD;
    bV4SizeImage: DWORD;
    bV4XPelsPerMeter: longint;
    bV4YPelsPerMeter: longint;
    bV4ClrUsed: DWORD;
    bV4ClrImportant: DWORD;
    bV4RedMask: DWORD;
    bV4GreenMask: DWORD;
    bV4BlueMask: DWORD;
    bV4AlphaMask: DWORD;
    bV4CSType: DWORD;
    bV4Endpoints: TCIEXYZTriple;
    bV4GammaRed: DWORD;
    bV4GammaGreen: DWORD;
    bV4GammaBlue: DWORD;
  end;
  TBitmapV4Header = BITMAPV4HEADER;
  PBitmapCoreHeader = ^TBitmapCoreHeader;
  {$EXTERNALSYM tagBITMAPCOREHEADER}
  tagBITMAPCOREHEADER = packed record
    bcSize: DWORD;
    bcWidth: word;
    bcHeight: word;
    bcPlanes: word;
    bcBitCount: word;
  end;
  TBitmapCoreHeader = tagBITMAPCOREHEADER;
  {$EXTERNALSYM BITMAPCOREHEADER}
  BITMAPCOREHEADER = tagBITMAPCOREHEADER;

  PBitmapInfoHeader = ^TBitmapInfoHeader;
  {$EXTERNALSYM tagBITMAPINFOHEADER}
  tagBITMAPINFOHEADER = packed record
    biSize: DWORD;
    biWidth: longint;
    biHeight: longint;
    biPlanes: word;
    biBitCount: word;
    biCompression: DWORD;
    biSizeImage: DWORD;
    biXPelsPerMeter: longint;
    biYPelsPerMeter: longint;
    biClrUsed: DWORD;
    biClrImportant: DWORD;
  end;
  TBitmapInfoHeader = tagBITMAPINFOHEADER;
  {$EXTERNALSYM BITMAPINFOHEADER}
  BITMAPINFOHEADER = tagBITMAPINFOHEADER;
  PBitmapFileHeader = ^TBitmapFileHeader;
  {$EXTERNALSYM tagBITMAPFILEHEADER}
  tagBITMAPFILEHEADER = packed record
    bfType: word;
    bfSize: DWORD;
    bfReserved1: word;
    bfReserved2: word;
    bfOffBits: DWORD;
  end;
  TBitmapFileHeader = tagBITMAPFILEHEADER;
  {$EXTERNALSYM BITMAPFILEHEADER}
  BITMAPFILEHEADER = tagBITMAPFILEHEADER;
  { BmpInfoCmp }

  BmpInfoCmp = class(TCustomApplication)
  protected
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
  end;

{ BmpInfoCmp }
procedure getBmpHeader(filepath:String;out outHeader:TBitmapFileHeader;out outInfo:TBitmapInfoHeader);
var w_filestream:TFileStream;
begin
     w_filestream:=TFileStream.Create(filepath,fmOpenRead or fmShareDenyWrite);
     try
        w_filestream.Read(outHeader,sizeof(outHeader));
        w_filestream.Read(outInfo,sizeof(outInfo));
     finally
       FreeAndNil(w_filestream);
     end;
end;

procedure BmpInfoCmp.DoRun;
var
  ErrorMsg: String;
  f1,f2:String;
  w_header1,w_header2:TBitmapFileHeader;
  w_info1,w_info2:TBitmapInfoHeader;
begin
  // quick check parameters
  ErrorMsg:=CheckOptions('h','help');
  if ErrorMsg<>'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Terminate;
    Exit;
  end;

  // parse parameters
  if HasOption('h','help') then begin
    WriteHelp;
    Terminate;
    Exit;
  end;
  f1:=Params[1];
  f2:=Params[2];
  getBmpHeader(f1,w_header1,w_info1);
  getBmpHeader(f2,w_header2,w_info2);
  writeln('FILEHEADER');
  if (w_header1.bfSize<>w_header2.bfSize) then begin
    WriteLn('L.bfSize:',IntToHex(w_header1.bfSize,8) ,' ',w_header1.bfSize);
    WriteLn('R.bfSize:',IntToHex(w_header2.bfSize,8) ,' ',w_header2.bfSize);
  end;
  writeln();
  if (w_header1.bfOffBits<>w_header2.bfOffBits) then begin
    WriteLn('L.bfOffBits:',IntToHex(w_header1.bfOffBits,8),' ',w_header1.bfOffBits);
    WriteLn('R.bfOffBits:',IntToHex(w_header2.bfOffBits,8),' ',w_header2.bfOffBits);
  end;
  writeln('BITMAPINFOHEADER');
  if (w_info1.biSize<>w_info2.biSize) then begin
    WriteLn('L.biSize:',IntToHex(w_info1.biSize,8),' ',w_info1.biSize);
    WriteLn('R.biSize:',IntToHex(w_info2.biSize,8),' ',w_info2.biSize);
  end;
  if (w_info1.biWidth<>w_info2.biWidth) then begin
    WriteLn('L.biWidth:',IntToHex(w_info1.biWidth,8),' ',w_info1.biWidth);
    WriteLn('R.biWidth:',IntToHex(w_info2.biWidth,8),' ',w_info2.biWidth);
  end;
  writeln('--');
  if (w_info1.biHeight<>w_info2.biHeight) then begin
    WriteLn('L.biHeight:',IntToHex(w_info1.biHeight,8),' ',w_info1.biHeight);
    WriteLn('R.biHeight:',IntToHex(w_info2.biHeight,8),' ',w_info2.biHeight);
  end;
  writeln('--');
  if (w_info1.biBitCount<>w_info2.biBitCount) then begin
    WriteLn('L.biBitCount:',IntToHex(w_info1.biBitCount,8),' ',w_info1.biBitCount);
    WriteLn('R.biBitCount:',IntToHex(w_info2.biBitCount,8),' ',w_info2.biBitCount);
  end;
  writeln('--');
  if (w_info1.biCompression<>w_info2.biCompression) then begin
    WriteLn('L.biCompression:',IntToHex(w_info1.biCompression,8),' ',w_info1.biCompression);
    WriteLn('R.biCompression:',IntToHex(w_info2.biCompression,8),' ',w_info2.biCompression);
  end;
  writeln('--');
  if (w_info1.biSizeImage<>w_info2.biSizeImage) then begin
    WriteLn('L.biSizeImage:',IntToHex(w_info1.biSizeImage,8),' ',w_info1.biSizeImage);
    WriteLn('R.biSizeImage:',IntToHex(w_info2.biSizeImage,8),' ',w_info2.biSizeImage);
  end;
  writeln('--');
  if (w_info1.biXPelsPerMeter<>w_info2.biXPelsPerMeter) then begin
    WriteLn('L.biXPelsPerMeter:',IntToHex(w_info1.biXPelsPerMeter,8),' ',w_info1.biXPelsPerMeter);
    WriteLn('R.biXPelsPerMeter:',IntToHex(w_info2.biXPelsPerMeter,8),' ',w_info2.biXPelsPerMeter);
  end;
  writeln('--');
  if (w_info1.biYPelsPerMeter<>w_info2.biYPelsPerMeter) then begin
    WriteLn('L.biYPelsPerMeter:',IntToHex(w_info1.biYPelsPerMeter,8),' ',w_info1.biYPelsPerMeter);
    WriteLn('R.biYPelsPerMeter:',IntToHex(w_info2.biYPelsPerMeter,8),' ',w_info2.biYPelsPerMeter);
  end;

  { add your program here }
  // stop program loop

  Terminate;
end;

constructor BmpInfoCmp.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;

destructor BmpInfoCmp.Destroy;
begin
  inherited Destroy;
end;

procedure BmpInfoCmp.WriteHelp;
begin
  { add your help code here }
  writeln('Usage: ',ExeName,' -h');
end;

var
  Application: BmpInfoCmp;
begin
  Application:=BmpInfoCmp.Create(nil);
  Application.Title:='My Application';
  Application.Run;
  Application.Free;
end.


你可能感兴趣的:(图像编程,pascal)