将图像存储为哈希代码C#
我正在建立一个网站,将存储数百万张图片,所以我需要一个唯一的id为每一张图片。什么加密技术最适合存储图像。现在这就是我使用SHA1时代码的样子 sha1旁边是否使用了标准哈希,两个图像是否可能具有相同的哈希代码将图像存储为哈希代码C#,c#,.net,image,hash,C#,.net,Image,Hash,我正在建立一个网站,将存储数百万张图片,所以我需要一个唯一的id为每一张图片。什么加密技术最适合存储图像。现在这就是我使用SHA1时代码的样子 sha1旁边是否使用了标准哈希,两个图像是否可能具有相同的哈希代码 Image img = Image.FromFile("image.jpg"); ImageConverter converter = new ImageConverter(); byte[] byteArray = (byte[])converter.ConvertTo(img
Image img = Image.FromFile("image.jpg");
ImageConverter converter = new ImageConverter();
byte[] byteArray = (byte[])converter.ConvertTo(img, typeof(byte[]));
string hash;
using (SHA1CryptoServiceProvidersha1 = new SHA1CryptoServiceProvider())
{
hash = Convert.ToBase64String(sha1.ComputeHash(byteArray));
}
如果我理解正确,您希望指定一个SHA1值作为文件名,这样您就可以检测到您的收藏中是否已经有该图像。我不认为这是最好的方法(如果你没有运行数据库,那么它可能是),但是,如果你计划拥有数以百万计的图像(出于实际原因),那么就认为不可能发生碰撞 为此,我不推荐使用SHA256,因为它的两个主要优点(抗碰撞+对某些理论攻击的免疫力)并不值得,因为它的速度大约是SHA1的10倍(并且您将散列大量相当大的文件) 您不必担心它的128位长度:为了有50%的机会在128位中找到冲突,您的集合中需要有18446744073709600000个图像(sqrt为2^128)
哦,我不想听起来很自负,但散列和加密是完全不同的东西。事实上,我想说散列更接近于代码签名/数字签名,而不是密码学。您可以使用这两种机制
然后,确定唯一性后,使用文件标识符的GUID或重用现有文件。两个不同的图像是否具有相同的哈希代码?不大可能发生的另一方面,同一图像的两个副本可以有不同的散列吗?当然 取一个无损png,打开它,然后以未压缩的形式重新保存。两个图像的像素将相同,但文件哈希将不同 除了像素,图像还包含元数据字段,如地理位置、日期/时间、相机制造商、相机型号、ISO速度、焦距等 因此,在整体使用图像文件时,哈希将受到压缩类型和元数据的影响 这里的主要问题是:是什么让图片对你来说“独一无二” 例如,如果一张图像已经上传,那么我下载它,删除相机模型或评论,然后重新上传,它对您来说是不同的图像,还是仍然与原始图像相同?位置字段呢 如果我下载一个无损png并将其保存为无损tiff,它将具有相同的像素数据,该怎么办 根据您的要求以及哪些字段很重要,您需要创建相关元数据字段(如果有)与图像的实际未压缩像素数据组合的哈希,而不是使用整个图像文件进行哈希 在
System.Security.Cryptography
中提供的标准哈希算法中,您可能会发现MD5最适合此应用程序。但无论如何都要和不同的人一起玩,看看哪一个最适合你
下面是一个代码示例,它为元数据字段和图像像素的组合获取哈希:
public class ImageHash
{
public string GetHash(string filePath)
{
using (var image = (Bitmap) Image.FromFile(filePath))
return GetHash(image);
}
public string GetHash(Bitmap bitmap)
{
var formatter = new BinaryFormatter();
using (var memoryStream = new MemoryStream())
{
var metafields = GetMetaFields(bitmap).ToArray();
if(metafields.Any())
formatter.Serialize(memoryStream, metafields);
var pixelBytes = GetPixelBytes(bitmap);
memoryStream.Write(pixelBytes, 0, pixelBytes.Length);
using (var hashAlgorithm = GetHashAlgorithm())
{
memoryStream.Seek(0, SeekOrigin.Begin);
var hash = hashAlgorithm.ComputeHash(memoryStream);
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
}
}
}
private static HashAlgorithm GetHashAlgorithm() => MD5.Create();
private static byte[] GetPixelBytes(Bitmap bitmap, PixelFormat pixelFormat = PixelFormat.Format32bppRgb)
{
var lockedBits = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, pixelFormat);
var bufferSize = lockedBits.Height * lockedBits.Stride;
var buffer = new byte[bufferSize];
Marshal.Copy(lockedBits.Scan0, buffer, 0, bufferSize);
bitmap.UnlockBits(lockedBits);
return buffer;
}
private static IEnumerable<KeyValuePair<string,string>> GetMetaFields(Image image)
{
string manufacturer = System.Text.Encoding.ASCII.GetString(image.PropertyItems[1].Value);
yield return new KeyValuePair<string, string>("manufacturer", manufacturer);
// return any other fields you may be interested in
}
}
虽然这是一个良好的开端,但该方法有一些方面可以改进,例如:
如果您只需要为图像分配一个唯一的标识符,为什么不分配一个GUID呢?@David我想OP需要存储唯一的图像。在服务器上有两个完全相同的文件,但名称不同是没有意义的。没错,我希望存储唯一的图像。可能两个有效图像具有相同的哈希代码,是的。如果你只关心唯一的文件名,那么就使用GUID。
var hash = new ImageHash().GetHash(@"some file path");