This is about Delphi, 32 bits and Windows/VCL:
For a procedure that takes an input bitmap and writes to an output bitmap with a given format (PixelFormat: pf8Bit with a gray scale palette) I use the following code:
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;
The Output bitmap might not be empty when it is being passed to this procedure, but might contain anything in any format. It will be completely overwritten in the procedure.
I wonder whether simply changing its PixelFormat might create some overhead (e.g. convert the old content to the new pixel format), so should I somehow clear it first, e.g. by calling _outBmp.SetSize(0, 0) or any other means? If yes, what would be the most efficient way?
EDIT:
I just did some timing with this code:
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;
The result on my computer (which is not slow): 5.331 [s] vs. 0.322 [s]
Unless I made an implementation error, this is quite significant. This is admittedly with a rather large bitmap though, but even with a more resonable size of 4096x4096 I get 0.693 vs. 0.040 which is still significant if this operation is executed many times (which it will be: several million times in fact).
This answers the question of whether there is a performance impact with a clear yes.
The remaining question is: Is SetSize(0,0) the most efficient way to clear a bitmap or is there a better way?
EDIT2:
TBitmap.Assign(nil) is another way to clear the bitmap:
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;
The timing is similar to .SetSize(0, 0).
I don't know the answer, but the test is flawed. The first set ends with a pf8bit correctly sized bitmap, the second is pf8bit 0x0. This is not the same. Somehow you don't allocate 10 times 16*1024 x 8 *1024 = 128MB bitmaps there.
The easiest option is of course to never change bittiness on existing bitmaps, but simply create a new one. With such large bitmaps, resizing and changing pixel type should be avoided at all costs if you care about performance.