一个位图文件以
BITMAPFILEHEADER
开头,
bfOffBits
成员指定了图像数据的起始地址。这是Dh(第11-14个字节)处的一个DWORD。Delphi VCL将此结构定义为'windows.pas'中的
TBitmapFileHeader
。
ScanLine
的最后一行指向该图像数据(自下而上)。VCL在图像的
dsBm
(
BITMAP
的成员)成员或
DIBSECTION
中的
bmBits
成员中具有该值。当请求扫描行时,VCL根据请求的行、每行的像素数(图像的宽度)以及组成像素的位数计算偏移量,并返回指向添加此偏移量到
bmBits
的地址的指针。这实际上是字节对字节的图像数据。
以下Delphi示例代码将24位位图读入文件流,并将每个读取的像素与
Bitmap.ScanLine
对应项的像素数据进行比较:
procedure TForm1.Button1Click(Sender: TObject);
var
BmpFile: string;
Bmp: TBitmap;
fs: TFileStream;
FileHeader: TBitmapFileHeader;
InfoHeader: TBitmapInfoHeader;
iHeight, iWidth, Padding: Longint;
ScanLine: Pointer;
RGBFile, RGBBitmap: TRGBTriple;
begin
BmpFile := ExtractFilePath(Application.ExeName) + 'Attention_128_24.bmp';
Bmp := TBitmap.Create;
Bmp.LoadFromFile(BmpFile);
Assert(Bmp.PixelFormat = pf24bit);
fs := TFileStream.Create(BmpFile, fmOpenRead or fmShareDenyWrite);
fs.Read(FileHeader, SizeOf(FileHeader));
fs.Read(InfoHeader, SizeOf(InfoHeader));
Assert(InfoHeader.biHeight > 0);
Padding := SizeOf(DWORD) -
(InfoHeader.biWidth * 3) mod SizeOf(DWORD);
fs.Seek(FileHeader.bfOffBits, soFromBeginning);
for iHeight := InfoHeader.biHeight - 1 downto 0 do begin
ScanLine := Bmp.ScanLine[iHeight];
for iWidth := 0 to InfoHeader.biWidth - 1 do begin
fs.Read(RGBFile, SizeOf(RGBFile));
RGBBitmap := TRGBTriple(Pointer(
Longint(ScanLine) + (iWidth * SizeOf(TRGBTriple)))^);
Assert((RGBBitmap.rgbtBlue = RGBFile.rgbtBlue) and
(RGBBitmap.rgbtGreen = RGBFile.rgbtGreen) and
(RGBBitmap.rgbtRed = RGBFile.rgbtRed));
end;
fs.Seek(Padding, soCurrent);
end;
end;
在十六进制编辑器中查找位图文件像素数据开头的图片如下: