2013-08-02 1 views
1

je dois dessiner un PNG (dans un TPicture) sur une toile avec les exigences suivantes:Dessiner un PNG formated TPicture sur une toile sans utiliser GDI +

  1. Il doit être très rapide (en raison de l'ordinateur cible courir un processeur lent).
  2. Il ne devrait pas nécessiter de bibliothèques supplémentaires qui augmenteront la taille de l'exe (en raison de la mise à jour automatique du PC cible sur une connexion mobile 2G).

Le code ci-dessous est le travail, mais utilise GDI + et:

  1. est beaucoup plus lent que le dessin d'un simple bitmap non transparent à l'aide BitBlt. Sur un processeur rapide, le temps de tirage passe de 1ms à 16ms. Sur un processeur lent, il passe de 100ms à 900ms.
  2. Augmente la taille de l'exe d'environ 0,5 Mo.

Voici le code GDI +. Il est conçu pour revenir à un BitBlt standard si le:

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; 

Update 1

En utilisant la suggestion de David j'ai réussi à se débarrasser de GDI + en utilisant un support intégré PNG de Delphi.

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; 

Malheureusement, le temps de tirage est exactement le même que celui de la méthode GDI +. Y a-t-il un moyen de l'optimiser?

+0

@DavidHeffernan - Bonne idée. Cela permet de se débarrasser de la dépendance GDI +, mais le temps de tirage ne s'améliore pas. Voir ma mise à jour ci-dessus. – norgepaul

+2

Pourquoi ne pas simplement DestinationCanvas.Draw (X, Y, Image1.Picture.Graphic); – bummi

Répondre

2

Il me semble que vous prenez inutilement un graphique en mémoire, en le compressant au format PNG, puis en le décompressant. Vous pouvez dessiner le graphique directement.

Appelez simplement Draw sur votre toile bitmap passant Picture.Graphic:

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

à quel point vous auriez probablement décider que le DrawPictureToBitmap est inutile, retirez-le et appelez directement Bitmap.Canvas.Draw().

Cela aura également l'heureux avantage que votre image ne se limite pas à contenir une image PNG, selon le code de la question.

+0

Super, qui a résolu les deux problèmes. – norgepaul

Questions connexes