delphi - 了解 Delphi 和 C++ Builder 中的 TBitmap.Scanline

标签 delphi bitmap c++builder porting vcl

Delphi 和 C++ Builder 有一个带有 Scanline 属性的 TBitmap 类,该属性返回位图像素的内存。当我在 BMP 文件的十六进制编辑器中查看时,这似乎有所不同。

我正在尝试将 C++ Builder 应用程序移植到 Java,并且想了解 Scanline 中的算法。如果我有该文件,如何像 Scanline 那样生成内存阵列? Scanline 背后的确切规范是什么?

澄清:BMP 是 Windows 24 位 DIB。我没有在代码中提供任何其他信息; C++ Builder 似乎将其加载到某种类型的内存结构中,但它不是逐字节加载的。想知道该结构的规范是什么。

最佳答案

位图文件以 BITMAPFILEHEADER 开头,bfOffBits成员指定图像数据的起始地址。这是位于 Dh 的 DWORD(第 11-14 个字节)。 Delphi VCL 的结构定义为“windows.pas”中的 TBitmapFileHeader

ScanLine 的最后一行指向此图像数据(自下而上)。 VCL 在 dsBm(a BITMAP ) 成员或 DIBSECTIONbmBits 成员中具有此值。的图像。当请求扫描线时,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;



关于在十六进制编辑器中查找位图文件的像素数据的开头的图片:

enter image description here

关于delphi - 了解 Delphi 和 C++ Builder 中的 TBitmap.Scanline,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7466349/

相关文章:

c++ - 删除 TXMLDocument 对象 Embarcadero

string - 快速 - 替换 AnsiString (C++) 中所有出现的 ' (apostrophe) with ' '(两个撇号)

android - C++ 生成器 : Include JAR files

delphi - 为什么我的 Delphi 对象没有调用 _AddRef 和 _Release?

delphi - 如何在 Windows Vista 和 7 中检索 Windows 资源管理器使用的文件预览?

c# - 在PNG图像中用白色替换透明背景

c++ - 从资源中加载图像并转换为内存中的位图

delphi - 删除窗体上某个类的所有组件(Delphi)

delphi - 有没有办法在Windows 2000上安装Delphi 2010

android - 在android中从上到下 move 图像