Мне нужно нарисовать PNG (в TPicture) на холсте со следующими требованиями:
- Он должен быть очень быстрым (из-за того, что на целевом ПК работает медленный процессор).
- Он не требует дополнительных библиотек, которые увеличивают размер exe (из-за автоматического обновления целевого ПК через мобильное соединение 2G).
Приведенный ниже код выполняет свою работу, но использует GDI + и:
- Это намного медленнее, чем рисование простого непрозрачного растрового изображения с использованием
BitBlt
. На быстром процессоре время прорисовки увеличивается с 1 мс до 16 мс. На медленном процессоре оно увеличивается со 100 мс до 900 мс. - Увеличивает размер exe примерно на 0,5 МБ.
Вот код GDI +. Он предназначен для возврата к стандартному BitBlt, если:
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
ComCtrls, ExtCtrls,
GDIPObj, GDIPAPI;
...
procedure DrawPictureToBitmap(Bitmap: TBitmap; X, Y: Integer; Picture: TPicture);
function PictureToGPBitmap(Picture: TPicture): TGPBitmap;
var
MemStream: TMemoryStream;
begin
MemStream := TMemoryStream.Create;
try
Picture.Graphic.SaveToStream(MemStream);
MemStream.Position := 0;
Result := TGPBitmap.Create(TStreamAdapter.Create(MemStream));
finally
FreeAndNil(MemStream);
end;
end;
var
GDICanvas: TGPGraphics;
GPImage: TGPImage;
begin
GDICanvas := TGPGraphics.Create(Bitmap.Canvas.Handle);
try
GPImage := PictureToGPBitmap(Picture);
try
GDICanvas.DrawImage(GPImage, X, Y);
// Did the draw succeed?
if GDICanvas.GetLastStatus <> Ok then
begin
// No, try a BitBlt!
BitBlt(Bitmap.Canvas.Handle, X, Y, Bitmap.Height, Bitmap.Width, Picture.Bitmap.Canvas.Handle, 0, 0, SRCCOPY);
end;
finally
FreeAndNil(GPImage);
end;
finally
FreeAndNil(GDICanvas);
end;
end;
Обновление 1
Используя предложение Дэвида, мне удалось избавиться от GDI +, используя встроенную в Delphi поддержку PNG.
procedure DrawPictureToBitmap(Bitmap: TBitmap; X, Y: Integer; Picture: TPicture);
var
PNG: TPngImage;
MemStream: TMemoryStream;
begin
PNG := TPngImage.Create;
try
MemStream := TMemoryStream.Create;
try
Picture.Graphic.SaveToStream(MemStream);
MemStream.Position := 0;
PNG.LoadFromStream(MemStream);
finally
FreeAndNil(MemStream);
end;
PNG.Draw(Bitmap.Canvas, Rect(X, Y, X + Picture.Width, Y + Picture.Height));
finally
FreeAndNil(PNG);
end;
end;
К сожалению, время прорисовки точно такое же, как и у метода GDI +. Есть ли способ, которым это можно оптимизировать?