4

在使用 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 与内存中的内容不同,但这没有任何意义。

欢迎任何建议。;)

4

2 回答 2

6

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

您所指的访问像素数据的两种方法是 的Pixels属性TCanvas和 的ScanLine属性TBitmap

Pixels属性TCanvas是 GDIGetPixelSetPixel函数的包装器。这些是对值进行操作的高级函数COLORREF。的文档COLORREF说:

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

换句话说,一个COLORREF值具有固定的像素颜色编码方式。GetPixelSetPixel函数主要处理固定形式和底层原始位图像素数据之间的转换COLORREF。另请注意,aCOLORREF不能表示 alpha 值。该COLORREF值采用 $00BBGGRR 格式。

另一方面, 的ScanLine属性TBitmap返回一个指向底层 DIB 对象的原始像素数据的指针。您在此处使用的数据是 32bpp 像素数据,该数据的约定是它以 $AARRGGBB 格式存储。32bpp 数据的 Windows文档说:

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

所以事实上这个文本是不正确和过时的。每个DWORD中的高字节实际上是 alpha 通道,如果它被使用的话。

于 2014-03-10T13:24:45.547 回答
5

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

于 2014-03-10T03:25:17.343 回答