delphi – 有什么方法可以加速TPNGImage上的SaveToStream?

前端之家收集整理的这篇文章主要介绍了delphi – 有什么方法可以加速TPNGImage上的SaveToStream?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个函数将TBitmap(我绘制)转换为TPng Image,然后将其保存为流,因此其他方法可以使用它.使用Png是因为它为报告输出创建了较小的图像(excel,html).问题是SaveToStream似乎花费了太多时间,比将TBitmap转换为TPngImage或使用带有png的TStream多15倍.这是代码
var
 BitmapImage: TBitmap;      
 PNGImage: TPngImage;
 PngStream: TStream;        
begin
  // draw on BitmapImage
  ...
  PNGImage := TPngImage.Create;
  PNGStream := TMemoryStream.Create;
  Try
     PNGImage.Assign(BitmapPicture.Bitmap); // Step 1: assign TBitmap to PNG
     PNGImage.SaveToStream(PNGStream);  // Step 2: save PNG to stream
     WS.Shapes.AddPicture(PNGStream,PNGImage.Width,PNGImage.Height); // Step 3: Add PNG from Stream to Excel
  finally
     PNGImage.Free;
     PNGStream.Free;
  end;
...

这是通过70000张图片测试的,以下是时间:
第1步:7秒

第2步:93秒

第3步:6秒

为什么保存到Stream这么慢?有什么建议可以优化吗?

使用Delphi XE7

编辑

这是带有简单bmp的示例(MCVE),它将转换为PNG,然后保存到流中.只是为了另一个验证,我添加了SaveToFile,当然需要更长时间,但它保存到磁盘,所以我认为可以接受.

img1.bmp为49.5KB,保存的PNG为661字节.
链接到img1.bmp = http://www.filedropper.com/img1_1

TMemoryStreamAccess = class(TMemoryStream)
  end;

procedure TForm1.Button1Click(Sender: TObject);
var BitmapImage:TBitmap;
  PNGImage:TPngImage;
  PNGStream:TMemoryStream;//TStream;
  i,t1,t2,t3,t4,t5,t6: Integer;
  vFileName:string;
begin

  BitmapImage:=TBitmap.Create;
  BitmapImage.LoadFromFile('c:\tmp\img1.bmp');

  t1:=0; t2:=0; t3:=0; t4:=0; t5:=0; t6:=0;

  for i := 1 to 70000 do
  begin

    PNGImage:=TPngImage.Create;
    PNGStream:=TMemoryStream.Create;
    try

      t1:=GetTickCount;
      PNGImage.Assign(BitmapImage);
      t2:=t2+GetTickCount-t1;

      t3:=GetTickCount;
      TMemoryStreamAccess(PNGStream).Capacity := 1000;
      PNGImage.SaveToStream(PNGStream);
      // BitmapImage.SaveToStream(PNGStream); <-- very fast!
      t4:=t4+GetTickCount-t3;

    finally
      PNGImage.Free;
      PNGstream.Free
    end;

  end;

   showmessage('Assign = '+inttostr(t2)+' - SaveToStream = '+inttostr(t4));
end;

解决方法

This is tested with 70000 images and here are the timings:

Step 1: 7 s

Step 2: 93 s

Step 3: 6 s

Why is saving to Stream so slow?

让我们来处理一些数字:

步骤1:7s = 7000ms. 7000/70000 =每张图像0.1ms

步骤2:93s = 93000ms.每张图像93000/70000 = ~1.33ms

第3步:6s = 6000ms.每张图像6000/70000 = ~0.086ms

你认为每个SaveToStream()的1.33毫秒是慢吗?你只是做了很多,所以他们随着时间的推移加起来,就是这样.

话虽这么说,内存中的PNG数据不会被压缩.保存数据时会压缩它.这是减速的一个原因.此外,保存PNG会对流进行大量写入操作,这会导致流执行多个内存(重新)分配(TPNGImage还会在保存期间执行内部内存分配),这是另一个减速.

Any suggestion to optimize this?

您无法对压缩开销做任何事情,但在调用SaveToStream()之前,您至少可以预先将TMemoryStream.Capacity设置为合理的值,以减少TMemoryStream在写入期间需要执行的内存重新分配.你不需要精确它.如果写入流导致其大小超过其当前容量,则只会相应地增加其容量.由于您已经处理了70000个图像,因此请考虑它们的平均大小并向其添加几个KB,并将其用作初始容量.

type
  TMemoryStreamAccess = class(TMemoryStream)
  end;

var
  BitmapImage: TBitmap;      
  PNGImage: TPngImage;
  PngStream: TMemoryStream;        
begin
  // draw on BitmapImage
  ...
  PNGImage := TPngImage.Create;
  Try
    PNGImage.Assign(BitmapPicture.Bitmap); // Step 1: assign TBitmap to PNG
    PNGStream := TMemoryStream.Create;
    try
      TMemoryStreamAccess(PNGStream).Capacity := ...; // some reasonable value
      PNGImage.SaveToStream(PNGStream);  // Step 2: save PNG to stream
      WS.Shapes.AddPicture(PNGStream,PNGImage.Height); // Step 3: Add PNG from Stream to Excel
    finally
      PNGStream.Free;
    end;
  finally
    PNGImage.Free;
  end;
  ...

如果仍然不够快,请考虑使用线程并行处理多个图像.不要按顺序处理它们.

猜你在找的Delphi相关文章