- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个函数,可以将 TBitmap(我绘制的)转换为 TPngImage,然后将其保存到流中,以便其他方法可以使用它。使用 Png 是因为它为报告输出(excel、html)创建较小的图像。问题是 SaveToStream 似乎花费太多时间,比将 TBitmap 转换为 TPngImage 或使用 TStream 与 png 多 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 的速度这么慢?有什么优化建议吗?
使用德尔福XE7
编辑
这里是示例(MCVE),其中包含简单的 bmp,它被转换为 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.1 毫秒
第 2 步:93 秒 = 93000 毫秒。 93000/70000 = 每幅图像约 1.33 毫秒
第 3 步:6s = 6000ms。 6000/70000 = 每幅图像约 0.086 毫秒
您认为每个 SaveToStream()
1.33 毫秒很慢吗?您只是做了很多事情,所以它们会随着时间的推移而增加,仅此而已。
话虽如此,内存中的 PNG 数据并未被压缩。保存数据时它会被压缩。所以这是经济放缓的原因之一。此外,保存 PNG 会对流进行大量写入,这可能会导致流执行多次内存(重新)分配(TPNGImage
还在保存期间执行内部内存分配),因此这是另一个减慢速度的方法.
Any suggestion to optimize this?
对于压缩开销您无能为力,但您至少可以在调用 SaveToStream()
之前将 TMemoryStream.Capacity
预先设置为合理的值减少写入期间 TMemoryStream
需要执行的内存重新分配。你不需要精确地对待它。如果写入流导致其Size
超过其当前Capacity
,它只会相应地增加其Capacity
。由于您已经处理了 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.Width, PNGImage.Height); // Step 3: Add PNG from Stream to Excel
finally
PNGStream.Free;
end;
finally
PNGImage.Free;
end;
...
如果这对您来说仍然不够快,请考虑使用线程并行处理多个图像。不要按顺序处理它们。
关于delphi - 有什么方法可以加快 TPNGImage 上的 SaveToStream 速度吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31861258/
实际上,我对以下如何解决我的问题有一些想法: 我有TCRTBGrid,用户可以在其中移动列并更改宽度。我想将设置保存在数据库中。我想我可以通过使用 Columns.LoadFromStream a
我有一个函数,可以将 TBitmap(我绘制的)转换为 TPngImage,然后将其保存到流中,以便其他方法可以使用它。使用 Png 是因为它为报告输出(excel、html)创建较小的图像。问题是
我尝试通过 RadServer IIS 包和 Delphi 客户端与 EMSEndpoint 交换数据。我尝试的事情对我来说看起来很简单,但我现在无法完成。 在包中有一个指向 MSSql 服务器的 T
我是一名优秀的程序员,十分优秀!