如何实现高效JS/TS算法将Blurhash转换为灰度图?
解决Blurhash转灰度后的拉伸变形问题
问题分析
你的代码出现拉伸变形的核心原因是编码时的xComponents和yComponents比例与图片宽高比不匹配:你固定使用了4和3作为分量数,但图片宽高比由ASPECT_RATIO决定(比如头像通常是1:1),分量比例(4:3)和图片比例不一致,导致编码后的Blurhash色块分布失衡,最终显示拉伸。
另外,简单的RGB平均计算灰度的方式不够准确,建议使用行业标准的加权灰度公式。
修复后的代码
const WIDTH = 30; const ASPECT_RATIO = validationConfig.media.profilePicture.aspectRatio; const HEIGHT = Math.floor(WIDTH / ASPECT_RATIO); // 根据宽高比计算匹配的分量数,保证比例一致 const X_COMPONENTS = 4; const Y_COMPONENTS = Math.round(X_COMPONENTS / ASPECT_RATIO); export function convertBlurhashToGreyscale(blurhash: string) { // 解码Blurhash为像素数组 const pixels = decode(blurhash, WIDTH, HEIGHT); // 用ITU-R BT.601标准公式计算灰度,比简单平均更准确 for (let i = 0; i < pixels.length; i += 4) { const r = pixels[i]; const g = pixels[i + 1]; const b = pixels[i + 2]; const grayValue = Math.round(0.299 * r + 0.587 * g + 0.114 * b); pixels[i] = grayValue; pixels[i + 1] = grayValue; pixels[i + 2] = grayValue; pixels[i + 3] = 255; // 保持不透明 } // 编码时使用匹配比例的分量数,且宽高与解码时一致 return encode(pixels, WIDTH, HEIGHT, X_COMPONENTS, Y_COMPONENTS); }
关键优化点
- 分量数匹配宽高比:通过
Y_COMPONENTS = Math.round(X_COMPONENTS / ASPECT_RATIO)让色块数量的比例和图片宽高比一致,避免拉伸变形。 - 准确灰度计算:使用加权公式计算灰度,符合人眼对RGB通道的敏感度,生成的灰度图更自然。
- 统一宽高参数:编码和解码使用相同的WIDTH和HEIGHT,避免不必要的重新计算导致的参数不一致。
内容的提问来源于stack exchange,提问作者Niccolò Caselli
相关产品推荐
相关产品推荐

