我正在另一个“下方”图像上显示透明图像。
在这种情况下,底部(实心)图像是棋盘网格,顶部图像是狮子(透明):
=
原因是要更好地显示透明度区域,因为通常您不会看到哪些区域是透明的。
问题是,位图的尺寸可以是任何尺寸,因此网格也需要与位图的尺寸相同。
如果你愿意,一个肮脏的方法是创建一个更大版本的棋盘网格,大小如2000x2000,那么根据你正在使用的位图的大小,你可以调整网格的画布以匹配。这并不理想,因为它意味着将大棋盘网格位图与您的应用程序一起存储,然后它意味着调整大小,这可能无法根据宽高比等给出正确的结果。
我认为正确的方法是以编程方式呈现棋盘网格,例如:
procedure RenderGrid(Source: TBitmap; Height, Width: Integer;
Size: Integer; Color1, Color2: TColor);
begin
end;
这将允许自定义具有不同大小和颜色的网格,而不用担心存储大型棋盘网格位图的开销并且不得不调整它的大小。
但是我不确定如何将网格绘制到位图上?我有一个想法是你需要遍历位图的每个交替行并以这种方式着色吗?我不确定。
这涉及我不擅长的数学和计算。如果您能够通过最有效的方式在位图上渲染网格,我将不胜感激。
答案 0 :(得分:5)
procedure RenderGrid(Source: TBitmap; Height, Width: Integer;
Size: Integer; Color1, Color2: TColor);
var
y: Integer;
x: Integer;
begin
Source.SetSize(Width, Height);
for y := 0 to Height div Size do
for x := 0 to Width div Size do
begin
if Odd(x) xor Odd(y) then
Source.Canvas.Brush.Color := Color1
else
Source.Canvas.Brush.Color := Color2;
Source.Canvas.FillRect(Rect(x*Size, y*Size, (x+1)*Size, (y+1)*Size));
end;
end;
答案 1 :(得分:3)
曾几何时,我profiled this specific need。考虑到您的RenderGrid
签名,很可能在绘制位图后绘制Bitmap
参数的图像。然后通过在Color1
中绘制整个位图来获得最佳性能,并仅绘制Color2
的方块:
procedure RenderGrid(Target: TBitmap; Height, Width: Integer; Size: Integer;
Color1, Color2: TColor);
var
Col: Integer;
Row: Integer;
begin
Target.SetSize(Width, Height)
Target.Canvas.Brush.Color := Color1;
Target.Canvas.FillRect(Rect(0, 0, Width, Height));
Target.Canvas.Brush.Color := Color2;
for Col := 0 to Width div Size do
for Row := 0 to Height div Size do
if Odd(Col + Row) then
Target.Canvas.FillRect(Bounds(Col * Size, Row * Size, Size, Size));
end;
但是,由于您正在谈论大型位图,下面显示的例程甚至会快20%。它创建一个只有4个正方形的小位图,比如一个2 x 2的棋盘,并让目标的画笔属性自动展开。 *)
procedure RenderGrid(Target: TBitmap; Height, Width: Integer; Size: Integer;
Color1, Color2: TColor);
var
Tmp: TBitmap;
begin
Tmp := TBitmap.Create;
try
Tmp.Canvas.Brush.Color := Color1;
Tmp.Width := 2 * Size;
Tmp.Height := 2 * Size;
Tmp.Canvas.Brush.Color := Color2;
Tmp.Canvas.FillRect(Rect(0, 0, Size, Size));
Tmp.Canvas.FillRect(Bounds(Size, Size, Size, Size));
Target.Canvas.Brush.Bitmap := Tmp;
if Target.Width * Target.Height = 0 then
Target.SetSize(Width, Height)
else
begin
Target.SetSize(Width, Height)
Target.Canvas.FillRect(Rect(0, 0, Width, Height));
end;
finally
Tmp.Free;
end;
end;
进一步优化:缓存此小位图(Tmp
),并在其大小未更改时重复使用。
答案 2 :(得分:-1)
使用这种方法可以获得更好的性能。只是不要传递CellSize = 0.
// Color1, Color2 in RRGGBB format (i.e. Red = $00FF0000)
procedure RenderGrid(Source: TBitmap; CellSize: Integer; Color1, Color2: TColorRef);
var
I, J: Integer;
Pixel: ^TColorRef;
UseColor1: Boolean;
begin
Source.PixelFormat := pf32bit;
Pixel := Source.ScanLine[Source.Height - 1];
for I := 0 to Source.Height - 1 do
begin
UseColor1 := (I div CellSize) mod 2 = 0;
for J := 0 to Source.Width - 1 do
begin
if J mod CellSize = 0 then UseColor1 := not UseColor1;
if UseColor1 then
Pixel^ := Color1
else
Pixel^ := Color2;
Inc(Pixel);
end;
end;
end;