在不使用GDI +的情况下在画布上绘制PNG格式图片

时间:2013-08-02 09:11:27

标签: delphi png gdi+ delphi-xe4

我需要在画布上绘制一个PNG(在TPicture中),其要求如下:

  1. 它需要非常快(由于目标PC运行缓慢的CPU)。
  2. 它不应该需要任何额外的库来增加exe的大小(由于目标PC通过2G移动连接自动更新)。
  3. 下面的代码完成了这项工作,但使用了 GDI + 和:

    1. 比使用BitBlt绘制简单的非透明位图慢得多。在快速处理器上,绘制时间从1ms增加到16ms。在慢速CPU上,它从100ms增加到900ms。
    2. 将exe的大小增加约0.5MB。
    3. 这是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 +方法完全相同。有没有什么方法可以优化它?

1 个答案:

答案 0 :(得分:3)

在我看来,你不必要地采用内存中的图形,压缩到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图像,这也会带来快乐的好处。