德尔福& C Builder有一个带有Scanline属性的TBitmap类,它返回位图像素的内存.当我查看BMP文件的十六进制编辑器时,这似乎有所不同.
我正在尝试将C Builder应用程序移植到Java,并希望了解Scanline中的算法.如果我有文件,我如何生成像Scanline那样的内存阵列? Scanline背后的确切规格是什么?
Clarifcation:BMP是Windows 24bit DIB.我在代码中没有提供任何其他信息; C Builder似乎将它加载到某种类型的内存结构中,但它不是逐字节的.想知道那个结构的规格是什么.
解决方法
位图文件以
BITMAPFILEHEADER
开头,bfOffBits成员指定图像数据的起始地址.这是Dh的DWORD(11-14字节). Delphi VCL的结构在’windows.pas’中定义为TBitmapFileHeader.
ScanLine的最后一行指向此图像数据(自下而上). VCL在dsBm(a BITMAP
)成员的bmBits成员或映像的DIBSECTION
中具有此值.当请求扫描线时,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'; // 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;