gpt4 book ai didi

delphi - 有什么方法可以加快 TPNGImage 上的 SaveToStream 速度吗?

转载 作者:行者123 更新时间:2023-12-03 14:59:17 27 4
gpt4 key购买 nike

我有一个函数,可以将 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/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com