Skip to content

使用阿里云OSS图片裁剪实现Krpano全景图多级加载

Published: at 18:56

背景

酷家乐全景图启动后会加载全景图的六面图的缩略图,同时开始加载 6 个面的完整图片,每一面加载完后去除对应面的预览图,这在全景图分辨率较高时会使得整体加载速度显著变慢,长时间处于显示预览图状态。 同时因为图片加载速度不一,加载过程中已加载的面和未加载的面交界很明显。随着图片分辨率的提升,这些问题将越来越明显。

明显的分界线

之前线上的做法是加载 WebP 格式(默认质量)的图片,但存在显著的画质损失,需要调研如何更快的加载高质量全景图。

经过调研发现,使用 krpano 的 Multires 功能可以做到将全景图的图片进行分块懒加载。

Multires 概述

从 krpano 1.17 开始,加入了 HTML5 Multiresolution 功能(简称 Multires),用于加载超高分辨率的全景图。

和一般网页图片的懒加载类似,Multires 通过自动分层和分块来推迟不可见范围内的内容的加载,基本规则如下:

其加载顺序大致为 L1落在可见范围内的tile -> L2落在可见范围内的tile -> L3落在可见范围内的tile -> ... -> 部分不可见的 Tile。具体顺序与 FOVaspreview 等设置有一定关系。

Multires 基于 HTML5 实现,其兼容性和 HTML5 基本保持一致,不支持 IE8、9。 兼容性参考

XML 配置

想要开启 Multires 需要在 XML 中进行对应的配置:

<image
    tilesize="512"              // 每个 tile 的大小
    baseindex="0"               // 下标从0开始(默认会从1开始)
 >
    <level tiledimagewidth="512" tiledimageheight="512" aspreview="true">
        <cube url="./l1/2000x2000_%s.jpg_%h_%v" />
    </level>
    <level tiledimagewidth="1024" tiledimageheight="1024">
        <cube url="./l2/2000x2000_%s.jpg_%h_%v" />
    </level>
    <level tiledimagewidth="2000" tiledimageheight="2000">
        <cube url="./l3/2000x2000_%s.jpg_%h_%v" />
    </level>
  ...
</image>

全景图加载过程中会将 url 内的占位符进行替换:

最新版本的 Krpano(1.20.9)还支持更简单的写法,不需要写分为多个 level:

<image>
    <cube url="pano_%s_%l_%v_%h.jpg"
        multires="TILESIZE,LEVELSIZE1,LEVELSIZE2,..."
        />
</image>

为什么 tilesize 取 512px?

  1. 取 2 的指数的 tilesize 可以自动触发 mipmapping,mipmapping 会在渲染时带来视觉和性能的提升(可能耗费更多的内存),但是在 Chrome 57,58 中对 mipmap 的处理存在 bug,需要关闭
  2. 过小的尺寸会导致出现大量的图片请求,过大的尺寸又会导致单个 tile 加载缓慢。该大小经过测试相对平衡且在视觉显示上较合理。

图片分级策略

目前设定的分级最高三级,如果单面图片尺寸小于 1024x1024,则跳过 L2 的加载。

L2 的设定需要多次测试确定,不一定是这个值。

使用阿里云 OSS 图片 API 进行切割

Multires 需要将图片进行切割分块,这个步骤如果由后端服务进行则会有较大的性能和传输存储压力,不过还好阿里云 OSS 提供了切割 API,可以便捷的进行图片的分块。

使用阿里云图片处理 API 提供的索引切割功能实现。 通过管道操作,将图片沿 x 轴每 512 像素裁剪,然后将裁剪的图沿 y 轴每 512 像素裁剪。从而将原图按下图类似的形式划分,完整的每一小块尺寸为 512*512。

sliced

可以用这样的图片操作取出划分后的索引(0,0)位置的裁剪图(索引从 0 开始):

https://oss.domain.com/some_pic.jpg_f?x-oss-process=image/resize,w_512|image/indexcrop,x_512,i_0|image/indexcrop,y_512,i_0

这样就得到了用在全景图 XML 中的 url:

https://oss.domain.com/some_pic.jpg_%s?x-oss-process=image/resize%2Cw_512|image/indexcrop%2Cx_512%2Ci_%h|image/indexcrop%2Cy_512%2Ci_%v

由于阿里云裁剪算法的问题,操作后的图片质量会有略有下降。如果对画质有较高要求,需要后端预处理裁剪出图组成最后一层。

对比测试

为了使差异更加明显,在对比过程主要在限速情况下进行,同时附上不限速的情况。

主要进行以下几个版本之间的对比:

限制条件:

主要关注指标:

对比

PANO-1

指标originwebpwebp 100Qmultires
首屏加载图片大小7.7M740k3.7M1.8M
加载时间46.28s7.76s30.74s18.66s
加载时间(无限制)14.43s2.18s6.12s3.80s

PANO-2

指标originwebpmultires
首屏加载图片大小7.1M543k1.6M
加载时间58.87s6.23s16.82s
加载时间(无限制)11.1s1.86s3.48s

PANO-3

指标originwebpmultires
首屏加载图片大小8.6M875k2M
加载时间1.2min8.76s20.39s
加载时间(无限制)13.33s2.41s4.22s

总结