The bitmap file starts with BITMAPFILEHEADER
, the bfOffBits
member indicates the starting address of the image data. This is the DWORD in Dh (11-14th byte). Delphi VCL has a structure defined as TBitmapFileHeader
in "windows.pas".
The last line of ScanLine
indicates the data of this image (bottom to top). VCL has this value in the bmBits
member of the dsBm
(a BITMAP
) or DIBSECTION
. When a scan string is requested, VCL calculates the offset based on the requested string, the number of pixels in the row (image width) and the number of bits making up the pixel, and returns a pointer to the address that adds this offset to bmBits
. This is really byte image data.
The following Delphi code example reads a 24-bit raster map into a file stream and compares each read pixel with Bitmap.ScanLine
pixel 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'; // laod bitmap to TBitmap Bmp := TBitmap.Create; Bmp.LoadFromFile(BmpFile); Assert(Bmp.PixelFormat = pf24bit); // read bitmap file with stream fs := TFileStream.Create(BmpFile, fmOpenRead or fmShareDenyWrite); // need to get the start of pixel array fs.Read(FileHeader, SizeOf(FileHeader)); // need to get width and height of bitmap fs.Read(InfoHeader, SizeOf(InfoHeader)); // just a general demo - no top-down image allowed Assert(InfoHeader.biHeight > 0); // size of each row is a multiple of the size of a DWORD Padding := SizeOf(DWORD) - (InfoHeader.biWidth * 3) mod SizeOf(DWORD); // pf24bit -> 3 bytes // start of pixel array fs.Seek(FileHeader.bfOffBits, soFromBeginning); // compare reading from file stream with the value from scanline for iHeight := InfoHeader.biHeight - 1 downto 0 do begin // get the scanline, bottom first ScanLine := Bmp.ScanLine[iHeight]; for iWidth := 0 to InfoHeader.biWidth - 1 do begin // read RGB from file stream fs.Read(RGBFile, SizeOf(RGBFile)); // read RGB from scan line RGBBitmap := TRGBTriple(Pointer( Longint(ScanLine) + (iWidth * SizeOf(TRGBTriple)))^); // assert the two values are the same Assert((RGBBitmap.rgbtBlue = RGBFile.rgbtBlue) and (RGBBitmap.rgbtGreen = RGBFile.rgbtGreen) and (RGBBitmap.rgbtRed = RGBFile.rgbtRed)); end; // skip row padding fs.Seek(Padding, soCurrent); end; end;
A picture about detecting the beginning of the pixel data of a raster file in a hex editor:

source share