首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解Delphi和C++生成器中的TBitmap.Scanline

理解Delphi和C++生成器中的TBitmap.Scanline
EN

Stack Overflow用户
提问于 2011-09-19 12:08:08
回答 1查看 7.1K关注 0票数 6

Delphi & C++ Builder有一个带有扫描线属性的TBitmap类,它返回位图像素的内存。当我查看BMP文件的十六进制编辑器时,这似乎是不同的。

我正在尝试将一个Java应用程序移植到C++,并想了解扫描线中的算法。如果我有这个文件,如何像Scanline那样生成内存数组?Scanline背后的确切规格是什么?

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

EN

回答 1

Stack Overflow用户

发布于 2011-09-19 23:47:30

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

ScanLine的最后一行指向此图像数据(自下而上)。VCL在dsBm( BITMAP)成员的bmBits成员或镜像的DIBSECTION中具有此值。当请求扫描线时,VCL根据所请求的行、行中的像素数(图像的宽度)和组成像素的位数来计算偏移量,并返回指向将该偏移量添加到bmBits的地址的指针。它实际上是一个字节一个字节的图像数据。

下面的Delphi示例代码将24位位图读取到文件流,并将读取的每个像素与Bitmap.ScanLine副本的像素数据进行比较:

代码语言:javascript
复制
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;

一张在十六进制编辑器中查找位图文件像素数据起始点的图片:

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7466349

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档