Understanding TBitmap.Scanline in Delphi & C ++ Builder

Delphi and C ++ Builder have the TBitmap class with the Scanline property, which returns the pixel memory of the bitmap. This seems different when I look in the hex editor of a BMP file.

I am trying to port a C ++ Builder application to Java and would like to understand the algorithm in Scanline. If I have a file, how do I create a memory array such as Scanline? What is the specific specification for Scanline?

Clarifcation: BMP is the Windows 24bit DIB. I do not provide any other information in the code; It seems that C ++ Builder loads it into some type of memory structure, but not byte for byte. I would like to know what the specification of this structure is.

+6
source share
1 answer

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:

enter image description here

+8
source

Source: https://habr.com/ru/post/897583/


All Articles