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张图片测试的,以下是时间: 第2步:93秒 第3步:6秒 为什么保存到Stream这么慢?有什么建议可以优化吗? 使用Delphi XE7 编辑 这是带有简单bmp的示例(MCVE),它将转换为PNG,然后保存到流中.只是为了另一个验证,我添加了SaveToFile,当然需要更长时间,但它保存到磁盘,所以我认为可以接受. img1.bmp为49.5KB,保存的PNG为661字节. 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:tmpimg1.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; 解决方法
让我们来处理一些数字: 步骤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还会在保存期间执行内部内存分配),这是另一个减速.
您无法对压缩开销做任何事情,但在调用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; ... 如果仍然不够快,请考虑使用线程并行处理多个图像.不要按顺序处理它们. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |