C# 图形的快速CRC。位图

C# 图形的快速CRC。位图,c#,caching,bitmap,crc,C#,Caching,Bitmap,Crc,在应用程序启动时,我构建一个图标缓存(24x24 32bbp预乘argb位图)。这个缓存包含大约一千个项目。出于内存和性能方面的原因,我不想在这个缓存中多次存储同一个映像。我认为最好的方法是在每个位图进入缓存时创建某种crc,并将新位图与crc列表进行比较 从仅加载在内存中的位图创建crc的好(快)方法是什么 还是我完全走错了路,有没有更好的方法来构建位图缓存?CRC与任何哈希函数都有相同的缺陷:相等的CRC值不能证明图像是相同的。您的程序将随机但不经常显示错误的图像 你还需要别的东西。就像您从

在应用程序启动时,我构建一个图标缓存(24x24 32bbp预乘argb位图)。这个缓存包含大约一千个项目。出于内存和性能方面的原因,我不想在这个缓存中多次存储同一个映像。我认为最好的方法是在每个位图进入缓存时创建某种crc,并将新位图与crc列表进行比较

从仅加载在内存中的位图创建crc的好(快)方法是什么


还是我完全走错了路,有没有更好的方法来构建位图缓存?

CRC与任何哈希函数都有相同的缺陷:相等的CRC值不能证明图像是相同的。您的程序将随机但不经常显示错误的图像


你还需要别的东西。就像您从中检索位图的文件名一样。

虽然我会重复Hans所说的,但我相信您可以做到这一点,但CRC是一种糟糕的算法

您可以改为创建生成位图字节的MD5哈希。根据我的计算,您的图像的大小必须至少为2Kb。要生成散列,您可以在整个位图中计算它,也可以偷偷地在每n个字节上进行计算-这在散列端会更快,但可能会占用更多内存,因为您必须将这些字节提取到新数组中

如果你要跳过每N个字节,我会使用4或2-使用4意味着你从每个连续像素中读取一个组件,使用两个意味着你从每个连续像素中读取两个组件

然而,MD5速度非常快,您可能会发现(我会在单元测试中对此进行基准测试),仅对整个位图进行哈希运算会更快

唯一的问题是,我看不出你如何在不事先知道它是散列的情况下提前检查是否应该生成给定的位图,而知道它是散列的唯一方法就是生成它。在这种情况下,此时您最好只保存新图像。图像缓存阵列中的一个额外元素不会破坏整个世界

为了节省空间和启动时间,您真正需要做的是在生成图像之前知道它是否与另一个图像相同。假设这些图像是动态生成的,那么当生成两个相同的图像时,它们是由具有相同参数的相同方法调用生成的吗

如果是这样,您可以改为使用一个或多个hashcode(使用
object.GetHashCode()
)为生成图像的方法的
MethodInfo
标记每个生成的图像(您可以通过调用
MethodBase.GetCurrentMethod()在方法本身内部获得该标记)
,以及传入的每个参数的每个hashcode。该方法的hashcode非常可靠,因为它使用运行时的方法句柄(对于每个方法都是唯一的)-在64位机器上,唯一可能发生的哈希代码压缩是句柄为64位,但哈希代码为32位。然而,在实践中,这种冲突很少发生,因为应用程序中必须有大量代码才能导致两个单独方法句柄的前32位相同

当然,除非这些参数类型具有良好的散列码函数,否则各个参数的散列码的可靠性要低得多


这个解决方案绝对不是完美的(最坏的情况下,你仍然会得到一些副本),但我认为这会加快速度。不过,正如我所说,这取决于您的复制图像总是由相同的调用生成。

嗨,Hans,图像通常来自资源,甚至可能是使用绘图功能当场创建的。没有文件名。您使用什么标识符从缓存中检索图像?同时nt我正在返回一个索引到图像数组中。缓存和重复测试都应该在幕后进行。Andras,非常感谢你给出了广泛的答案。我已经实现了位图字节的MD5哈希,初始测试很好。没有误报,没有误报。图像缓存现在包含大约500个条目(未来会有更多),但我的应用程序中使用这些图标的实例数很容易达到数千个。这是我希望摆脱的开销。@David Rutten:很高兴能提供帮助。这是一个有趣的挑战(我相信还有其他方法,但我认为这可能是最好的“简单”解决方案)。我在数据库中存储7k+的XML时遇到了类似的问题,但我不希望存储重复。我使用MD5哈希处理,但从未遇到冲突。