【发布时间】:2009-11-06 01:16:50
【问题描述】:
我正在尝试比较文件系统中的两个 UIImage 以查看它们是否相同。显然,我不能使用 NSObject 的 hash 方法,因为它返回的是对象的 hash,而不是实际的图像数据。
我发现代码从字符串生成 MD5 哈希,但我还没有发现如何为 UIImage 实现它。
我应该如何对 UIImage 进行散列处理?还是我的图像比较方法完全关闭了?
【问题讨论】:
标签: iphone cocoa-touch hash
我正在尝试比较文件系统中的两个 UIImage 以查看它们是否相同。显然,我不能使用 NSObject 的 hash 方法,因为它返回的是对象的 hash,而不是实际的图像数据。
我发现代码从字符串生成 MD5 哈希,但我还没有发现如何为 UIImage 实现它。
我应该如何对 UIImage 进行散列处理?还是我的图像比较方法完全关闭了?
【问题讨论】:
标签: iphone cocoa-touch hash
我最终使用以下代码来完成任务。请注意,这需要您导入 <CommonCrypto/CommonDigest.h>:
unsigned char result[CC_MD5_DIGEST_LENGTH];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(inImage)];
CC_MD5([imageData bytes], [imageData length], result);
NSString *imageHash = [NSString stringWithFormat:
@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]
];
【讨论】:
CC_MD5_DIGEST_LENGTH 而不是16,以防值发生变化。
不是最优解:
[ UIImagePNGRepresentation( uiImage1 ) isEqualToData:
UIImagePNGRepresentation( uiImage2 ) ];
这基本上比较了 2 张图像的 PNG 编码数据。由于图像相似性是一个复杂的主题,因此可以根据最终目标的确切含义来设计更好更快的解决方案(即,您是要逐像素比较图像,还是只是近似相似性,这可以使用源的下采样版本图片等)。
【讨论】:
Swift 4.2 中使用 SHA256 算法对 UIImage 进行哈希处理的 Swift 代码。您可以使用其他算法,这些算法可能更快或生成的重复次数更少,但对于大多数用例来说,这个已经足够了。
只需将代码放在项目中的某处并像这样使用它:yourUIImage.sha256()
extension UIImage{
public func sha256() -> String{
if let imageData = cgImage?.dataProvider?.data as? Data {
return hexStringFromData(input: digest(input: imageData as NSData))
}
return ""
}
private func digest(input : NSData) -> NSData {
let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
var hash = [UInt8](repeating: 0, count: digestLength)
CC_SHA256(input.bytes, UInt32(input.length), &hash)
return NSData(bytes: hash, length: digestLength)
}
private func hexStringFromData(input: NSData) -> String {
var bytes = [UInt8](repeating: 0, count: input.length)
input.getBytes(&bytes, length: input.length)
var hexString = ""
for byte in bytes {
hexString += String(format:"%02x", UInt8(byte))
}
return hexString
}
}
顺便说一下,您需要一个导入 CommonCrypto 的桥接头。如果您没有,请按照以下步骤操作:
BridgingHeader
ProjectName/BridgingHeader.h
#import <CommonCrypto/CommonHMAC.h> 放入您的头文件中重复概率很低,但如果你有庞大的数据集,你可以相对容易地升级到 SHA512:
重复概率大约是:
【讨论】:
下面有更优雅的代码
+(NSString *)MD5HexDigest:(NSData *)input {
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(input.bytes, (unsigned int)input.length, result);
NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
for (int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {
[ret appendFormat:@"%02x",result[i]];
}
return ret;
}
【讨论】:
这个更新的 sn-p 应该可以工作。感谢andreas's answer 提供大纲。
// Usage
image.sha256
// extensions
import CommonCrypto
extension UIImage {
var sha256: String {
guard let imageData = jpegData(compressionQuality: 1) else { return "" }
return imageData.digest.hexString
}
}
extension Data {
var digest: Data {
let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
var hash = [UInt8](repeating: 0, count: digestLength)
CC_SHA256(bytes, UInt32(count), &hash)
return Data(bytes: hash, count: digestLength)
}
var hexString: String {
let hexString = map { String(format: "%02.2hhx", $0) }.joined()
return hexString
}
}
【讨论】: