2

次の要件でキャンバスに PNG を (TPicture で) 描画する必要があります。

  1. 非常に高速である必要があります (ターゲット PC の CPU が遅いため)。
  2. exe のサイズを大きくする追加のライブラリは必要ありません (2G モバイル接続を介したターゲット PC の自動更新のため)。

以下のコードは仕事をしますが、GDI+と以下を使用します:

  1. を使用して単純な不透明ビットマップを描画するよりもはるかに遅くなりますBitBlt。高速プロセッサでは、描画時間が 1 ミリ秒から 16 ミリ秒に増加します。遅い CPU では、100 ミリ秒から 900 ミリ秒に増加します。
  2. exeのサイズを約0.5MB増やします。

これが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

David の提案を使用して、Delphi のビルトイン PNG サポートを使用して GDI+ を取り除くことができました。

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+ 方式とまったく同じです。これを最適化する方法はありますか?

4

1 に答える 1

4

不必要にメモリ内のグラフィックを取得し、PNG に圧縮してから解凍しているように思えます。グラフィックを直接描画できます。

Drawビットマップ キャンバスを呼び出すだけで次のように渡されPicture.Graphicます。

procedure DrawPictureToBitmap(Bitmap: TBitmap; X, Y: Integer; Picture: TPicture);
begin
  Bitmap.Canvas.Draw(X, Y, Picture.Graphic);
end;

その時点で、おそらくDrawPictureToBitmap無意味であると判断し、それを削除してBitmap.Canvas.Draw()直接呼び出すでしょう。

これには、質問のコードのように、画像が PNG 画像を含むものに限定されないという嬉しい利点もあります。

于 2013-08-02T10:05:49.173 に答える