渐进式图像加载 - 模糊占位符图像(如 Unsplash)

渐进式图像加载 - 模糊占位符图像(如 Unsplash)

Unsplash 是我最喜欢的图片网站,不仅因为它有大量免费图片,还因为它的用户体验非常好。Unsplash 开始使用 BlurHash 来提供 渐进式图片加载 体验已经有一段时间了。

BlurHash added to photo objects

概念

渐进式图像加载

渐进式图像加载 可带来更好的用户体验。但什么是渐进式图像加载?

无需等待最终图像渲染完成,先使用低质量图像作为占位符 (LQIP),加载完成后再切换到原始图像。

发生了什么?

  1. 使用特定 aspect-ratio 渲染元素(例如 div),通常与原始图像相同
  2. 先渲染 低质量图像
  3. 当此元素 在视口中时,触发加载原始图像
  4. 原始图像加载完成后,在低质量图像上渲染原始图像,然后在背景上 隐藏/删除低质量图像

以下是一个例子:

占位图 vs 原始图

⬅️ 这个 8×6 像素的图像可以放大多次(例如,在我的屏幕上为 865×649 像素),而不会增加明显的噪音。

Unsplash 是怎么做的

  1. 使用 XHR 获取列表数据
  2. 从列表项的 blur_hash 字段解码 BlurHash
  3. 从使用解码的 BlurHash 数据绘制的画布生成 8 x 8 像素 image/bmp 图像,并将其渲染为图像占位符
  4. 在加载时渲染原始图像

为什么用 BMP 呢?

请查看 图片大小对比.

此外,渲染小尺寸图像比绘制画布消耗更少的 CPU 和内存。

如何生成占位图?

Photoshop 是处理滤镜效果(例如高斯模糊)的绝佳工具,但对于大多数用户来说太复杂了。

Photoshop

因此我创建了一个 Web 应用程序 (Image Blurrer) 来生成模糊的占位符图像。支持 4 种类型的输出图像:

  1. StackBlur
  2. Gaussian Blur
  3. BlurHash
  4. CSS Gradient

对比

图像质量

使用我的 Image Blurrer,在使用 StackBlur 生成模糊图像时,可以自定义模糊半径。在我的个人使用和测试中,StackBlur 是我的最爱,因为它的模糊半径灵活。

画布大小 模糊半径
32 px 2 px
StackBlur
Gaussian Blur
BlurHash
CSS Gradient

BlurHash 在大多数情况下是一个不错的选择(可以从 Unsplash 的经验中证明),但是在某些情况下它会将原始图像的暗区渲染得太暗。

例如:

原始图片 BlurHash
https://r2-assets.thelynan.com/uPic/P1010249.jpg UcF~mn?b00D$~q-:IUM{?c%3M{RjWBWBt7xu

图片尺寸对比

测试图片: https://r2-assets.thelynan.com/uPic/progress-image-loading-test-img.jpg

我在测试结果中突出显示了最小尺寸。在我的测试中,当画布宽度低于 10px 时,image/bmp 最小,然后在 12px - 22px 之间,image/png 占据主导地位,之后 image/jpeg 最小。

width(px) jpeg png bmp
4 816 B 132 B 90 B
6 828 B 168 B 135 B
8 825 B 222 B 198 B
10 846 B 279 B 279 B
12 867 B 366 B 378 B
14 885 B 432 B 495 B
16 882 B 546 B 630 B
18 936 B 618 B 783 B
20 954 B 768 B 954 B
22 942 B 855 B 1.1 KB
24 1.0 KB 1.0 KB 1.3 KB
26 1.0 KB 1.1 KB 1.5 KB
28 1.1 KB 1.3 KB 1.8 KB
30 1.1 KB 1.4 KB 2.0 KB
32 1.1 KB 1.6 KB 2.3 KB

实际上,大多数浏览器不支持通过 canvas.toDataURL 直接生成 image/bmp,如果指定的类型不受支持,则将使用 image/png 格式。

解决方案:

  1. canvs-to-bmp
  2. jimp 我的选择,因为我已经用它来生成 CSS 渐变,而且在我的实践中,jimp 生成尺寸较小的 bmp 图像文件。
jimp getBase64Async
1
2
3
4
const img = await Jimp.read("./path/to/image.jpg");
img.getBase64Async("image/bmp").then((res) => {
resolve(res);
});

感谢

  1. StackBlur
  2. Gaussian Blur
  3. BlurHash
  4. CSS Gradient
  5. jimp

渐进式图像加载 - 模糊占位符图像(如 Unsplash)

https://cn.thelynan.com/progressive-image-loading/

作者

Lynan

发布于

2024-02-15

许可协议

评论