我想用两种颜色绘制一个200%拉伸的单色位图:纯黑色和纯白色。
我使用以下代码,但没有显示任何内容
如果我用SRCCOPY
替换SRCPAINT
,我会得到一个白色矩形,但仍然没有随机的2x2块被绘制为应该发生的。
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowCell(Form1.Canvas); //Using another canvas does not help.
end;
procedure ShowCell(Canvas: TCanvas);
const
cHeight = 100;
cWidth = 50; //50 * 8 = 400 pixels
var
bmpinfo: PBitmapInfo;
color: PRGBQUAD;
i: Integer;
x,y,h: integer;
DataBuffer: array[0..cHeight-1,0..cWidth-1] of byte;
ScanLineWidth: integer;
Cell: TLifeCell;
Coordinate: TCoordinate;
begin
GetMem(bmpinfo, SizeOf(TBitmapInfo) + SizeOf(TRGBQUAD)*2);
color:= @bmpinfo^.bmiColors[0];
color^.rgbRed:= 255;
color^.rgbBlue:= 255;
color^.rgbGreen:= 255;
color^.rgbReserved:= 0;
Inc(color);
color^.rgbRed:= 0;
color^.rgbBlue:= 0;
color^.rgbGreen:= 0;
color^.rgbReserved:= 0;
with bmpinfo.bmiHeader do begin
biSize:= SizeOf(bmpinfo.bmiHeader);
biWidth:= cWidth*8; //8 pixels per byte
biHeight:= cHeight;
biPlanes:= 1;
biBitCount:= 1;
biCompression:= BI_RGB;
biSizeImage:= 0;
biXPelsPerMeter:= 0;
biYPelsPerMeter:= 0;
biClrUsed:= 0;
biClrImportant:= 0;
end;
ScanlineWidth:= cWidth div 8;
if (ScanlineWidth mod 4) <> 0 then Inc(ScanlineWidth, 4 - ScanlineWidth mod 4);
for x:= 0 to cwidth-1 do begin
for y:= 0 to cheight-1 do begin
DataBuffer[x][y]:= Random(255);
end;
end;
StretchDIBits(Canvas.Handle, 0, 0, cHeight*2, cWidth*2*8, 0, 0, cHeight, cWidth*8,
@DataBuffer, bmpinfo^, DIB_RGB_COLORS, SRCCOPY);
FreeMem(bmpinfo);
end;
我在这里做错了什么?
答案 0 :(得分:1)
它对我有一些修正 - 循环中的cwidth / cheight和主要 - 交换了StretchDiBits函数的width和height参数。 GetLastError报告了错误的参数值吗? (在我的情况下 - 不是)
for x:= 0 to cwidth-1 do begin
for y:= 0 to cheight-1 do begin
DataBuffer[x][y]:= Random(255);
end;
end;
StretchDIBits(Canvas.Handle, 0,0,cWidth*2*8,cHeight*2,0,0,cwidth*8,cHeight,@DataBuffer,
bmpinfo^, DIB_RGB_COLORS, SRCCOPY);
另一个可能的问题 - 您定义了cWidth
(数据缓冲区宽度),与ScanlineWidth计算无关。
答案 1 :(得分:1)
有很多错误:
位图声明与StretchDIBits调用不匹配
问题是位图的声明必须与StretchDIBits
的参数匹配。如果这些不匹配,您将收到无声错误,并且不会显示任何内容。
以下是问题专栏:
with bmpinfo.bmiHeader do begin
biSize:= SizeOf(bmpinfo.bmiHeader);
biWidth:= cWidth*8; //8 pixels per byte must match srcWidth.
biHeight:= cHeight; // must match srcHeight below.
StretchDIBits(Canvas.Handle,0,0,cWidth*2*8,cHeight*2
,0,0,cwidth*8,cHeight, //srcWidth,srcHeight
@DataBuffer, bmpinfo^, DIB_RGB_COLORS, SRCCOPY);
如果srcWidth
或srcHeight
参数超出位图的尺寸,则呼叫将失败。
在问题高度和宽度反转的StretchDIBits
调用中,使位图太大并强制出错,从而阻止显示。
位图颠倒
因为IBM在位图格式上有肮脏的手,逻辑会从窗口中消失,而位图的默认设置是颠倒的。
BITMAPINFOHEADER
biHeight 位图的高度(以像素为单位)。如果biHeight为正,则位图是自下而上的DIB,其原点是左下角。如果biHeight是负数,则位图是自上而下的DIB,其原点是左上角。
除非您希望数据颠倒,否则最好让biHeight
为负数,如下所示:
with bmpinfo.bmiHeader do begin
biSize:= SizeOf(bmpinfo.bmiHeader);
biWidth:= cWidth*8; //8 pixels per byte must match srcWidth.
biHeight:= -cHeight; // "-" = TopDown: must match srcHeight below.
循环x和y颠倒
在循环中,请注意缓冲区中的x和y是相反的。
for y:= 0 to cHeight-1 do begin
for x:= 0 to cWidth-1 do begin //fill scanlines in the inner loop.
DataBuffer[y][x]:= Random(256); //y,x must be reversed!
end; {for x}
end; {for y}
未检查状态代码
如果我打扰检查StretchDIBits
的返回值,那么我可以省去自己的麻烦。我会知道有一个错误。
如果函数成功,则返回值是复制的扫描行数。请注意,此值对于镜像内容可能为负。
如果函数失败,或者没有复制扫描行,则返回值为0.
Success:= StretchDIBits(.....
Assert(Success <> 0,'StretchDIBits error, check your arguments');
出于性能原因,位图的宽度应为4字节的倍数
如果要使用(32位)整数写入位图缓冲区,最好确保位图宽度是4个字节的倍数,否则由于未对齐的写入而导致延迟。
如果使用64位Int64写入,请将其设为8个字节的倍数。
Windows仅强制执行2字节对齐。这是因为位图需要与16位Windows位图保持兼容。
bmWidthBytes 每条扫描行中的字节数。此值必须可被2整除,因为系统假定位图的位值形成一个字对齐的数组