【发布时间】:2020-04-21 01:17:58
【问题描述】:
这是关于 Delphi、32 位和 Windows/VCL:
对于接受输入位图并以给定格式(PixelFormat:pf8Bit 带灰度调色板)写入输出位图的过程,我使用以下代码:
procedure ConvertBitmap(_inBmp: TBitmap; _outBmp: TBitmap);
begin
_outBmp.PixelFormat := pf8Bit;
_outBmp.Palette := MakeGrayPalette();
_outBmp.SetSize(_inBmp.Width, _inBmp.Height);
// code that works on ScanLines goes here
end;
输出位图在传递给此过程时可能不为空,但可能包含任何格式的任何内容。它将在程序中被完全覆盖。
我想知道简单地更改它的 PixelFormat 是否会产生一些开销(例如,将旧内容转换为新的像素格式),所以我应该先以某种方式清除它,例如通过调用 _outBmp.SetSize(0, 0) 或任何其他方式?如果是,最有效的方法是什么?
编辑:
我只是用这段代码做了一些计时:
procedure TimingTest;
var
Stopwatch1: TStopwatch;
Stopwatch2: TStopwatch;
bmp: TBitmap;
i: Integer;
begin
bmp := TBitmap.Create;
try
Stopwatch1 := TStopwatch.Create;
Stopwatch2 := TStopwatch.Create;
for i := 0 to 10 - 1 do begin
bmp.PixelFormat := pf24bit;
bmp.SetSize(16 * 1024, 8 * 1024);
Stopwatch1.Start;
bmp.PixelFormat := pf8bit;
bmp.Palette := MakeGrayPalette();
Stopwatch1.Stop;
end;
for i := 0 to 10 - 1 do begin
bmp.PixelFormat := pf24bit;
bmp.SetSize(16 * 1024, 8 * 1024);
Stopwatch2.Start;
bmp.SetSize(0, 0);
bmp.PixelFormat := pf8bit;
bmp.Palette := MakeGrayPalette();
Stopwatch2.Stop;
end;
l_Timing.Caption := Format('%.3f [s] vs %.3f [s]', [
Stopwatch1.ElapsedMilliseconds / 1000, Stopwatch2.ElapsedMilliseconds / 1000]);
finally
FreeAndNil(bmp);
end;
end;
我电脑上的结果(不慢): 5.331 [s] 与 0.322 [s]
除非我犯了实施错误,否则这非常重要。诚然,这是一个相当大的位图,但即使使用更合理的 4096x4096 尺寸,我也会得到 0.693 与 0.040,如果多次执行此操作(实际上将是:几百万次),这仍然很重要。
这回答了是否对性能有影响的问题,答案是肯定的。
剩下的问题是:SetSize(0,0) 是清除位图最有效的方法还是有更好的方法?
EDIT2:
TBitmap.Assign(nil) 是另一种清除位图的方法:
for i := 0 to 10 - 1 do begin
bmp.PixelFormat := pf24bit;
bmp.SetSize(16 * 1024, 8 * 1024);
Stopwatch3.Start;
bmp.Assign(nil);
bmp.PixelFormat := pf8bit;
bmp.Palette := MakeGrayPalette();
Stopwatch3.Stop;
end;
时序类似于.SetSize(0, 0)。
【问题讨论】:
-
您对目前的代码有实际问题吗?
-
这不是问题,但是总的代码(包括隐藏在 // ScanLines 上的代码)可能需要一些性能改进。到目前为止,我已经减少了对 TBitmap.ScanLine[] 的调用次数,这很有帮助,并将 PixelFormat 从 pf24Bit 减少到 pf8Bit,这也得到了一些微秒。现在我正在研究其他领域,这让我觉得可能会提高性能。 (在你问之前:不,我还没有做任何时间安排,但我正在这样做。)
-
当您不知道这是否有任何好处时,询问如何清除位图(无论这意味着什么)是没有意义的。您应该尝试根据可衡量的数据优化您的代码。
-
0.324s 与 0.322s 相同,完全在可变性范围内。我认为
Assign(nil)是清除实例的规范方式。但是,我可能会选择创建一个新的位图实例。如果您关心性能,那么您可能会考虑使用 graphics32 之类的库。 -
我猜你对 TBitmap.Create 的成本有误。在看到毫秒范围内的时间之前,我需要将循环增加到 100。即使是 Free/Create 也与将大小设置为 0 一样快。
标签: delphi vcl delphi-2007 tbitmap