You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Next.js中上传图片至服务器时生成blurhash的实现方案

前端生成BlurHash的实现方案

步骤1:安装依赖

安装blurhash库,它支持在前端环境下生成和解析BlurHash:

npm install blurhash
# 或
yarn add blurhash

步骤2:在上传流程中生成BlurHash

先封装一个从文件生成BlurHash的异步工具函数,再修改react-dropzone的文件处理逻辑,把生成的Hash和图片信息一起存储:

封装生成BlurHash的函数

import { encode } from 'blurhash';

async function generateBlurHash(file) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.src = URL.createObjectURL(file);
    
    img.onload = () => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      // 设置小尺寸画布生成BlurHash,32x32是平衡效果与性能的常用值
      const width = 32;
      const height = Math.round((img.height / img.width) * width);
      canvas.width = width;
      canvas.height = height;
      
      ctx.drawImage(img, 0, 0, width, height);
      const imageData = ctx.getImageData(0, 0, width, height);
      
      // 生成BlurHash,最后两个参数是组件数,数值越小Hash越短、模糊效果越粗糙
      const hash = encode(imageData.data, width, height, 4, 4);
      resolve(hash);
      
      // 清理临时URL避免内存泄漏
      URL.revokeObjectURL(img.src);
    };
    
    img.onerror = (err) => {
      reject(err);
      URL.revokeObjectURL(img.src);
    };
  });
}

修改上传逻辑

const {getRootProps, getInputProps} = useDropzone({
  onDrop: async (acceptedFiles) => {
    // 先做数量校验,提前终止无效操作
    const totalCount = acceptedFiles.length + files.length;
    if (totalCount > 9) {
      alert("最多选择9张图片");
      return;
    }
    if (acceptedFiles.length > 9) {
      alert("单次最多选择9张图片");
      return;
    }

    // 遍历处理每个文件
    for (const [index, file] of acceptedFiles.entries()) {
      // 检查重复图片
      const isDuplicate = files.some(existing => existing.name === file.name);
      if (isDuplicate) {
        alert("检测到重复图片");
        continue;
      }

      try {
        const options = {
          maxSizeMB: 5,
          maxWidthOrHeight: 1920,
          useWebWorker: true,
        };
        const compressedFile = await imageCompression(file, options);
        
        // 生成BlurHash并加入文件对象
        const blurHash = await generateBlurHash(compressedFile);
        
        setFiles(prevState => [
          ...prevState,
          {
            id: index,
            src: URL.createObjectURL(compressedFile),
            name: file.name,
            blurHash // 存储BlurHash,后续上传到Firebase时一并保存
          }
        ]);
      } catch (err) {
        console.error("图片处理失败:", err);
        alert("图片处理失败,请重试");
      }
    }
  },
})

步骤3:为Next.js Image生成blurDataURL

从Firebase获取图片URL和对应的BlurHash后,用blurhash的解码方法生成base64格式的模糊图,作为blurDataURL传入Next.js Image组件:

import { decode } from 'blurhash';

function getBlurDataURL(blurHash) {
  if (!blurHash) return '';
  // 解码BlurHash为像素数据
  const pixels = decode(blurHash, 32, 32);
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const imageData = ctx.createImageData(32, 32);
  imageData.data.set(pixels);
  ctx.putImageData(imageData, 0, 0);
  return canvas.toDataURL(); // 转换为base64格式
}

// 使用Next.js Image组件示例
<Image
  src={imageUrl}
  alt="图片描述"
  width={1920}
  height={1080}
  blurDataURL={getBlurDataURL(imageBlurHash)}
  placeholder="blur"
/>

注意事项

  • BlurHash的组件数(encode方法最后两个参数):建议用3x3或4x4,平衡Hash长度与模糊效果。
  • 务必清理临时生成的objectURL,避免内存泄漏。
  • 所有异步操作需加try/catch,处理图片加载、压缩、Hash生成时的异常。

内容的提问来源于stack exchange,提问作者Mohammed Bekele

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 03:52:36