奇怪的问题。也许有人可以提供一些见解。
情景 1。我在内存中有一个 TBitmap,它在进行复杂计算以计算每个像素的颜色时被写入。每隔一段时间(通常在填充位图的每条水平线之后)TBitmap 被绘制到表单上的图像(image1.Canvas.Draw(0, 0, TBitmap)。大多数时候这工作正常,但我注意到如果每条位图线有许多缓慢的复杂计算(比如计算时间超过 30 秒或一分钟),那么主窗体会有一个瞬间“闪烁”,以某种方式擦除位图,所以 image.draw 调用只绘制最新计算的行和前 y 行在位图中被空白。我通过在计算之前锁定位图来解决这个问题。
场景 2。 这是主要的麻烦。我正在写入 TMemoryStream 而不是位图。同样的交易。进行计算以计算每个像素值,然后在此过程中使用 memstream.Write(bytevalue, 1) 将每个像素值写入 TMemoryStream。在所有计算结束时,我使用 memstream.SaveToFile('whatever.bmp') 将流保存到位图,然后使用 memstream.Free 释放流。如果计算很快,那么无论大小如何,流都会保存(我正在做 10000x10000 尺寸的测试)。
我什至可以告诉结果文件将被损坏,因为主应用程序窗口/表单确实有轻微的闪烁,就像它正在重新绘制一样。发生这种情况时,就好像位图和 TMemoryStream 的每个句柄都被杀死/刷新,因此现有数据已损坏。
有任何想法吗?这真的很糟糕。尤其是当每个图像可能需要一个小时才能创建时,才发现当它完成时,后台发生了某些事情并损坏了位图或 TMemoryStream。
有什么方法可以像使用位图一样锁定 TMemoryStream 句柄?这可能会有所帮助。或者一些声明告诉 Delphi “不要弄乱我的对象,即使看起来应用程序花费的时间太长”
或者有谁知道导致这种情况发生的德尔福内部的后端原因。
TMemoryStream 是在执行所有计算的过程中创建的,因此是本地对象。对于位图问题,位图是过程之外的全局变量并且它发生了,所以我认为这不是原因。
这也是在 Windows 7 下,但我注意到 Vista 下的原始位图问题。
更新1:
很抱歉没有使用评论,但是对文本大小有限制...
作为对雷米(以及其他阅读本文的人)的回复……
单线程。对于内存流,如果计算速度很快,它在 5000x5000 分辨率下工作得很好,但如果计算速度很慢,它就会失败。
作为一个基本框架,代码是沿着
SetupMemorystream;
for y:=0 to height do
for x:=0 to width do
DoCalcs;
SetByteValue;
end;
end;
SaveStream;
如果 DoCalcs 相对较快,那么一切都按计划进行。如果它很慢,那么我得到 TMemoryStream 损坏,并且流保存到的结果位图已损坏。
这与使用内存中的 TBitmap 相同,直到我发现我可以锁定位图,这会阻止 Delphi 和/或 Windows “当它想要”时重新分配一个新的句柄,这会破坏位图中的数据。
这太巧合了,以至于不认为 TMemoryStream 及其句柄不会发生同样的问题。
更新 2:
还有一个可能有用的信息。
当 TMemoryStream 保存正常时,生成的文件(对于 5000x5000 位图)大小为 75,000,054 字节。
当保存的流损坏时,它似乎是一个随机值(从句柄损坏到流被保存的大小)。示例大小为 22 MB 和 9 MB。
当我查看生成的文件是一个十六进制编辑器时,它表明文件的开头与标题块是正确的,但尾部会以某种方式被截断。
这太奇怪了。无论如何,我绝对可以肯定在 SaveToFile 调用之后和释放它之前刷新一个 TMemoryStream?