发现一个简单低成本的全平台图片“高斯模糊”方案:BlurHash

前段时间在看 ActivityPub 文档时发现它们的客户端在加载图片时使用了一种叫做 BlurHash 的技术来显示图片加载出来之前的 Placeholder,效果非常好,而且成本极低,如果集成到 App 中可以很大程度上提高多图页面的用户体验。

这种技术可以让你图片加载出来之前显示一个填充图,这个图看起来有点像原图的高斯模糊,并且显示这个“高斯模糊”时并不需要提前把图片加载出来,计算成本也很低,完全可以当作图片加载完成前的 Placeholder 使用,而不必使用纯色块来填充,类似于下图这样:

右边就是 BlurHash 生成的图片,看起来效果还是可以的,下面就说要如何实现这种技术。

BlurHash 的使用

上面图中的中间图片有一个称为 BlurHash 的字符串,这个字符串就是通过算法计算出来的左边的原图的颜色分布信息,计算结果是一个不算长的字符串,然后客户端按照算法输入 BlurHash String,即可生成右边的那种看起来像高斯模糊一样的图片。

BlurHash 本质上就是一系列算法,因此适用所有的前端平台,包括 Web、Android、iOS 等等,接入的成本也很低。

使用起来是非常简单的,因为算法都很简单,不过我们需要后端的支持,因为后端接口在返回图片 url 给客户端时需要同时把这个图片的 BlurHash String 也返回过来,客户端根据 BlurHash 生成图片当作 Placeholder,再去加载图片,提供用户体验。

项目地址如下:

https://github.com/woltapp/blurhash

因为算法确实比较简单,他们甚至没有提供 SDK,只是提供了每一种语言的实现代码,大家直接把这个代码复制到项目中即可,Kotlin 代码就一个文件,提供 BlurHash ,返回 Bitmap,就这么简单。

不过 Compose 实际使用时需要自己写一点胶水代码,也可以直接用我写好的。

fun Modifier.blurhash(blurHash: String): Modifier = composed {
    var size: Size? by remember {
        mutableStateOf(null)
    }
    var bitmap: Bitmap? by remember {
        mutableStateOf(null)
    }
    val coroutineScope = rememberCoroutineScope()
    if (size != null) {
        DisposableEffect(blurHash) {
            if (bitmap == null && size != null) {
                coroutineScope.launch {
                    bitmap = withContext(Dispatchers.IO) {
                        BlurHashDecoder.decode(
                            blurHash = blurHash,
                            width = (size!!.width * 0.5F).roundToInt(),
                            height = (size!!.height * 0.5F).roundToInt(),
                        )
                    }
                }
            }
            onDispose {
                bitmap?.recycle()
                bitmap = null
            }
        }
    }
    onSizeChanged {
        size = it.toSize()
    }.drawBehind {
        if (bitmap != null && size != null) {
            drawImage(
                image = bitmap!!.asImageBitmap(),
                dstSize = IntSize(size!!.width.roundToInt(), size!!.height.roundToInt()),
            )
        }
    }
}

其他平台,iOS、Web 这些也按照类似的方式直接集成即可,后端的 SDK 也是有的,直接集成就行了。


2 条回复

  1. Jdeal 的头像

    感谢博主分享 🎉 高斯模糊的效果还是很NICE的~

    1. kezhang404@gmail.com 的头像

      效果确实可以的,我自己的项目也在用。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注