本文共 9274 字,大约阅读时间需要 30 分钟。
下面这些结构说明来自,讲的很详尽。因为本文主要讲述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.
转载地址:http://mozfi.baihongyu.com/