Skip to content

利用hash对比算法过滤用户上传的相同图片 🖼️ ​

背景 🎯 ​

在实际开发中,我们经常需要防止用户重复上传相同的图片,以节省服务器存储空间并提升用户体验。本文将介绍如何使用图片哈希对比算法来实现这个功能。

实现原理 💡 ​

  1. 当用户上传图片时,先将图片转换为 base64 格式
  2. 使用 SparkMD5 算法计算图片的哈希值
  3. 将哈希值存入 Set 集合中进行去重判断
  4. 根据判断结果决定是否继续上传流程

代码实现 ⌨️ ​

javascript
// 1. 处理文件输入变化
const handleFileInputChange = async (e) => {
  hashFilterSet([...e.target.files]);
};  

// 2. 哈希过滤处理
const hashFilterSet = async (arr) => {
  let fileList = [];
  for (const file of arr) {
    try {
      const hash = await calculateImageHash(file);
      
      if (uploadedImages.has(hash)) {
        console.log('检测到重复图片:', hash);
        tip({
          type: "warning",
          content: "请勿上传相同的图片",
        });
      } else {
        fileList.push(file);
        setUploadedImages(new Set([...uploadedImages, hash]));
      }
    } catch (error) {
      console.error('计算图片哈希值出错:', error);
    }
  }
  // 处理通过验证的文件
  handlerFiles(fileList);
}

// 3. 计算图片哈希值
const calculateImageHash = (file) => {
  return new Promise((resolve, reject) => {
    const imgHash = new Image();
    imgHash.onload = () => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      canvas.width = imgHash.width;
      canvas.height = imgHash.height;
      ctx.drawImage(imgHash, 0, 0, imgHash.width, imgHash.height);
      const data = canvas.toDataURL('image/jpeg');
      hashString(data).then(resolve);
    };
    imgHash.onerror = reject;
    imgHash.src = URL.createObjectURL(file);
  });
}

// 4. 使用 SparkMD5 计算哈希值
const hashString = (str) => {
  return new Promise((resolve) => {
    const spark = new SparkMD5.ArrayBuffer();
    const enc = new TextEncoder();
    const data = enc.encode(str);
    spark.append(data);
    resolve(spark.end());
  });
}

注意事项 ⚠️ ​

  1. 需要提前引入 SparkMD5 库
  2. 图片哈希对比不是完全可靠的,可能存在极少数误判情况
  3. 对于大图片,建议在计算哈希值之前进行适当压缩
  4. 建议在服务端也进行一次查重验证,确保数据安全

优化建议 🚀 ​

  1. 可以考虑使用 Web Worker 来进行哈希计算,避免阻塞主线程
  2. 可以实现图片预览功能,提升用户体验
  3. 可以添加上传进度提示
  4. 可以设置文件大小和类型限制

总结 📝 ​

通过使用哈希对比算法,我们可以有效地过滤重复图片上传。这个方案实现简单,性能较好,适用于大多数图片上传场景。在实际应用中,可以根据具体需求进行适当的调整和优化。

参考资料 📚 ​