Delphi TBitmap - 为什么Pixels和ScanLine不同?

时间:2014-03-10 02:32:50

标签: delphi bitmap pixels scanline

使用32位TBitmap时,我从Canvas.Pixels切换到ScanLine。

然后我将值设置为红色,只是发现它显示为蓝色。

知道为什么吗?

这是一段代码摘录:

procedure TForm1.FormPaint(Sender: TObject);
var
  varBitmap: TBitmap;
  pLock: PIntegerArray;
  iColor: integer;
begin
  varBitmap := TBitmap.Create;
  varBitmap.PixelFormat := pf32bit;
  varBitmap.Width := 800;
  varBitmap.Height := 600;

  // Set Pixels to Red
  varBitmap.Canvas.Pixels[0, 0] := $0000FF;

  // Shows $FF0000 (blue)
  pLock := varBitmap.ScanLine[0];
  iColor := pLock[0];
  ShowMessageFmt('%x', [iColor]);

  // Set ScanLine to Red
  pLock[0] := $0000FF;

  // Displays a blue pixel
  Canvas.Draw(0, 0, varBitmap);
end;

似乎TColor与内存中的内容不同,但这没有任何意义。

欢迎任何建议。 ;)

2 个答案:

答案 0 :(得分:6)

VCL位图类TBitmap是Windows本机设备独立位图(DIB)的包装器。这些位图对象可以以各种不同的像素格式存储位图。它们可以是单色的,每像素一位,每像素高达32位,即您使用的格式。它们还可用于存储基于调色板的位图,其中每个像素都将索引保存到颜色表中。

访问您引用的像素数据的两种方法是Pixels的{​​{1}}属性和TCanvas的{​​{1}}属性。

ScanLine的{​​{1}}属性是GDI GetPixelSetPixel函数的包装器。这是一个以COLORREF值运行的高级函数。 COLORREF的文档说:

  

低位字节包含红色相对强度的值;第二个字节包含绿色值;第三个字节包含蓝色的值。高位字节必须为零。单个字节的最大值为0xFF。

换句话说,TBitmap值具有对像素颜色进行编码的固定方式。 PixelsTCanvas函数可以处理固定COLORREF形式与基础原始位图像素数据之间的转换。另请注意,GetPixel不能表示alpha值。 SetPixel值为$ 00BBGGRR格式。

另一方面,COLORREF的{​​{1}}属性会返回指向底层DIB对象的原始像素数据的指针。您在这里使用的数据是32bpp像素数据,该数据的约定是它以$ AARRGGBB格式存储。 32bpp数据的Windows documentation表示:

  

位图最多有2 ^ 32种颜色。如果BITMAPINFOHEADER的biCompression成员是BI_RGB,则BITMAPINFO的bmiColors成员为NULL。位图数组中的每个DWORD表示像素的蓝色,绿色和红色的相对强度。蓝色的值是最低有效8位,后面是绿色和红色各8位。不使用每个DWORD中的高字节。

所以实际上这个文本不正确并且已经过时了。事实上,每个COLORREF中的高字节是alpha通道(如果使用的话)。

答案 1 :(得分:5)

32位像素数据采用$AARRGGBB格式。您正在设置蓝色组件,而不是红色组件。使用$FF0000代替$0000FF。或者更好的是,使用RGB()函数。